All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.bidib.wizard.client.spring.SettingsLocationEnvironmentPostProcessor Maven / Gradle / Ivy

There is a newer version: 2.0.29
Show newest version
package org.bidib.wizard.client.spring;

import java.awt.BorderLayout;
import java.awt.Frame;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Collection;
import java.util.Properties;
import java.util.function.Consumer;

import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.filefilter.WildcardFileFilter;
import org.apache.commons.logging.Log;
import org.bidib.wizard.api.locale.Resources;
import org.bidib.wizard.api.utils.WizardUtils;
import org.bidib.wizard.common.utils.ImageUtils;
import org.springframework.boot.ConfigurableBootstrapContext;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.context.config.ConfigDataEnvironmentUpdateListener;
import org.springframework.boot.env.EnvironmentPostProcessor;
import org.springframework.boot.logging.DeferredLogFactory;
import org.springframework.core.Ordered;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.io.ResourceLoader;

import com.jgoodies.forms.builder.ButtonBarBuilder;
import com.jgoodies.forms.builder.FormBuilder;
import com.jgoodies.forms.factories.Paddings;
import com.jidesoft.swing.FolderChooser;

public class SettingsLocationEnvironmentPostProcessor implements EnvironmentPostProcessor, Ordered {

    public static final int ORDER = Ordered.HIGHEST_PRECEDENCE + 7;

    private final Log logger;

    private final ConfigurableBootstrapContext bootstrapContext;

    private final ConfigDataEnvironmentUpdateListener environmentUpdateListener;

    public SettingsLocationEnvironmentPostProcessor(DeferredLogFactory logFactory,
        ConfigurableBootstrapContext bootstrapContext) {
        this(logFactory, bootstrapContext, null);
    }

    public SettingsLocationEnvironmentPostProcessor(DeferredLogFactory logFactory,
        ConfigurableBootstrapContext bootstrapContext, ConfigDataEnvironmentUpdateListener environmentUpdateListener) {
        this.logger = logFactory.getLog(getClass());
        this.bootstrapContext = bootstrapContext;
        this.environmentUpdateListener = environmentUpdateListener;
    }

    @Override
    public int getOrder() {
        return ORDER;
    }

