pl.baczkowicz.spy.ui.configuration.BaseConfigurationManager.java Source code

Java tutorial

Introduction

Here is the source code for pl.baczkowicz.spy.ui.configuration.BaseConfigurationManager.java

Source

/***********************************************************************************
 * 
 * Copyright (c) 2016 Kamil Baczkowicz
 * 
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * and Eclipse Distribution License v1.0 which accompany this distribution.
 *
 * The Eclipse Public License is available at
 *    http://www.eclipse.org/legal/epl-v10.html
 *    
 * The Eclipse Distribution License is available at
 *   http://www.eclipse.org/org/documents/edl-v10.php.
 *
 * Contributors:
 * 
 *    Kamil Baczkowicz - initial API and implementation and/or initial documentation
 *    
 */
package pl.baczkowicz.spy.ui.configuration;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import pl.baczkowicz.spy.common.generated.ConnectionDetails;
import pl.baczkowicz.spy.common.generated.ConnectionGroup;
import pl.baczkowicz.spy.common.generated.ConnectionGroupReference;
import pl.baczkowicz.spy.common.generated.ConnectionReference;
import pl.baczkowicz.spy.configuration.BaseConfigurationUtils;
import pl.baczkowicz.spy.configuration.PropertyFileLoader;
import pl.baczkowicz.spy.exceptions.ConfigurationException;
import pl.baczkowicz.spy.exceptions.XMLException;
import pl.baczkowicz.spy.ui.panes.SpyPerspective;
import pl.baczkowicz.spy.ui.properties.ModifiableConnection;
import pl.baczkowicz.spy.ui.utils.DialogFactory;
import pl.baczkowicz.spy.utils.ThreadingUtils;
import pl.baczkowicz.spy.utils.TimeUtils;
import pl.baczkowicz.spy.xml.XMLParser;

public abstract class BaseConfigurationManager implements IConfigurationManager {
    public static final String SPY_COMMON_SCHEMA = "/spy-common.xsd";

    private final static Logger logger = LoggerFactory.getLogger(BaseConfigurationManager.class);

    private List<ConfiguredConnectionGroupDetails> connectionGroups = new ArrayList<>();

    private ConfiguredConnectionGroupDetails rootGroup;

    private File loadedConfigurationFile;

    private Exception lastException;

    /** The application name. */
    public static String APPLICATION_NAME = "mqtt-spy";

    private PropertyFileLoader defaultPropertyFile;

    private PropertyFileLoader uiPropertyFile;

    protected void loadDefaultPropertyFile() throws ConfigurationException {
        // Load the default property file from classpath
        this.defaultPropertyFile = new PropertyFileLoader();
        this.defaultPropertyFile.readFromClassPath(getDefaultPropertyFileLocation());
    }

    public Object loadConfiguration(final XMLParser parser, final File file) {
        Object configuration;

        try {
            clear();
            configuration = parser.loadFromFile(file);

            setLoadedConfigurationFile(file);
            return configuration;
        } catch (XMLException e) {
            setLastException(e);
            DialogFactory.createErrorDialog("Invalid configuration file",
                    "Cannot process the given configuration file. See the log file for more details.");
            logger.error("Cannot process the configuration file at " + file.getAbsolutePath(), e);
        } catch (FileNotFoundException e) {
            setLastException(e);
            DialogFactory.createErrorDialog("Invalid configuration file",
                    "Cannot read the given configuration file. See the log file for more details.");
            logger.error("Cannot read the configuration file from " + file.getAbsolutePath(), e);
        }

        return null;
    }

    public void createConnectionGroups(final List<ConnectionGroup> configuredGroups,
            final List<ModifiableConnection> configuredConnections) {
        final List<ConnectionGroup> groupsWithoutParent = new ArrayList<>(configuredGroups);

        // Clear up resources - in case something was loaded before
        getConnectionGrops().clear();
        setRootGroup(null);

        // This is expected from v0.3.0
        for (final ConnectionGroup group : configuredGroups) {
            final ConfiguredConnectionGroupDetails details = new ConfiguredConnectionGroupDetails(group, false);

            for (ConnectionGroupReference subgroup : group.getSubgroups()) {
                groupsWithoutParent.remove(subgroup.getReference());
            }

            getConnectionGrops().add(details);
        }

        // Create the root if no groups present (pre v0.3.0)
        if (getConnectionGrops().isEmpty() || groupsWithoutParent.isEmpty()) {
            logger.debug("Creating root group called 'All connections'");
            setRootGroup(
                    new ConfiguredConnectionGroupDetails(new ConnectionGroup(BaseConfigurationUtils.DEFAULT_GROUP,
                            "All connections", new ArrayList<>(), new ArrayList<>()), false));

            getConnectionGrops().add(getRootGroup());

            // Assign all connections to the new root
            for (final ModifiableConnection connection : configuredConnections) {
                connection.setGroup(new ConnectionGroupReference(getRootGroup()));
                getRootGroup().getConnections().add(new ConnectionReference(connection));
            }

            getRootGroup().apply();
        } else {
            // Find the root group
            final String rootId = groupsWithoutParent.get(0).getID();
            for (final ConfiguredConnectionGroupDetails group : getConnectionGrops()) {
                if (group.getID().equals(rootId)) {
                    setRootGroup(group);
                    break;
                }
            }
            // At this point, new groups link to old connection and group objects, and old connection objects to old groups

            // Re-wire all connections
            updateTree(getRootGroup());
        }
    }

    private void updateTree(final ConfiguredConnectionGroupDetails parentGroup) {
        final List<ConnectionGroupReference> subgroups = new ArrayList<>(parentGroup.getSubgroups());
        parentGroup.getSubgroups().clear();

        for (final ConnectionGroupReference reference : subgroups) {
            final ConnectionGroup group = (ConnectionGroup) reference.getReference();
            final ConfiguredConnectionGroupDetails groupDetails = findMatchingGroup(group);
            parentGroup.getSubgroups().add(new ConnectionGroupReference(groupDetails));
            groupDetails.setGroup(new ConnectionGroupReference(parentGroup));
            groupDetails.apply();

            // Recursive
            updateTree(groupDetails);
        }

        final List<ConnectionReference> connections = new ArrayList<>(parentGroup.getConnections());
        parentGroup.getConnections().clear();

        for (final ConnectionReference reference : connections) {
            final ConnectionDetails connection = (ConnectionDetails) reference.getReference();
            final ModifiableConnection connectionDetails = findMatchingConnection(connection,
                    new ArrayList<>(getConnections()));

            if (connectionDetails != null) {
                parentGroup.getConnections().add(new ConnectionReference(connectionDetails));
                connectionDetails.setGroup(new ConnectionGroupReference(parentGroup));
                connectionDetails.apply();
            } else {
                logger.warn("Match not found for connection {}", connection.getName());
            }
        }

        parentGroup.apply();
    }

    public static ModifiableConnection findMatchingConnection(final ConnectionDetails connection,
            final List<ModifiableConnection> connections) {
        for (final ModifiableConnection connectionDetails : connections) {
            if (connection.getID().equals(connectionDetails.getID())) {
                return connectionDetails;
            }
        }

        return null;
    }

    public List<ConfiguredConnectionGroupDetails> getOrderedGroups() {
        List<ModifiableConnection> orderedConnections = new ArrayList<>();
        List<ConfiguredConnectionGroupDetails> orderedGroups = new ArrayList<>();

        orderedGroups.add(getRootGroup());
        sortConnections(getRootGroup(), orderedGroups, orderedConnections);

        return orderedGroups;
    }

    public List<ModifiableConnection> getOrderedConnections() {
        List<ModifiableConnection> orderedConnections = new ArrayList<>();
        List<ConfiguredConnectionGroupDetails> orderedGroups = new ArrayList<>();

        sortConnections(getRootGroup(), orderedGroups, orderedConnections);

        return orderedConnections;
    }

