org.bidib.wizard.client.spring.SettingsLocationEnvironmentPostProcessor Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of bidibwizard-client Show documentation
Show all versions of bidibwizard-client Show documentation
jBiDiB BiDiB Wizard Client Application POM
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);
}
}
}