    @Override
    public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
        postProcessEnvironment(environment, application.getResourceLoader(), application.getAdditionalProfiles());
    }

    private static final String WIZARD_SETTINGSFILE_LOCATION_REFERENCE = "wizard2.properties";

    private static final String WIZARD_SETTINGSFILE_LOCATION_PROPERTY = "wizard.settings.file-location";

    private static final String WIZARD_CONFIGURATION_FILE_LOCATION_PROPERTY = "wizard.configuration.file-location";

    private String wizardConfigurationFileLocationReference;

    void postProcessEnvironment(
        ConfigurableEnvironment environment, ResourceLoader resourceLoader, Collection additionalProfiles) {

        try {
            // get the value from the environment or the default value
            wizardConfigurationFileLocationReference =
                environment.getProperty(WIZARD_SETTINGSFILE_LOCATION_PROPERTY, "${user.home}/.bidib");
            // resolve placeholders
            wizardConfigurationFileLocationReference =
                environment.resolvePlaceholders(wizardConfigurationFileLocationReference);

            this.logger
                .info("Location of settings file location reference: " + wizardConfigurationFileLocationReference);

            // check if the reference file to the settings location exists
            final File file =
                new File(wizardConfigurationFileLocationReference, WIZARD_SETTINGSFILE_LOCATION_REFERENCE);
            if (!file.exists()) {
                this.logger.info("The settings file location reference was not found.");

                selectLocation(environment, file);
            }
            else {
                // get the location of the wizard configuration files
                this.logger.info("The settings file location reference was found.");

                try (InputStream is = new FileInputStream(file)) {
                    //
                    Properties props = new Properties();

                    props.load(is);

                    wizardConfigurationFileLocationReference = props.getProperty(WIZARD_SETTINGSFILE_LOCATION_PROPERTY);

                    SettingsLocationEnvironmentPostProcessor.this.logger
                        .info("Read wizardSettingsFileLocationReference from location: " + file.getPath()
                            + ", wizardConfigurationFileLocationReference: "
                            + wizardConfigurationFileLocationReference);

                    final File location = new File(wizardConfigurationFileLocationReference);
                    if (!location.exists()) {
                        try {
                            FileUtils.forceMkdir(location);
                        }
                        catch (Exception ex) {
                            SettingsLocationEnvironmentPostProcessor.this.logger
                                .warn("Create directory for wizardSettingsFiles failed.", ex);
                        }
                    }
                }
                catch (Exception ex) {
                    SettingsLocationEnvironmentPostProcessor.this.logger
                        .warn("Failed to read the wizardSettingsFileLocationReference from location: " + file.getPath(),
                            ex);

                    throw new RuntimeException(
                        "Failed to read the wizardSettingsFileLocationReference from location: " + file.getPath());
                }
            }

            environment
                .getSystemProperties()
                .put(WIZARD_CONFIGURATION_FILE_LOCATION_PROPERTY, wizardConfigurationFileLocationReference);

        }
        catch (Exception ex) {
            this.logger.warn("Fetch the location of settings file location reference failed.", ex);
        }
    }

    private void selectLocation(final ConfigurableEnvironment environment, final File file) {
        String userHome = environment.resolvePlaceholders("${user.home}");

        logger.info("Select the location for wizard settings files.");

        try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        }
        catch (ClassNotFoundException | InstantiationException | IllegalAccessException
            | UnsupportedLookAndFeelException ex) {
            logger.warn("Set look and feel failed", ex);
        }

        boolean foundAndUseOldLocation = false;
        boolean copyWizardConfigFromOldLocation = false;
        // check if the wizard.yml exists in the 'old default directory'
        try {
            final File oldWizardConfigurationFile = new File(userHome, ".bidib/wizard.yml");
            if (oldWizardConfigurationFile.exists()) {
                this.logger
                    .info("Found the wizard.yml in the old default directory: " + oldWizardConfigurationFile.getPath());

                // ask the user if he wants to keep this location
                int result =
                    JOptionPane
                        .showConfirmDialog(JOptionPane.getFrameForComponent(null),
                            Resources
                                .getString(SettingsLocationEnvironmentPostProcessor.class, "keep-old-location.message",
                                    oldWizardConfigurationFile.getParentFile().getPath()),
                            Resources
                                .getString(SettingsLocationEnvironmentPostProcessor.class, "keep-old-location.title"),
                            JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
                if (result == JOptionPane.YES_OPTION) {
                    this.logger.info("User accepted to use old configuration location.");

                    wizardConfigurationFileLocationReference = oldWizardConfigurationFile.getParentFile().getPath();
                    this.logger
                        .info("Found and use the configuration from the old location: "
                            + wizardConfigurationFileLocationReference);

                    foundAndUseOldLocation = true;
                }
                else {
                    this.logger.info("User declined to use old configuration location.");
                    copyWizardConfigFromOldLocation = true;
                }
            }
        }
        catch (Exception ex) {
            this.logger.warn("Check if the wizard.yml exists in the 'old default directory' failed.", ex);
        }

        if (!foundAndUseOldLocation) {
            File defaultDirectory = new File(userHome, WizardUtils.getDefaultConfigSubDir());
            // String selectedFile = defaultDirectory.getName();

            SettingsLocationEnvironmentPostProcessor.this.logger
                .info("Prepared the default location directory: " + defaultDirectory.getPath());

            SettingsLocationEnvironmentPostProcessor.this.logger.info("Prepare and show the settings location dialog.");

            // dialog to show the default location and let the user change this location
            final SettingsLocationDialog chooser =
                new SettingsLocationDialog(null, logger, defaultDirectory, (location) -> {
                    wizardConfigurationFileLocationReference = location.getPath();

                    if (!location.exists()) {
                        SettingsLocationEnvironmentPostProcessor.this.logger
                            .info("The selected location does not exist and will be created: "
                                + wizardConfigurationFileLocationReference);
                        try {
                            FileUtils.forceMkdir(location);
                        }
                        catch (Exception ex) {
                            SettingsLocationEnvironmentPostProcessor.this.logger
                                .warn("Create directory for wizardSettingsFiles failed.", ex);
                        }
                    }
                    else {
                        SettingsLocationEnvironmentPostProcessor.this.logger
                            .info("The selected location does exist: " + wizardConfigurationFileLocationReference);
                    }
                });
            chooser.setVisible(null);

            SettingsLocationEnvironmentPostProcessor.this.logger
                .info("Use the wizardSettingsFileLocationReference: " + wizardConfigurationFileLocationReference);
        }

        if (!file.getParentFile().exists()) {
            try {
                FileUtils.forceMkdir(file.getParentFile());
            }
            catch (Exception ex) {
                SettingsLocationEnvironmentPostProcessor.this.logger
                    .warn("Create directory for wizardSettingsFileLocationReference failed.", ex);
            }
        }

        try (OutputStream os = new FileOutputStream(file)) {
            //
            Properties props = new Properties();
            props.put(WIZARD_SETTINGSFILE_LOCATION_PROPERTY, wizardConfigurationFileLocationReference);

            props.store(os, "Added by Wizard 2");

            SettingsLocationEnvironmentPostProcessor.this.logger
                .info("Wrote wizardSettingsFileLocationReference to location: " + file.getPath());
        }
        catch (Exception ex) {
            SettingsLocationEnvironmentPostProcessor.this.logger
                .warn("Write the wizardSettingsFileLocationReference failed: " + file, ex);

            throw new RuntimeException("Write the wizardSettingsFileLocationReference failed: " + file);
        }

        // check if we must copy the existing configuration files to the new location
        if (copyWizardConfigFromOldLocation) {
            // check if the configuration files exist in the new location already
            try {
                final File oldDirectory = new File(userHome, ".bidib");
                final File newLocationConfigurationFile =
                    new File(wizardConfigurationFileLocationReference, "wizard.yml");
                if (!newLocationConfigurationFile.exists()) {
                    SettingsLocationEnvironmentPostProcessor.this.logger
                        .info("copy the existing wizard configuration files to the new location.");

                    // ask the user if he wants to keep this location
                    int result =
                        JOptionPane
                            .showConfirmDialog(JOptionPane.getFrameForComponent(null),
                                Resources
                                    .getString(SettingsLocationEnvironmentPostProcessor.class,
                                        "copy-config-from-old-location.message", oldDirectory.getPath()),
                                Resources
                                    .getString(SettingsLocationEnvironmentPostProcessor.class,
                                        "copy-config-from-old-location.title"),
                                JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
                    if (result == JOptionPane.YES_OPTION) {
                        SettingsLocationEnvironmentPostProcessor.this.logger
                            .info("User accepted to copy existing configuration files.");

                        final File oldWizardConfigurationFile = new File(oldDirectory, "wizard.yml");
                        copyFile(oldWizardConfigurationFile, newLocationConfigurationFile);

                        final FileFilter fileFilter =
                            WildcardFileFilter.builder().setWildcards("wizardmodule_*.yml").get();
                        File[] files = oldDirectory.listFiles(fileFilter);
                        if (files != null && files.length > 0) {
                            for (File sourceFile : files) {
                                File targetFile =
                                    new File(wizardConfigurationFileLocationReference, sourceFile.getName());
                                copyFile(sourceFile, targetFile);
                            }
                        }
                        else {
                            SettingsLocationEnvironmentPostProcessor.this.logger
                                .info("No wizard module configuration files found.");
                        }
                    }
                    else {
                        SettingsLocationEnvironmentPostProcessor.this.logger
                            .info("User declined to copy existing configuration files.");
                    }
                }
                else {
                    SettingsLocationEnvironmentPostProcessor.this.logger
                        .info(
                            "The wizard configuration file exists in the new location already. Skip copy existing files.");
                }
            }
            catch (Exception ex) {
                SettingsLocationEnvironmentPostProcessor.this.logger
                    .warn("Write the wizardSettingsFileLocationReference failed: " + file, ex);
            }
        }
    }

    private void copyFile(File source, File target) {
        try (InputStream sourceStream = new FileInputStream(source);
            OutputStream targetStream = new FileOutputStream(target)) {
            IOUtils.copy(sourceStream, targetStream);
        }
        catch (Exception ex) {
            SettingsLocationEnvironmentPostProcessor.this.logger.warn("Copy configuration file failed: " + source, ex);
        }
    }

    private static class SettingsLocationDialog extends JDialog {

        private static final long serialVersionUID = 1L;

        private static final String ENCODED_DIALOG_COLUMN_SPECS = "pref, 3dlu, max(200dlu;pref), 3dlu, pref";

        private static final String ENCODED_DIALOG_ROW_SPECS = "pref, 3dlu, pref, 3dlu, pref";

        private final Log logger;

        private final Consumer locationConsumer;

        public SettingsLocationDialog(Frame frame, final Log logger, final File defaultDirectory,
            final Consumer locationConsumer) {
            super(frame, Resources.getString(SettingsLocationEnvironmentPostProcessor.class, "title"), true);
            this.logger = logger;
            this.locationConsumer = locationConsumer;

            // set the wizard icon as default frame icon
            setIconImage(
                ImageUtils.createImageIcon(SettingsLocationDialog.class, "/icons/wizard-logo2-48x48.png").getImage());

            getContentPane().setLayout(new BorderLayout());

            FormBuilder builder =
                FormBuilder
                    .create().columns(ENCODED_DIALOG_COLUMN_SPECS).rows(ENCODED_DIALOG_ROW_SPECS).panel(new JPanel());
            builder.border(Paddings.DIALOG);

            int row = 1;

            JLabel configurationFilesLocationLabel =
                new JLabel(Resources
                    .getString(SettingsLocationEnvironmentPostProcessor.class, "configuration-files-location"));
            builder.add(configurationFilesLocationLabel).xy(1, row);

            row += 2;

            final JTextField textConfigurationFilesLocation = new JTextField();
            textConfigurationFilesLocation.setText(defaultDirectory.getPath());
            builder.add(textConfigurationFilesLocation).xyw(1, row, 3);

            JButton chooserButton =
                new JButton(Resources.getString(SettingsLocationEnvironmentPostProcessor.class, "choose"));
            chooserButton.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    logger.info("Show the FolderChooser.");

                    try {

                        final FolderChooser chooser = new FolderChooser();
                        chooser.setSelectedFolder(defaultDirectory.getParentFile());
                        chooser.setRecentListVisible(false);
                        chooser
                            .setDialogTitle(Resources
                                .getString(SettingsLocationEnvironmentPostProcessor.class,
                                    "choose-configuration-location"));
                        int returnVal = chooser.showOpenDialog(SettingsLocationDialog.this);

                        logger.info("The returnVal: " + returnVal);
                        if (returnVal == FolderChooser.APPROVE_OPTION) {
                            File settingsLocation = chooser.getSelectedFile();
                            SettingsLocationDialog.this.logger
                                .info("Selected settingsLocation: " + settingsLocation.getPath());
                            textConfigurationFilesLocation.setText(settingsLocation.getPath());
                        }
                    }
                    catch (Exception ex) {
                        logger.warn("Show folder chooser failed.", ex);
                    }
                    catch (Error err) {
                        logger.warn("Show folder chooser failed.", err);
                    }

                }
            });
            builder.add(chooserButton).xy(5, row);

            row += 2;

            // buttons
            JButton continueButton =
                new JButton(Resources.getString(SettingsLocationEnvironmentPostProcessor.class, "continue"));

            continueButton.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {

                    final File settingsLocation = new File(textConfigurationFilesLocation.getText());
                    setVisible(false);
                    fireContinue(settingsLocation);
                }
            });

            JButton cancel = new JButton(Resources.getString(SettingsLocationEnvironmentPostProcessor.class, "cancel"));

            cancel.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    setVisible(false);
                    fireCancel();
                }
            });

            JPanel buttons = new ButtonBarBuilder().addGlue().addButton(continueButton, cancel).build();

            builder.add(buttons).xyw(1, row, 5);

            getContentPane().add(builder.build());

            pack();
        }

        public void setVisible(Frame frame) {

            setLocationRelativeTo(frame);
            setMinimumSize(getSize());
            setVisible(true);
        }

        private void fireContinue(final File settingsLocation) {
            SettingsLocationDialog.this.logger.info("Continue operation.");
            locationConsumer.accept(settingsLocation);
        }

        private void fireCancel() {
            SettingsLocationDialog.this.logger.warn("Cancel operation and exit application.");

            System.exit(1);
        }

    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy