Diagnostic.java

package pro.verron.officestamper;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import picocli.CommandLine.Command;

import java.io.InputStream;
import java.time.LocalDate;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.prefs.BackingStoreException;
import java.util.prefs.Preferences;

import static java.util.stream.Collectors.toMap;

/// Diagnostic class for collecting system information.
@Command(name = "diagnostic")
public final class Diagnostic implements Runnable {

    private static final Logger logger = LoggerFactory.getLogger(Diagnostic.class);
    private final LocalDate date;
    private final String user;
    private final Map<String, String> userPreferences;
    private final Map<String, String> jvmProperties;
    private final Map<String, String> environmentVariables;

    private Diagnostic() {
        this(LocalDate.now(), System.getenv("USERNAME"), extractUserPreferences(), extractJvmProperties(), extractEnvironmentVariables());
    }

    private Diagnostic(LocalDate date, String user, Map<String, String> userPreferences, Map<String, String> jvmProperties, Map<String, String> environmentVariables) {
        this.date = date;
        this.user = user;
        this.userPreferences = userPreferences;
        this.jvmProperties = jvmProperties;
        this.environmentVariables = environmentVariables;
    }

    private static Map<String, String> extractUserPreferences() {
        var preferenceRoot = Preferences.userRoot();
        var preferenceKeys = extractPreferenceKeys(preferenceRoot);
        var entries = preferenceKeys.stream().collect(toMap(key -> key, k -> preferenceRoot.get(k, "<null>")));
        return Map.copyOf(entries);
    }

    private static Map<String, String> extractJvmProperties() {
        var properties = System.getProperties();
        var propertyNames = properties.stringPropertyNames();
        var entries = propertyNames.stream().collect(toMap(k -> k, properties::getProperty));
        return Map.copyOf(entries);
    }

    private static Map<String, String> extractEnvironmentVariables() {
        var env = System.getenv();
        return Map.copyOf(env);
    }

    private static List<String> extractPreferenceKeys(Preferences preferenceRoot) {
        try {
            return Arrays.asList(preferenceRoot.keys());
        } catch (BackingStoreException e) {
            logger.atWarn().setCause(e).log("Failed to list the preference keys");
            return List.of("failed-to-list-preference-keys");
        }
    }

    static Object context() {
        return context(new Diagnostic());
    }

    private static Object context(Diagnostic diagnosticMaker) {
        logger.info("Create a context with system environment variables, jvm properties, and user preferences");
        var map = new TreeMap<String, Object>();
        map.put("reportDate", diagnosticMaker.date());
        map.put("reportUser", diagnosticMaker.user());
        map.put("environment", diagnosticMaker.environmentVariables().entrySet());
        map.put("properties", diagnosticMaker.jvmProperties().entrySet());
        map.put("preferences", diagnosticMaker.userPreferences().entrySet());
        return map;
    }

    static Object context(LocalDate date, String user, Map<String, String> userPreferences, Map<String, String> jvmProperties, Map<String, String> environmentVariables) {
        return context(new Diagnostic(date, user, userPreferences, jvmProperties, environmentVariables));
    }

    static InputStream template() {
        logger.info("Load the internally packaged 'Diagnostic.docx' template resource");
        return Utils.streamResource("Diagnostic.docx");
    }

    /// Returns the diagnostic date.
    ///
    /// @return the date
    public LocalDate date() {
        return date;
    }

    /// Returns the diagnostic user.
    ///
    /// @return the user
    public String user() {
        return user;
    }

    private Map<String, String> environmentVariables() {
        return environmentVariables;
    }

    private Map<String, String> jvmProperties() {
        return jvmProperties;
    }

    private Map<String, String> userPreferences() {
        return userPreferences;
    }

    @Override
    public void run() {

    }
}