    private void sortConnections(final ConfiguredConnectionGroupDetails parentGroup,
            final List<ConfiguredConnectionGroupDetails> orderedGroups,
            List<ModifiableConnection> orderedConnections) {
        for (final ConnectionGroupReference reference : parentGroup.getSubgroups()) {
            final ConfiguredConnectionGroupDetails group = (ConfiguredConnectionGroupDetails) reference
                    .getReference();
            orderedGroups.add(group);

            // Recursive
            sortConnections(group, orderedGroups, orderedConnections);
        }

        for (final ConnectionReference reference : parentGroup.getConnections()) {
            final ModifiableConnection connection = (ModifiableConnection) reference.getReference();
            orderedConnections.add(connection);
        }
    }

    public List<ModifiableConnection> getConnections(final ConfiguredConnectionGroupDetails group) {
        List<ModifiableConnection> orderedConnections = new ArrayList<>();
        for (final ConnectionReference connetionRef : group.getConnections()) {
            orderedConnections.add((ModifiableConnection) connetionRef.getReference());
        }
        return orderedConnections;
    }

    protected abstract void clear();

    protected void loadUiPropertyFile() throws ConfigurationException {
        // Load the UI property file
        if (!getUiPropertyFileObject().exists()) {
            logger.info("Creating UI property file");
            createUiPropertyFileFromClassPath();
        }
        this.uiPropertyFile = new PropertyFileLoader();
        this.uiPropertyFile.readFromFileSystem(getUiPropertyFileObject());
    }

    public static String getDefaultHomeDirectory() {
        final String filePathSeparator = System.getProperty("file.separator");
        String userHomeDirectory = System.getProperty("user.home");

        if (!userHomeDirectory.endsWith(filePathSeparator)) {
            userHomeDirectory = userHomeDirectory + filePathSeparator;
        }

        return userHomeDirectory + APPLICATION_NAME + filePathSeparator;
    }

    public static String getDefaultPropertyFileLocation() {
        return "/" + APPLICATION_NAME + ".properties";
    }

    public static String getUiPropertyFileLocation() {
        return "/" + APPLICATION_NAME + "-ui.properties";
    }

    public static String getDefaultConfigurationFileName() {
        return APPLICATION_NAME + "-configuration.xml";
    }

    public static File getDefaultConfigurationFileObject() {
        return new File(getDefaultHomeDirectory() + getDefaultConfigurationFileName());
    }

    /**
     * Gets the default property file.
     * 
     * @return the defaultPropertyFile
     */
    public PropertyFileLoader getDefaultPropertyFile() {
        return defaultPropertyFile;
    }

    /**
     * Gets the UI property file.
     * 
     * @return the uiPropertyFile
     */
    public PropertyFileLoader getUiPropertyFile() {
        return uiPropertyFile;
    }

    public static File getUiPropertyFileObject() {
        return new File(getDefaultHomeDirectory() + getUiPropertyFileLocation());
    }

    public static boolean createUiPropertyFileFromClassPath() {
        final String origin = "/samples" + getUiPropertyFileLocation();
        try {
            return copyFileFromClassPath(BaseConfigurationManager.class.getResourceAsStream(origin),
                    getUiPropertyFileObject());
        } catch (IllegalArgumentException | IOException e) {
            // TODO: show warning dialog for invalid
            logger.error("Cannot copy file from {}", origin, e);
        }

        return false;
    }

    public static File getDefaultHomeDirectoryFileObject() {
        return new File(getDefaultHomeDirectory());
    }

    public static boolean copyFileFromClassPath(final InputStream orig, final File dest) throws IOException {
        getDefaultHomeDirectoryFileObject().mkdirs();
        streamToFile(orig, dest);

        return true;
    }

    public static void streamToFile(final InputStream input, final File output) throws IOException {
        try (FileOutputStream out = new FileOutputStream(output)) {
            IOUtils.copy(input, out);
        }
    }

    public String generateConnectionGroupId() {
        ThreadingUtils.sleep(1);
        return "cg" + TimeUtils.getMonotonicTime();
    }

    public static String generateConnectionId() {
        ThreadingUtils.sleep(1);
        return "conn" + TimeUtils.getMonotonicTime();
    }

    public List<ConfiguredConnectionGroupDetails> getConnectionGrops() {
        return connectionGroups;
    }

    public ConfiguredConnectionGroupDetails getRootGroup() {
        return rootGroup;
    }

    public void setRootGroup(ConfiguredConnectionGroupDetails value) {
        this.rootGroup = value;
    }

    protected ConfiguredConnectionGroupDetails findMatchingGroup(final ConnectionGroup group) {
        for (final ConfiguredConnectionGroupDetails groupDetails : connectionGroups) {
            if (group.getID().equals(groupDetails.getID())) {
                return groupDetails;
            }
        }

        return null;
    }

    public Exception getLastException() {
        return lastException;
    }

    public void setLastException(Exception lastException) {
        this.lastException = lastException;
    }

    public File getLoadedConfigurationFile() {
        return loadedConfigurationFile;
    }

    public void setLoadedConfigurationFile(File file) {
        this.loadedConfigurationFile = file;
    }

    public boolean isConfigurationWritable() {
        if (loadedConfigurationFile != null && loadedConfigurationFile.canWrite()) {
            return true;
        }
        return false;
    }

    public boolean isConfigurationReadOnly() {
        if (loadedConfigurationFile != null && !loadedConfigurationFile.canWrite()) {
            return true;
        }

        return false;
    }

    public void updateUiProperty(final String propertyName, final String propertyValue) {
        getUiPropertyFile().setProperty(propertyName, propertyValue);
    }

    public static boolean createDefaultConfigFromFile(final File orig) {
        try {
            final File dest = BaseConfigurationManager.getDefaultConfigurationFileObject();

            dest.mkdirs();
            Files.copy(orig.toPath(), dest.toPath(), StandardCopyOption.REPLACE_EXISTING);

            return true;

        } catch (IOException e) {
            // TODO: show warning dialog for invalid
            logger.error("Cannot copy configuration file", e);
        }

        return false;
    }

    public static boolean createDefaultConfigFromClassPath(final String name) {
        final String origin = "/samples" + "/" + name + "-" + APPLICATION_NAME + "-configuration.xml";
        try {
            return BaseConfigurationManager.copyFileFromClassPath(
                    BaseConfigurationManager.class.getResourceAsStream(origin),
                    BaseConfigurationManager.getDefaultConfigurationFileObject());
        } catch (IllegalArgumentException | IOException e) {
            // TODO: show warning dialog for invalid
            logger.error("Cannot copy configuration file from {}", origin, e);
        }

        return false;
    }

    public void saveUiProperties(final double width, final double height, boolean maximized,
            final SpyPerspective selectedPerspective, final boolean resizeMessagePane) {
        updateUiProperty(UiProperties.WIDTH_PROPERTY, String.valueOf(width));
        updateUiProperty(UiProperties.HEIGHT_PROPERTY, String.valueOf(height));
        updateUiProperty(UiProperties.MAXIMIZED_PROPERTY, String.valueOf(maximized));
        updateUiProperty(UiProperties.PERSPECTIVE_PROPERTY, selectedPerspective.toString());
        updateUiProperty(UiProperties.MESSAGE_PANE_RESIZE_PROPERTY, String.valueOf(resizeMessagePane));

        // Other properties are read-only from file

        try {
            getUiPropertyFile().saveToFileSystem(APPLICATION_NAME + "-ui", getUiPropertyFileObject());
        } catch (IOException e) {
            logger.error("Cannot save UI properties", e);
        }
    }

}