Mercurial > hg > release > thermostat-1.4
changeset 1748:c4d1214d3de0
Add Thermostat Setup GUI
Add a GUI alternative to the thermostat-setup script
Reviewed-by: jerboaa, omajid
Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2015-July/014460.html
PR2581
line wrap: on
line diff
--- a/distribution/assembly/all-plugin-assembly.xml Tue Sep 01 13:21:43 2015 -0400 +++ b/distribution/assembly/all-plugin-assembly.xml Wed Sep 02 11:26:48 2015 +0200 @@ -57,6 +57,7 @@ <include>com.redhat.thermostat:thermostat-storage-profile-distribution</include> <include>com.redhat.thermostat:thermostat-thread-distribution</include> <include>com.redhat.thermostat:thermostat-validate-distribution</include> + <include>com.redhat.thermostat:thermostat-setup-distribution</include> <include>com.redhat.thermostat:thermostat-vm-classstat-distribution</include> <include>com.redhat.thermostat:thermostat-vm-cpu-distribution</include> <include>com.redhat.thermostat:thermostat-vm-gc-distribution</include>
--- a/distribution/pom.xml Tue Sep 01 13:21:43 2015 -0400 +++ b/distribution/pom.xml Wed Sep 02 11:26:48 2015 +0200 @@ -425,6 +425,12 @@ </dependency> <dependency> <groupId>com.redhat.thermostat</groupId> + <artifactId>thermostat-setup-distribution</artifactId> + <version>${project.version}</version> + <type>zip</type> + </dependency> + <dependency> + <groupId>com.redhat.thermostat</groupId> <artifactId>thermostat-host-memory-distribution</artifactId> <version>${project.version}</version> <type>zip</type>
--- a/launcher/src/main/java/com/redhat/thermostat/launcher/internal/LauncherImpl.java Tue Sep 01 13:21:43 2015 -0400 +++ b/launcher/src/main/java/com/redhat/thermostat/launcher/internal/LauncherImpl.java Wed Sep 02 11:26:48 2015 +0200 @@ -88,7 +88,6 @@ public class LauncherImpl implements Launcher { private static final String HELP_COMMAND_NAME = "help"; - private static final String SETUP_SCRIPT_NAME = "thermostat-setup"; private static final Translate<LocaleResources> t = LocaleResources.createLocalizer(); private static final Logger logger = LoggingUtils.getLogger(LauncherImpl.class); @@ -160,7 +159,12 @@ if (isThermostatConfigured()) { runCommandFromArguments(args, listeners, inShell); } else { - printSetupHelpMessage(); + if (Arrays.asList(args).contains("--skip-setup")) { + runCommandFromArguments(args, listeners, inShell); + } else { + String[] setupArgs = {"setup"}; + runCommandFromArguments(setupArgs, listeners, inShell); + } } } } catch (NoClassDefFoundError e) { @@ -185,12 +189,6 @@ } } - private void printSetupHelpMessage() { - String msg = t.localize(LocaleResources.LAUNCHER_FIRST_LAUNCH_MSG, - SETUP_SCRIPT_NAME).getContents(); - printAndLogLine(msg); - } - // Log messages might go to a file. Be sure to print to stdout as well. private void printAndLogLine(String msg) { System.out.println(msg); @@ -361,7 +359,7 @@ private CommandContext setupCommandContext(Command cmd, Arguments args) throws CommandException { CommandContext ctx = cmdCtxFactory.createContext(args); - + if (cmd.isStorageRequired()) { ServiceReference dbServiceReference = context.getServiceReference(DbService.class);
--- a/pom.xml Tue Sep 01 13:21:43 2015 -0400 +++ b/pom.xml Wed Sep 02 11:26:48 2015 +0200 @@ -245,6 +245,7 @@ <module>laf-utils</module> <module>thermostat-plugin-validator</module> <module>validate-command</module> + <module>setup-command</module> <module>config</module> <!-- development related modules --> <module>integration-tests</module>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/setup-command/command/pom.xml Wed Sep 02 11:26:48 2015 +0200 @@ -0,0 +1,121 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + + Copyright 2012-2015 Red Hat, Inc. + + This file is part of Thermostat. + + Thermostat is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + Thermostat is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Thermostat; see the file COPYING. If not see + <http://www.gnu.org/licenses/>. + + Linking this code with other modules is making a combined work + based on this code. Thus, the terms and conditions of the GNU + General Public License cover the whole combination. + + As a special exception, the copyright holders of this code give + you permission to link this code with independent modules to + produce an executable, regardless of the license terms of these + independent modules, and to copy and distribute the resulting + executable under terms of your choice, provided that you also + meet, for each linked independent module, the terms and conditions + of the license of that module. An independent module is a module + which is not derived from or based on this code. If you modify + this code, you may extend this exception to your version of the + library, but you are not obligated to do so. If you do not wish + to do so, delete this exception statement from your version. + +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>com.redhat.thermostat</groupId> + <artifactId>thermostat-setup</artifactId> + <version>1.3.4-SNAPSHOT</version> + </parent> + + <artifactId>thermostat-setup-command</artifactId> + <packaging>bundle</packaging> + + <name>Thermostat Setup Command</name> + + <build> + <plugins> + <plugin> + <groupId>org.apache.felix</groupId> + <artifactId>maven-bundle-plugin</artifactId> + <extensions>true</extensions> + <configuration> + <instructions> + <Bundle-SymbolicName>com.redhat.thermostat.setup.command</Bundle-SymbolicName> + <Bundle-Vendor>Red Hat, Inc.</Bundle-Vendor> + <Export-Package /> + <Private-Package> + com.redhat.thermostat.setup.command, + com.redhat.thermostat.setup.command.internal, + com.redhat.thermostat.setup.command.locale, + </Private-Package> + <Bundle-Activator>com.redhat.thermostat.setup.command.internal.Activator</Bundle-Activator> + <!-- Do not autogenerate uses clauses in Manifests --> + <_nouses>true</_nouses> + </instructions> + </configuration> + </plugin> + </plugins> + </build> + + <dependencies> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.mockito</groupId> + <artifactId>mockito-core</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>com.redhat.thermostat</groupId> + <artifactId>thermostat-common-test</artifactId> + <version>${project.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>com.redhat.thermostat</groupId> + <artifactId>thermostat-common-core</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>com.redhat.thermostat</groupId> + <artifactId>thermostat-plugin-validator</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>com.redhat.thermostat</groupId> + <artifactId>thermostat-shared-config</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>com.redhat.thermostat</groupId> + <artifactId>thermostat-client-swing</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>com.redhat.thermostat</groupId> + <artifactId>thermostat-launcher</artifactId> + <version>${project.version}</version> + </dependency> + </dependencies> +</project> +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/setup-command/command/src/main/java/com/redhat/thermostat/setup/command/SetupCommand.java Wed Sep 02 11:26:48 2015 +0200 @@ -0,0 +1,113 @@ +/* + * Copyright 2012-2015 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.setup.command; + +import com.redhat.thermostat.common.cli.AbstractCommand; +import com.redhat.thermostat.common.cli.CommandContext; +import com.redhat.thermostat.common.cli.CommandException; +import com.redhat.thermostat.internal.utils.laf.ThemeManager; +import com.redhat.thermostat.setup.command.internal.SetupWindow; +import com.redhat.thermostat.setup.command.internal.ThermostatSetup; +import com.redhat.thermostat.setup.command.internal.ThermostatSetupImpl; +import com.redhat.thermostat.shared.config.CommonPaths; +import com.redhat.thermostat.shared.locale.LocalizedString; +import org.osgi.framework.BundleContext; + +import java.awt.EventQueue; +import java.io.PrintStream; +import java.lang.reflect.InvocationTargetException; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +public class SetupCommand extends AbstractCommand { + private SetupWindow mainWindow; + + private CommonPaths paths; + private BundleContext context; + private CountDownLatch pathsAvailable; + private ThermostatSetup thermostatSetup; + private PrintStream out; + + public SetupCommand(BundleContext context) { + this.context = context; + pathsAvailable = new CountDownLatch(1); + } + + @Override + public void run(CommandContext ctx) throws CommandException { + out = ctx.getConsole().getOutput(); + + try { + setLookAndFeel(); + + pathsAvailable.await(1000l, TimeUnit.MILLISECONDS); + requireNonNull(paths, new LocalizedString("CommonPaths dependency not available")); + + createMainWindowAndRun(); + } catch (InterruptedException | InvocationTargetException e) { + throw new CommandException(new LocalizedString("SetupCommand failed to run"), e); + } + } + + public void setPaths(CommonPaths paths) { + this.paths = paths; + pathsAvailable.countDown(); + } + + public boolean isStorageRequired() { + return false; + } + + //package-private for testing + void createMainWindowAndRun() { + thermostatSetup = new ThermostatSetupImpl(context, paths, out); + mainWindow = new SetupWindow(out, thermostatSetup); + mainWindow.run(); + } + + //package-private for testing + void setLookAndFeel() throws InvocationTargetException, InterruptedException { + EventQueue.invokeAndWait(new Runnable() { + @Override + public void run() { + ThemeManager themeManager = ThemeManager.getInstance(); + themeManager.setLAF(); + } + }); + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/setup-command/command/src/main/java/com/redhat/thermostat/setup/command/internal/Activator.java Wed Sep 02 11:26:48 2015 +0200 @@ -0,0 +1,84 @@ +/* + * Copyright 2012-2015 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.setup.command.internal; + +import java.util.Map; + +import com.redhat.thermostat.common.MultipleServiceTracker; +import com.redhat.thermostat.common.cli.CommandRegistry; +import com.redhat.thermostat.common.cli.CommandRegistryImpl; +import com.redhat.thermostat.shared.config.CommonPaths; +import org.osgi.framework.BundleActivator; +import org.osgi.framework.BundleContext; +import com.redhat.thermostat.setup.command.SetupCommand; + +public class Activator implements BundleActivator { + + private CommandRegistry reg; + private MultipleServiceTracker tracker; + private SetupCommand setupCommand; + + @Override + public void start(final BundleContext context) throws Exception { + reg = new CommandRegistryImpl(context); + setupCommand = new SetupCommand(context); + reg.registerCommand("setup", setupCommand); + + Class<?>[] deps = new Class<?>[] { + CommonPaths.class + }; + tracker = new MultipleServiceTracker(context, deps, new MultipleServiceTracker.Action() { + @Override + public void dependenciesAvailable(Map<String, Object> services) { + CommonPaths paths = (CommonPaths) services.get(CommonPaths.class.getName()); + setupCommand.setPaths(paths); + } + + @Override + public void dependenciesUnavailable() { + reg.unregisterCommands(); + } + }); + tracker.open(); + } + + @Override + public void stop(BundleContext context) throws Exception { + reg.unregisterCommands(); + tracker.close(); + } +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/setup-command/command/src/main/java/com/redhat/thermostat/setup/command/internal/CredentialFinder.java Wed Sep 02 11:26:48 2015 +0200 @@ -0,0 +1,70 @@ +/* + * Copyright 2012-2015 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.setup.command.internal; + +import com.redhat.thermostat.shared.config.CommonPaths; + +import java.io.File; + +public class CredentialFinder { + + private final CommonPaths paths; + + public CredentialFinder(CommonPaths paths) { + this.paths = paths; + } + + public File getConfiguration(String name) { + File systemFile = getConfigurationFile(paths.getSystemConfigurationDirectory(), name); + if (isUsable(systemFile)) { + return systemFile; + } + File userFile = getConfigurationFile(paths.getUserConfigurationDirectory(), name); + if (isUsable(userFile)) { + return userFile; + } + return null; + } + + File getConfigurationFile(File directory, String name) { + return new File(directory, name); + } + + private boolean isUsable(File file) { + return file.isFile() && file.canRead(); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/setup-command/command/src/main/java/com/redhat/thermostat/setup/command/internal/MongoUserSetupView.java Wed Sep 02 11:26:48 2015 +0200 @@ -0,0 +1,314 @@ +/* + * Copyright 2012-2015 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.setup.command.internal; + +import com.redhat.thermostat.setup.command.locale.LocaleResources; +import com.redhat.thermostat.shared.locale.Translate; + +import javax.swing.BorderFactory; +import javax.swing.Box; +import javax.swing.BoxLayout; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JPasswordField; +import javax.swing.JTextField; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.LayoutManager; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.net.URL; +import java.util.Arrays; + +public class MongoUserSetupView extends JPanel implements SetupView { + + private JButton backBtn; + private JButton defaultSetupBtn; + private JButton nextBtn; + private JButton cancelBtn; + + private JTextField usernameField; + private JPasswordField passwordField1; + private JPasswordField passwordField2; + + private JPanel toolbar; + private JPanel midPanel; + private JPanel detailsPanel; + private JPanel messagePanel; + + private JLabel usernameLabel; + private JLabel passwordLabel1; + private JLabel passwordLabel2; + private JLabel passwordMismatchLabel; + private JLabel detailsMissingLabel; + private JCheckBox showPasswordCheckbox; + + private static final String THERMOSTAT_LOGO = "thermostat.png"; + private static final String PROGRESS = "Step 2 of 3"; + private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer(); + + public MongoUserSetupView(LayoutManager layout) { + super(layout); + + createMidPanel(); + createToolbarPanel(); + + this.add(midPanel, BorderLayout.CENTER); + this.add(toolbar, BorderLayout.SOUTH); + + DocumentListener inputValidator = new DocumentListener() { + @Override + public void insertUpdate(DocumentEvent documentEvent) { + validateInput(); + } + + @Override + public void removeUpdate(DocumentEvent documentEvent) { + validateInput(); + } + + @Override + public void changedUpdate(DocumentEvent documentEvent) { + validateInput(); + } + }; + usernameField.getDocument().addDocumentListener(inputValidator); + passwordField1.getDocument().addDocumentListener(inputValidator); + passwordField2.getDocument().addDocumentListener(inputValidator); + } + + @Override + public void setTitleAndProgress(JLabel title, JLabel progress) { + title.setText(translator.localize(LocaleResources.MONGO_SETUP_TITLE).getContents()); + progress.setText(PROGRESS); + } + + private void createMidPanel() { + usernameLabel = new JLabel("Username: "); + usernameField = new JTextField(30); + passwordLabel1 = new JLabel("Password:"); + passwordField1 = new JPasswordField(30); + passwordLabel2 = new JLabel("Verify Password:"); + passwordField2 = new JPasswordField(30); + showPasswordCheckbox = new JCheckBox("Show passwords"); + showPasswordCheckbox.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent actionEvent) { + togglePasswords(showPasswordCheckbox.isSelected()); + } + }); + + defaultSetupBtn = new JButton("Use Defaults"); + defaultSetupBtn.setPreferredSize(new Dimension(140, 30)); + passwordMismatchLabel = new JLabel("Passwords don't match!"); + passwordMismatchLabel.setForeground(Color.RED); + detailsMissingLabel = new JLabel("Please fill in ALL fields"); + detailsMissingLabel.setForeground(Color.RED); + detailsPanel = new JPanel(new GridBagLayout()); + + GridBagConstraints c = new GridBagConstraints(); + c.fill = GridBagConstraints.HORIZONTAL; + c.gridx = 0; + c.gridy = 0; + c.gridwidth = 1; + c.insets.top = 40; + detailsPanel.add(usernameLabel, c); + c.gridx = 1; + c.gridy = 0; + c.gridwidth = 2; + detailsPanel.add(usernameField, c); + c.gridx = 0; + c.gridy = 1; + c.gridwidth = 1; + c.insets.top = 10; + detailsPanel.add(passwordLabel1, c); + c.gridx = 1; + c.gridy = 1; + c.gridwidth = 2; + detailsPanel.add(passwordField1, c); + c.gridx = 0; + c.gridy = 2; + c.gridwidth = 1; + detailsPanel.add(passwordLabel2, c); + c.gridx = 1; + c.gridy = 2; + c.gridwidth = 2; + detailsPanel.add(passwordField2, c); + c.gridx = 1; + c.gridy = 3; + c.gridwidth = 1; + detailsPanel.add(showPasswordCheckbox, c); + + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.LINE_END; + c.gridx = 2; + c.gridy = 3; + c.gridwidth = 1; + detailsPanel.add(defaultSetupBtn, c); + + messagePanel = new JPanel(new FlowLayout(FlowLayout.CENTER)); + + midPanel = new JPanel(new BorderLayout()); + midPanel.add(detailsPanel, BorderLayout.NORTH); + midPanel.add(messagePanel, BorderLayout.SOUTH); + } + + private void createToolbarPanel() { + URL logoURL = SetupWindow.class.getClassLoader().getResource(THERMOSTAT_LOGO); + JLabel thermostatLogo = new JLabel(new ImageIcon(logoURL)); + + backBtn = new JButton(translator.localize(LocaleResources.BACK).getContents()); + backBtn.setPreferredSize(new Dimension(70, 30)); + nextBtn = new JButton(translator.localize(LocaleResources.NEXT).getContents()); + nextBtn.setPreferredSize(new Dimension(70, 30)); + nextBtn.setEnabled(false); + cancelBtn = new JButton(translator.localize(LocaleResources.CANCEL).getContents()); + cancelBtn.setPreferredSize(new Dimension(70, 30)); + + toolbar = new JPanel(); + toolbar.setLayout(new BoxLayout(toolbar, BoxLayout.LINE_AXIS)); + toolbar.setBorder(BorderFactory.createEmptyBorder(0, 10, 10, 10)); + toolbar.add(thermostatLogo); + toolbar.add(Box.createHorizontalGlue()); + toolbar.add(backBtn); + toolbar.add(nextBtn); + toolbar.add(cancelBtn); + } + + private void togglePasswords(boolean isVisible) { + if (isVisible) { + passwordField1.setEchoChar((char) 0); + passwordField2.setEchoChar((char) 0); + } else { + passwordField1.setEchoChar('*'); + passwordField2.setEchoChar('*'); + } + } + + private void validateInput() { + if (usernameField.getText().isEmpty() || passwordField1.getPassword().length == 0 || passwordField2.getPassword().length == 0) { + showDetailsMissing(); + nextBtn.setEnabled(false); + } else if (!(Arrays.equals(passwordField1.getPassword(), passwordField2.getPassword()))) { + showPasswordMismatch(); + nextBtn.setEnabled(false); + } else { + removeErrorMessages(); + nextBtn.setEnabled(true); + } + } + + public void enableButtons() { + backBtn.setEnabled(true); + defaultSetupBtn.setEnabled(true); + nextBtn.setEnabled(true); + } + + public void disableButtons() { + backBtn.setEnabled(false); + defaultSetupBtn.setEnabled(false); + nextBtn.setEnabled(false); + } + + private void showPasswordMismatch() { + messagePanel.removeAll(); + messagePanel.add(passwordMismatchLabel); + midPanel.revalidate(); + midPanel.repaint(); + } + + private void showDetailsMissing() { + messagePanel.removeAll(); + messagePanel.add(detailsMissingLabel); + midPanel.revalidate(); + midPanel.repaint(); + } + + private void removeErrorMessages() { + messagePanel.removeAll(); + midPanel.revalidate(); + midPanel.repaint(); + } + + @Override + public Component getUiComponent() { + return this; + } + + public JButton getBackBtn() { + return backBtn; + } + + public JButton getDefaultSetupBtn() { + return defaultSetupBtn; + } + + public JButton getNextBtn() { + return nextBtn; + } + + public JButton getCancelBtn() { + return cancelBtn; + } + + public String getUsername() { + return usernameField.getText(); + } + + public void setUsername(String username) { + this.usernameField.setText(username); + } + + public char[] getPassword() { + return passwordField1.getPassword(); + } + + public void setPassword(String password) { + this.passwordField1.setText(password); + this.passwordField2.setText(password); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/setup-command/command/src/main/java/com/redhat/thermostat/setup/command/internal/MongodbUserSetupException.java Wed Sep 02 11:26:48 2015 +0200 @@ -0,0 +1,52 @@ +/* + * Copyright 2012-2015 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.setup.command.internal; + +public class MongodbUserSetupException extends Exception { + + public MongodbUserSetupException(String message) { + super(message); + } + + public MongodbUserSetupException(Throwable cause) { + super(cause); + } + + public MongodbUserSetupException(String message, Throwable cause) { + super(message, cause); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/setup-command/command/src/main/java/com/redhat/thermostat/setup/command/internal/SetupView.java Wed Sep 02 11:26:48 2015 +0200 @@ -0,0 +1,54 @@ +/* + * Copyright 2012-2015 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.setup.command.internal; + +import javax.swing.JLabel; +import java.awt.Component; + +public interface SetupView { + + /** + * Sets the title of the current view + * and updates the progress + * + * @param title + * @param progress + */ + void setTitleAndProgress(JLabel title, JLabel progress); + + Component getUiComponent(); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/setup-command/command/src/main/java/com/redhat/thermostat/setup/command/internal/SetupWindow.java Wed Sep 02 11:26:48 2015 +0200 @@ -0,0 +1,326 @@ +/* + * Copyright 2012-2015 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.setup.command.internal; + +import com.redhat.thermostat.setup.command.locale.LocaleResources; +import com.redhat.thermostat.shared.locale.Translate; + +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.SwingUtilities; +import javax.swing.SwingWorker; +import java.awt.BorderLayout; +import java.awt.Font; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.io.IOException; +import java.io.PrintStream; +import java.util.concurrent.CountDownLatch; +import java.util.Arrays; + +public class SetupWindow { + private CountDownLatch shutdown; + private JFrame frame; + private JPanel mainView; + private JPanel topPanel; + private JLabel title; + private JLabel progress; + private StartView startView; + private MongoUserSetupView mongoUserSetupView; + private UserPropertiesView userPropertiesView; + private String username = null; + private char[] password = null; + private boolean showDetailedBlurb = false; + private ThermostatSetup thermostatSetup; + + private static final String defaultUsername = "mongodevuser"; + private static final String defaultPassword = "mongodevpassword"; + private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer(); + + private PrintStream out; + + public SetupWindow(PrintStream out, ThermostatSetup thermostatSetup) { + this.out = out; + this.thermostatSetup = thermostatSetup; + shutdown = new CountDownLatch(1); + } + + public void run() { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + initialize(); + addViewListeners(); + showView(startView); + frame.setVisible(true); + } + }); + + try { + shutdown.await(); + } catch (InterruptedException e) { + e.printStackTrace(); + } finally { + cleanup(); + } + } + + private void cleanup() { + if (password != null) { + Arrays.fill(password, '\0'); + } + } + + private void initialize() { + frame = new JFrame(translator.localize(LocaleResources.WINDOW_TITLE).getContents()); + setLargeFrame(false); + frame.addWindowListener(new WindowAdapter() { + @Override + public void windowClosing(WindowEvent e) { + shutdown(); + } + }); + mainView = new JPanel(new BorderLayout()); + createTopPanel(); + mainView.add(topPanel, BorderLayout.NORTH); + frame.add(mainView); + + startView = new StartView(new BorderLayout()); + mongoUserSetupView = new MongoUserSetupView(new BorderLayout()); + userPropertiesView = new UserPropertiesView(new BorderLayout()); + } + + private void createTopPanel() { + title = new JLabel(); + title.setFont(new Font("Liberation Sans", Font.BOLD, 16)); + progress = new JLabel(); + + topPanel = new JPanel(new GridBagLayout()); + GridBagConstraints c = new GridBagConstraints(); + c.insets.left = 10; + c.insets.top = 10; + c.gridx = 0; + c.weightx = 0.5; + c.anchor = GridBagConstraints.LINE_START; + topPanel.add(progress, c); + c.gridx = 1; + c.weightx = 1; + c.gridwidth = 2; + topPanel.add(title, c); + } + + private void addViewListeners() { + startView.getNextBtn().addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent actionEvent) { + showDetailedBlurb = false; + startView.showMoreInfo(showDetailedBlurb); + setLargeFrame(showDetailedBlurb); + + mainView.remove(startView); + showView(mongoUserSetupView); + } + }); + startView.getCancelBtn().addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent actionEvent) { + shutdown(); + } + }); + startView.getShowMoreInfoBtn().addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent actionEvent) { + showDetailedBlurb = !showDetailedBlurb; + startView.showMoreInfo(showDetailedBlurb); + setLargeFrame(showDetailedBlurb); + } + }); + mongoUserSetupView.getBackBtn().addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent actionEvent) { + mainView.remove(mongoUserSetupView); + showView(startView); + } + }); + mongoUserSetupView.getDefaultSetupBtn().addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent actionEvent) { + mongoUserSetupView.setUsername(defaultUsername); + mongoUserSetupView.setPassword(defaultPassword); + } + }); + mongoUserSetupView.getNextBtn().addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent actionEvent) { + username = mongoUserSetupView.getUsername(); + password = mongoUserSetupView.getPassword(); + runMongoSetup(); + + if (thermostatSetup.isWebAppInstalled()) { + mainView.remove(mongoUserSetupView); + showView(userPropertiesView); + } + } + }); + mongoUserSetupView.getCancelBtn().addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent actionEvent) { + shutdown(); + } + }); + userPropertiesView.getFinishBtn().addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent actionEvent) { + runPropertiesSetup(); + } + }); + userPropertiesView.getCancelBtn().addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent actionEvent) { + shutdown(); + } + }); + } + + private void setLargeFrame(boolean setLarge) { + if (setLarge) { + frame.setSize(600, 600); + } else { + frame.setSize(600, 350); + } + } + + private void runMongoSetup() { + SwingWorker worker = new SwingWorker<Void, Void>() { + @Override + public Void doInBackground() { + mongoUserSetupView.disableButtons(); + userPropertiesView.disableButtons(); + try { + thermostatSetup.createMongodbUser(username, password); + } catch (MongodbUserSetupException e) { + e.printStackTrace(); + shutdown(); + } + return null; + } + + @Override + public void done() { + mongoUserSetupView.enableButtons(); + userPropertiesView.enableButtons(); + if (!thermostatSetup.isWebAppInstalled()) { + shutdown(); + } + } + }; + worker.execute(); + } + + private void runPropertiesSetup() { + SwingWorker worker = new SwingWorker<Void, Void>() { + @Override + public Void doInBackground() { + userPropertiesView.disableButtons(); + try { + String[] agentRoles = null; + String[] clientRoles = null; + if (userPropertiesView.makeAgentUserSelected()) { + agentRoles = new String[] { + UserRoles.CMD_CHANNEL_VERIFY, + UserRoles.LOGIN, + UserRoles.PREPARE_STATEMENT, + UserRoles.PURGE, + UserRoles.REGISTER_CATEGORY, + UserRoles.ACCESS_REALM, + UserRoles.SAVE_FILE, + UserRoles.WRITE, + UserRoles.GRANT_FILES_WRITE_ALL, + }; + } + if (userPropertiesView.makeClientAdminSelected()) { + clientRoles = new String[] { + UserRoles.GRANT_AGENTS_READ_ALL, + UserRoles.CMD_CHANNEL_GENERATE, + UserRoles.GRANT_HOSTS_READ_ALL, + UserRoles.LOAD_FILE, + UserRoles.LOGIN, + UserRoles.PREPARE_STATEMENT, + UserRoles.READ, + UserRoles.ACCESS_REALM, + UserRoles.REGISTER_CATEGORY, + UserRoles.GRANT_VMS_READ_BY_USERNAME_ALL, + UserRoles.GRANT_VMS_READ_BY_VM_ID_ALL, + UserRoles.GRANT_FILES_READ_ALL, + UserRoles.WRITE, + }; + } + thermostatSetup.createThermostatUser(username, password, agentRoles); + thermostatSetup.createThermostatUser(username, password, clientRoles); + + } catch (IOException e) { + e.printStackTrace(); + shutdown(); + } + return null; + } + + @Override + public void done() { + userPropertiesView.enableButtons(); + shutdown(); + } + }; + worker.execute(); + } + + private void showView(SetupView view) { + mainView.add(view.getUiComponent(), BorderLayout.CENTER); + view.setTitleAndProgress(title, progress); + mainView.revalidate(); + mainView.repaint(); + } + + private void shutdown() { + shutdown.countDown(); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/setup-command/command/src/main/java/com/redhat/thermostat/setup/command/internal/StartView.java Wed Sep 02 11:26:48 2015 +0200 @@ -0,0 +1,184 @@ +/* + * Copyright 2012-2015 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.setup.command.internal; + +import com.redhat.thermostat.common.ApplicationInfo; +import com.redhat.thermostat.setup.command.locale.LocaleResources; +import com.redhat.thermostat.shared.locale.Translate; + +import javax.swing.BorderFactory; +import javax.swing.Box; +import javax.swing.BoxLayout; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JEditorPane; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.event.HyperlinkEvent; +import javax.swing.event.HyperlinkListener; +import java.awt.BorderLayout; +import java.awt.Component; +import java.awt.Desktop; +import java.awt.Dimension; +import java.awt.LayoutManager; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; + +public class StartView extends JPanel implements SetupView { + + private JButton nextBtn; + private JButton cancelBtn; + private JButton moreInfoBtn; + + private JPanel toolbar; + private JEditorPane thermostatBlurb; + private JPanel midPanel; + private static final String THERMOSTAT_LOGO = "thermostat.png"; + private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer(); + private static final String SHOW_MORE = "Show More"; + private static final String SHOW_LESS = "Show Less"; + private static final String PROGRESS = "Step 1 of 3"; + + public StartView(LayoutManager layout) { + super(layout); + + createToolbarPanel(); + createMidPanel(); + } + + @Override + public void setTitleAndProgress(JLabel title, JLabel progress) { + title.setText(translator.localize(LocaleResources.WELCOME_SCREEN_TITLE).getContents()); + progress.setText(PROGRESS); + } + + private void createMidPanel() { + thermostatBlurb = new JEditorPane(); + thermostatBlurb.setEditorKit(JEditorPane.createEditorKitForContentType("text/html")); + thermostatBlurb.setEditable(false); + + moreInfoBtn = new JButton(); + moreInfoBtn.setAlignmentX(Component.LEFT_ALIGNMENT); + showMoreInfo(false); + + thermostatBlurb.addHyperlinkListener(new HyperlinkListener() { + public void hyperlinkUpdate(HyperlinkEvent e) { + if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) { + if (Desktop.isDesktopSupported()) { + String userGuideURL = new ApplicationInfo().getUserGuide(); + try { + Desktop.getDesktop().browse(new URI(userGuideURL)); + } catch (IOException | URISyntaxException e1) { + e1.printStackTrace(); + } + } + } + } + }); + JScrollPane scrollPane = new JScrollPane(thermostatBlurb); + scrollPane.setAlignmentX(Component.LEFT_ALIGNMENT); + + midPanel = new JPanel(); + midPanel.setLayout(new BoxLayout(midPanel, BoxLayout.Y_AXIS)); + midPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); + midPanel.add(scrollPane); + midPanel.add(moreInfoBtn); + + this.add(midPanel, BorderLayout.CENTER); + } + + private void createToolbarPanel() { + URL logoURL = SetupWindow.class.getClassLoader().getResource(THERMOSTAT_LOGO); + JLabel thermostatLogo = new JLabel(new ImageIcon(logoURL)); + + nextBtn = new JButton(translator.localize(LocaleResources.NEXT).getContents()); + nextBtn.setPreferredSize(new Dimension(70, 30)); + cancelBtn = new JButton(translator.localize(LocaleResources.CANCEL).getContents()); + cancelBtn.setPreferredSize(new Dimension(70, 30)); + + toolbar = new JPanel(); + toolbar.setLayout(new BoxLayout(toolbar, BoxLayout.LINE_AXIS)); + toolbar.setBorder(BorderFactory.createEmptyBorder(0, 10, 10, 10)); + toolbar.add(thermostatLogo); + toolbar.add(Box.createHorizontalGlue()); + toolbar.add(nextBtn); + toolbar.add(cancelBtn); + + this.add(toolbar, BorderLayout.SOUTH); + } + + public void showMoreInfo(boolean setDetailed) { + String userGuideURL = new ApplicationInfo().getUserGuide(); + StringBuilder text = new StringBuilder(); + + text.append("<html>"); + if(setDetailed) { + text.append(translator.localize(LocaleResources.THERMOSTAT_BLURB).getContents()); + moreInfoBtn.setText(SHOW_LESS); + } else { + text.append(translator.localize(LocaleResources.THERMOSTAT_BRIEF).getContents()); + moreInfoBtn.setText(SHOW_MORE); + } + text.append("<center><a href=\"\">") + .append(userGuideURL) + .append("</a></center>") + .append("</html>").toString(); + + thermostatBlurb.setText(text.toString()); + } + + @Override + public Component getUiComponent() { + return this; + } + + public JButton getShowMoreInfoBtn() { + return moreInfoBtn; + } + + public JButton getNextBtn() { + return nextBtn; + } + + public JButton getCancelBtn() { + return cancelBtn; + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/setup-command/command/src/main/java/com/redhat/thermostat/setup/command/internal/ThermostatSetup.java Wed Sep 02 11:26:48 2015 +0200 @@ -0,0 +1,71 @@ +/* + * Copyright 2012-2015 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.setup.command.internal; + +import java.io.IOException; + +public interface ThermostatSetup { + + /** + * Provided a username and password, + * creates a MongodbUser + * + * @param username + * @param password + * @throws MongodbUserSetupException + */ + void createMongodbUser(String username, char[] password) throws MongodbUserSetupException; + + /** + * Creates web.auth file and sets + * users.properties and + * roles.properties for a user + * + * @param username + * @param password + * @param roles + * @throws IOException + */ + void createThermostatUser(String username, char[] password, String[] roles) throws IOException; + + /** + * Checks if webapp is installed on the system + * + * @return true if webapp is installed, false otherwise + */ + boolean isWebAppInstalled(); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/setup-command/command/src/main/java/com/redhat/thermostat/setup/command/internal/ThermostatSetupImpl.java Wed Sep 02 11:26:48 2015 +0200 @@ -0,0 +1,391 @@ +/* + * Copyright 2012-2015 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.setup.command.internal; + +import com.redhat.thermostat.common.ActionEvent; +import com.redhat.thermostat.common.ActionListener; +import com.redhat.thermostat.common.cli.AbstractStateNotifyingCommand; +import com.redhat.thermostat.common.tools.ApplicationState; +import com.redhat.thermostat.setup.command.locale.LocaleResources; +import com.redhat.thermostat.shared.config.CommonPaths; +import com.redhat.thermostat.shared.locale.Translate; +import com.redhat.thermostat.launcher.Launcher; +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceReference; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintStream; +import java.io.PrintWriter; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Arrays; +import java.util.Properties; + + +public class ThermostatSetupImpl implements ThermostatSetup { + private static final String WEB_AUTH_FILE = "web.auth"; + private static final String USERS_PROPERTIES = "thermostat-users.properties"; + private static final String ROLES_PROPERTIES = "thermostat-roles.properties"; + private static final String MONGO_INPUT_SCRIPT = "/tmp/mongo-input.js"; + private static final String DEFAULT_AGENT_USER = "agent-tester"; + private static final String DEFAULT_CLIENT_USER = "client-tester"; + private static final String DEFAULT_USER_PASSWORD = "tester"; + private static final String THERMOSTAT_AGENT = "thermostat-agent"; + private static final String THERMOSTAT_CLIENT = "thermostat-client"; + private static final String THERMOSTAT_CMDC = "thermostat-cmdc"; + private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer(); + private static final String[] STORAGE_START_ARGS = {"storage", "--start", "--permitLocalhostException"}; + private static final String[] STORAGE_STOP_ARGS = {"storage", "--stop"}; + + private static boolean storageFailed = false; + private List<ActionListener<ApplicationState>> listeners; + private String setupTmpUnlockContent; + private String webApp; + private String setupUnlockContentRegular; + private String userAgentAuth; + private String userDoneFile; + private String createUserScript; + private PrintStream out; + private CredentialFinder finder; + private File setupCompleteFile; + private Launcher launcher; + private Properties roleProps; + + public ThermostatSetupImpl(BundleContext context, CommonPaths paths, PrintStream out) { + this.out = out; + finder = new CredentialFinder(paths); + + ServiceReference launcherRef = context.getServiceReference(Launcher.class); + launcher = (Launcher) context.getService(launcherRef); + + listeners = new ArrayList<>(); + listeners.add(new StorageListener(out)); + setThermostatVars(paths); + } + + //package-private constructor for testing + ThermostatSetupImpl(Launcher launcher, CommonPaths paths, PrintStream out, CredentialFinder finder) { + this.launcher = launcher; + this.finder = finder; + listeners = new ArrayList<>(); + listeners.add(new StorageListener(out)); + setThermostatVars(paths); + } + + private void setThermostatVars(CommonPaths paths) { + //set thermostat environment + createUserScript = paths.getSystemThermostatHome().toString() + "/lib/create-user.js"; + userAgentAuth = paths.getUserAgentAuthConfigFile().toString(); + userDoneFile = paths.getUserThermostatHome().toString() + "/data/mongodb-user-done.stamp"; + webApp = paths.getSystemThermostatHome() + "/webapp"; + String setupCompletePath = paths.getUserThermostatHome().toString() + "/data/setup-complete.stamp"; + setupCompleteFile = new File(setupCompletePath); + + //set stamp complete vars + DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd-HH:mm:ss zzz"); + Date date = new Date(); + String timestamp = dateFormat.format(date); + String programName = "Thermostat Setup"; + setupTmpUnlockContent = "Temporarily unlocked thermostat via " + programName + " on " + timestamp; + setupUnlockContentRegular = "Created by " + programName + " on " + timestamp; + } + + @Override + public void createMongodbUser(String username, char[] password) throws MongodbUserSetupException { + try { + unlockThermostat(); + + startStorage(); + + byte[] encoded = Files.readAllBytes(Paths.get(createUserScript)); + String mongoInput = new String(encoded); + mongoInput = mongoInput.replaceAll("\\$USERNAME", username); + mongoInput = mongoInput.replaceAll("\\$PASSWORD", String.valueOf(password)); + + File mongoInputFile = new File(MONGO_INPUT_SCRIPT); + mongoInputFile.deleteOnExit(); + Files.write(mongoInputFile.toPath(), mongoInput.getBytes()); + + int mongoRetVal = runMongo(); + if (mongoRetVal != 0) { + throw new MongodbUserSetupException("Mongodb user setup failed"); + } + + stopStorage(); + + File userDoneFile = new File(this.userDoneFile); + userDoneFile.createNewFile(); + + Files.write(setupCompleteFile.toPath(), setupUnlockContentRegular.getBytes()); + } catch (IOException | InterruptedException e) { + removeTempStampFile(); + throw new MongodbUserSetupException("Error creating Mongodb user", e); + } + } + + //package-private for testing + void unlockThermostat() throws IOException { + Files.write(setupCompleteFile.toPath(), setupTmpUnlockContent.getBytes()); + } + + private void startStorage() throws MongodbUserSetupException { + launcher.run(STORAGE_START_ARGS, listeners, false); + + if (storageFailed) { + throw new MongodbUserSetupException("Thermostat storage failed to start"); + } + } + + private void stopStorage() throws MongodbUserSetupException { + launcher.run(STORAGE_STOP_ARGS, listeners, false); + + if (storageFailed) { + throw new MongodbUserSetupException("Thermostat storage failed to stop"); + } + } + + //package-private for testing + int runMongo() throws IOException, InterruptedException { + ProcessBuilder mongoProcess = new ProcessBuilder("mongo", "127.0.0.1:27518/thermostat", MONGO_INPUT_SCRIPT); + return mongoProcess.start().waitFor(); + } + + private void removeTempStampFile() { + if (setupCompleteFile.exists()) { + setupCompleteFile.delete(); + } + } + + @Override + public void createThermostatUser(String username, char[] password, String[] roles) throws IOException { + File credentialsFile = finder.getConfiguration(WEB_AUTH_FILE); + try { + Properties credentialProps = new Properties(); + credentialProps.setProperty("storage.username", username); + credentialProps.setProperty("storage.password", String.valueOf(password)); + credentialProps.store(new FileOutputStream(credentialsFile), "Storage Credentials"); + + credentialsFile.setReadable(true, false); + credentialsFile.setWritable(true, true); + + List<String> rolesList = Arrays.asList(roles); + + if(rolesList.containsAll(Arrays.asList(UserRoles.CLIENT_ROLES))) { + createClientUser(); + setClientRoles(roles); + } else if(rolesList.containsAll(Arrays.asList(UserRoles.AGENT_ROLES))) { + createAgentUser(); + setAgentRoles(roles); + } + + } catch (IOException e) { + throw new IOException("Automatic substitution of file " + WEB_AUTH_FILE + " failed!", e); + } + } + + private void createAgentUser() throws IOException { + Properties userProps = new Properties(); + FileOutputStream userStream = new FileOutputStream(finder.getConfiguration(USERS_PROPERTIES), true); + userProps.setProperty(DEFAULT_AGENT_USER, DEFAULT_USER_PASSWORD); + userProps.store(userStream, "Agent User"); + + setAgentCredentials(); + } + + private void setAgentCredentials() throws IOException { + Properties agentProps = new Properties(); + FileOutputStream agentAuthStream = new FileOutputStream(new File(userAgentAuth)); + agentProps.setProperty("username", DEFAULT_AGENT_USER); + agentProps.setProperty("password", DEFAULT_USER_PASSWORD); + agentProps.store(agentAuthStream, "Agent Credentials"); + } + + private void createClientUser() throws IOException { + Properties userProps = new Properties(); + FileOutputStream userStream = new FileOutputStream(finder.getConfiguration(USERS_PROPERTIES), true); + userProps.setProperty(DEFAULT_CLIENT_USER, DEFAULT_USER_PASSWORD); + userProps.store(userStream, "Client User"); + } + + private void setAgentRoles(String[] agentRoles) throws IOException { + String[] agentUserRoles = new String[] { + THERMOSTAT_AGENT + }; + setRoleProperty(DEFAULT_AGENT_USER, agentUserRoles); + setRoleProperty(THERMOSTAT_AGENT, agentRoles); + FileOutputStream roleStream = new FileOutputStream(finder.getConfiguration(ROLES_PROPERTIES), true); + roleProps.store(new PropertiesWriter(roleStream), "Thermostat Agent Roles"); + } + + private void setClientRoles(String[] clientRoles) throws IOException { + String[] clientUserRoles = new String[] { + THERMOSTAT_CLIENT, + THERMOSTAT_CMDC, + UserRoles.PURGE + }; + + String[] cmdcRoles = new String[]{ + UserRoles.GRANT_CMD_CHANNEL_GARBAGE_COLLECT, + UserRoles.GRANT_CMD_CHANNEL_DUMP_HEAP, + UserRoles.GRANT_CMD_CHANNEL_GRANT_THREAD_HARVESTER, + UserRoles.GRANT_CMD_CHANNEL_KILLVM, + UserRoles.GRANT_CMD_PROFILE_VM, + UserRoles.GRANT_CMD_CHANNEL_PING, + UserRoles.GRANT_CMD_CHANNEL_JMX_TOGGLE_NOTIFICATION, + }; + + setRoleProperty(DEFAULT_CLIENT_USER, clientUserRoles); + setRoleProperty(THERMOSTAT_CLIENT, clientRoles); + setRoleProperty(THERMOSTAT_CMDC, cmdcRoles); + + FileOutputStream roleStream = new FileOutputStream(finder.getConfiguration(ROLES_PROPERTIES), true); + roleProps.store(new PropertiesWriter(roleStream), "Thermostat Client Roles"); + } + + private void setRoleProperty(String attribute, String[] roles) throws IOException { + if(roleProps == null) { + roleProps = new Properties(); + } + if (roles.length > 0) { + StringBuilder rolesBuilder = new StringBuilder(); + for (int i = 0; i < roles.length - 1; i++) { + rolesBuilder.append(roles[i] + ", " + System.getProperty("line.separator")); + } + rolesBuilder.append(roles[roles.length - 1]); + roleProps.setProperty(attribute, rolesBuilder.toString()); + } + } + + @Override + public boolean isWebAppInstalled() { + Path webAppPath = Paths.get(webApp); + if (Files.exists(webAppPath)) { + return true; + } else { + return false; + } + } + + /** + * The Properties.store() method doesn't allow for new lines. This + * class is used so that when a property key has multiple associated + * values, they are written in a readable manner. + */ + public static class PropertiesWriter extends PrintWriter { + + private static final int INDENT_AMOUNT = 4; + + public PropertiesWriter(OutputStream out) { + super(out); + } + + @Override + public void write(char[] line, int startIdx, int len) { + for (int i = startIdx; i < len; i++) { + // interpret new lines as such + if (isNewLine(line, i)) { + i++; // skip 'n' in \n + try { + out.write('\\'); + out.write(System.getProperty("line.separator")); + // indent following lines + for (int j = 0; j < INDENT_AMOUNT; j++) { + out.write(' '); + } + } catch (IOException e) { + e.printStackTrace(System.err); + } + } else { + try { + out.write(line[i]); + } catch (IOException e) { + e.printStackTrace(System.err); + } + } + } + } + + private boolean isNewLine(char[] line, int j) { + if (j + 1 > line.length) { + return false; + } + if (line[j] == '\\' && line[j + 1] == 'n') { + return true; + } + return false; + } + } + + private static class StorageListener implements ActionListener<ApplicationState> { + + private final PrintStream out; + + private StorageListener(PrintStream out) { + this.out = out; + } + + @Override + public void actionPerformed(ActionEvent<ApplicationState> actionEvent) { + if (actionEvent.getSource() instanceof AbstractStateNotifyingCommand) { + AbstractStateNotifyingCommand storage = (AbstractStateNotifyingCommand) actionEvent.getSource(); + // Implementation detail: there is a single Storage instance registered + // as an OSGi service. We remove ourselves as listener so that we don't get + // notified in the case that the command is invoked by some other means later. + storage.getNotifier().removeActionListener(this); + + switch (actionEvent.getActionId()) { + case START: + storageFailed = false; + break; + case FAIL: + out.println(translator.localize(LocaleResources.STORAGE_FAILED).getContents()); + storageFailed = true; + break; + } + } + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/setup-command/command/src/main/java/com/redhat/thermostat/setup/command/internal/UserPropertiesView.java Wed Sep 02 11:26:48 2015 +0200 @@ -0,0 +1,172 @@ +/* + * Copyright 2012-2015 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.setup.command.internal; + +import com.redhat.thermostat.setup.command.locale.LocaleResources; +import com.redhat.thermostat.shared.locale.Translate; + +import javax.swing.BorderFactory; +import javax.swing.Box; +import javax.swing.BoxLayout; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JLabel; +import javax.swing.JPanel; +import java.awt.BorderLayout; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.LayoutManager; +import java.net.URL; + +public class UserPropertiesView extends JPanel implements SetupView { + + private JButton finishBtn; + private JButton backBtn; + private JButton cancelBtn; + + private JPanel toolbar; + private JPanel midPanel; + private JPanel detailsPanel; + private JCheckBox makeAgentUserBtn; + private JCheckBox makeClientAdminBtn; + + private static final String THERMOSTAT_LOGO = "thermostat.png"; + private static final String PROGRESS = "Step 3 of 3"; + private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer(); + + public UserPropertiesView(LayoutManager layout) { + super(layout); + + createMidPanel(); + createToolbarPanel(); + + this.add(midPanel, BorderLayout.CENTER); + this.add(toolbar, BorderLayout.SOUTH); + } + + @Override + public void setTitleAndProgress(JLabel title, JLabel progress) { + title.setText(translator.localize(LocaleResources.USERS_SETUP_TITLE).getContents()); + progress.setText(PROGRESS); + } + + public void createMidPanel() { + JLabel agentInfo = new JLabel(translator.localize(LocaleResources.AGENT_INFO).getContents()); + JLabel clientInfo = new JLabel(translator.localize(LocaleResources.CLIENT_INFO).getContents()); + makeAgentUserBtn = new JCheckBox(translator.localize(LocaleResources.CREATE_AGENT_USER).getContents()); + makeAgentUserBtn.setSelected(true); + makeClientAdminBtn = new JCheckBox(translator.localize(LocaleResources.CREATE_CLIENT_ADMIN).getContents()); + makeClientAdminBtn.setSelected(true); + detailsPanel = new JPanel(new GridBagLayout()); + + GridBagConstraints c = new GridBagConstraints(); + c.fill = GridBagConstraints.HORIZONTAL; + c.gridy = 0; + c.insets.top = 40; + detailsPanel.add(agentInfo, c); + c.gridy = 1; + c.insets.top = 10; + detailsPanel.add(makeAgentUserBtn, c); + c.insets.top = 25; + c.gridy = 2; + detailsPanel.add(clientInfo, c); + c.insets.top = 10; + c.gridy = 3; + detailsPanel.add(makeClientAdminBtn, c); + + midPanel = new JPanel(new BorderLayout()); + midPanel.add(detailsPanel, BorderLayout.NORTH); + } + + private void createToolbarPanel() { + URL logoURL = SetupWindow.class.getClassLoader().getResource(THERMOSTAT_LOGO); + JLabel thermostatLogo = new JLabel(new ImageIcon(logoURL)); + + backBtn = new JButton(translator.localize(LocaleResources.BACK).getContents()); + backBtn.setPreferredSize(new Dimension(70, 30)); + backBtn.setEnabled(false); + finishBtn = new JButton(translator.localize(LocaleResources.FINISH).getContents()); + finishBtn.setPreferredSize(new Dimension(70, 30)); + cancelBtn = new JButton(translator.localize(LocaleResources.CANCEL).getContents()); + cancelBtn.setPreferredSize(new Dimension(70, 30)); + + toolbar = new JPanel(); + toolbar.setLayout(new BoxLayout(toolbar, BoxLayout.LINE_AXIS)); + toolbar.setBorder(BorderFactory.createEmptyBorder(0, 10, 10, 10)); + toolbar.add(thermostatLogo); + toolbar.add(Box.createHorizontalGlue()); + toolbar.add(backBtn); + toolbar.add(finishBtn); + toolbar.add(cancelBtn); + } + + public void enableButtons() { + makeAgentUserBtn.setEnabled(true); + makeClientAdminBtn.setEnabled(true); + finishBtn.setEnabled(true); + } + + public void disableButtons() { + makeAgentUserBtn.setEnabled(false); + makeClientAdminBtn.setEnabled(false); + finishBtn.setEnabled(false); + } + + @Override + public Component getUiComponent() { + return this; + } + + public JButton getFinishBtn() { + return finishBtn; + } + + public JButton getCancelBtn() { + return cancelBtn; + } + + public boolean makeAgentUserSelected() { + return makeAgentUserBtn.isSelected(); + } + + public boolean makeClientAdminSelected() { + return makeClientAdminBtn.isSelected(); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/setup-command/command/src/main/java/com/redhat/thermostat/setup/command/internal/UserRoles.java Wed Sep 02 11:26:48 2015 +0200 @@ -0,0 +1,112 @@ +/* + * Copyright 2012-2015 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.setup.command.internal; + +public interface UserRoles { + + /** + * Allows for a user to read records tied to any host. + */ + final String GRANT_HOSTS_READ_ALL = "thermostat-hosts-grant-read-hostname-ALL"; + /** + * Allows for a user to read records tied to any JVM id. + */ + final String GRANT_VMS_READ_BY_VM_ID_ALL = "thermostat-vms-grant-read-vmId-ALL"; + /** + * Allows for a user to read records tied to any username the JVM is running as. + */ + final String GRANT_VMS_READ_BY_USERNAME_ALL = "thermostat-vms-grant-read-username-ALL"; + /** + * Allows for a user to read any file from storage. + */ + final String GRANT_FILES_READ_ALL = "thermostat-files-grant-read-filename-ALL"; + /** + * Allows for a user to write any file to storage. + */ + final String GRANT_FILES_WRITE_ALL = "thermostat-files-grant-write-filename-ALL"; + /** + * Allows for a user to see records tied to any agent. + */ + final String GRANT_AGENTS_READ_ALL = "thermostat-agents-grant-read-agentId-ALL"; + + final String GRANT_CMD_CHANNEL_GARBAGE_COLLECT = "thermostat-cmdc-grant-garbage-collect"; + final String GRANT_CMD_CHANNEL_DUMP_HEAP = "thermostat-cmdc-grant-dump-heap"; + final String GRANT_CMD_CHANNEL_GRANT_THREAD_HARVESTER = "thermostat-cmdc-grant-thread-harvester"; + final String GRANT_CMD_CHANNEL_KILLVM = "thermostat-cmdc-grant-killvm"; + final String GRANT_CMD_CHANNEL_PING = "thermostat-cmdc-grant-ping"; + final String GRANT_CMD_CHANNEL_JMX_TOGGLE_NOTIFICATION = "thermostat-cmdc-grant-jmx-toggle-notifications"; + final String GRANT_CMD_PROFILE_VM = "thermostat-cmdc-grant-profile-vm"; + + final String PREPARE_STATEMENT = "thermostat-prepare-statement"; + final String READ = "thermostat-query"; + final String WRITE = "thermostat-write"; + final String LOAD_FILE = "thermostat-load-file"; + final String SAVE_FILE = "thermostat-save-file"; + final String PURGE = "thermostat-purge"; + final String REGISTER_CATEGORY = "thermostat-register-category"; + final String CMD_CHANNEL_VERIFY = "thermostat-cmdc-verify"; + final String CMD_CHANNEL_GENERATE = "thermostat-cmdc-generate"; + final String LOGIN = "thermostat-login"; + final String ACCESS_REALM = "thermostat-realm"; + + /** + * Basic role memberships for agent users + */ + final String[] AGENT_ROLES = { + UserRoles.PREPARE_STATEMENT, + UserRoles.WRITE, + UserRoles.CMD_CHANNEL_VERIFY, + UserRoles.LOGIN, + UserRoles.PURGE, + UserRoles.REGISTER_CATEGORY, + UserRoles.ACCESS_REALM, + UserRoles.SAVE_FILE, + }; + + /** + * Basic role memberships for client users + */ + final String[] CLIENT_ROLES = { + UserRoles.ACCESS_REALM, + UserRoles.LOGIN, + UserRoles.READ, + UserRoles.PREPARE_STATEMENT, + UserRoles.CMD_CHANNEL_GENERATE, + UserRoles.LOAD_FILE, + UserRoles.REGISTER_CATEGORY + }; +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/setup-command/command/src/main/java/com/redhat/thermostat/setup/command/locale/LocaleResources.java Wed Sep 02 11:26:48 2015 +0200 @@ -0,0 +1,69 @@ +/* + * Copyright 2012-2015 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.setup.command.locale; + +import com.redhat.thermostat.shared.locale.Translate; + + +public enum LocaleResources { + + WINDOW_TITLE, + WELCOME_SCREEN_TITLE, + MONGO_SETUP_TITLE, + USERS_SETUP_TITLE, + NEXT, + BACK, + CANCEL, + FINISH, + AGENT_INFO, + CLIENT_INFO, + THERMOSTAT_BRIEF, + THERMOSTAT_BLURB, + STORAGE_FAILED, + CREATE_AGENT_USER, + CREATE_CLIENT_ADMIN, + ; + + static final String RESOURCE_BUNDLE = + "com.redhat.thermostat.setup.locale.strings"; + + public static Translate<LocaleResources> createLocalizer() { + return new Translate(RESOURCE_BUNDLE, LocaleResources.class); + } + +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/setup-command/command/src/main/resources/com/redhat/thermostat/setup/locale/strings.properties Wed Sep 02 11:26:48 2015 +0200 @@ -0,0 +1,64 @@ +WINDOW_TITLE=Thermostat Setup + +WELCOME_SCREEN_TITLE=Welcome to the Thermostat Setup Wizard + +MONGO_SETUP_TITLE=MongoDB User Setup + +USERS_SETUP_TITLE=Thermostat Users Setup + +NEXT=Next> + +BACK=<Back + +CANCEL=Cancel + +FINISH=Finish + +THERMOSTAT_BRIEF=\ +<p>\ + Thermostat is a database backed distributed monitoring \ + solution with support for monitoring multiple JVM instances. \ +</p>\ +<p>\ + Please see the Thermostat User Guide for more information:\ +<p> + +THERMOSTAT_BLURB =\ +<p>\ + Thermostat is a database backed distributed monitoring \ + solution with support for monitoring multiple JVM instances. \ + The system is made up of three (3) components:\ +</p>\ +<ol>\ + <li>Agents which collect data.</li>\ + <li>Clients, which allow users to visualize collected data.</li>\ + <li>Storage layer which connects the above components.</li>\ +</ol>\ +<p>\ + The storage layer itself is two-tiered. The endpoint agents \ + and clients communicate with is a web application which uses \ + Mongodb as a backing database. \ +</p>\ +<p>\ + This setup wizard helps with a setup where all three components \ + run on a local system. In particular, it helps with the setup \ + of the storage layer. First, a user is set up in mongodb which \ + the web endpoint will use for database connections. Second, \ + the web endpoint's servlet config is updated so as to use the \ + credentials of this database user. \ +</p>\ +<p>\ + Please see the Thermostat User Guide for more information on \ + how to connect clients and agents to the pre-configured storage \ + layer:\ +<p> + +CREATE_AGENT_USER=Create Agent User + +CREATE_CLIENT_ADMIN=Create Client Admin User + +STORAGE_FAILED="Thermostat storage failed" + +AGENT_INFO=Agents connect to storage and send collected data from JVMs + +CLIENT_INFO=Clients connect to storage and retrieve data to display
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/setup-command/command/src/test/java/com/redhat/thermostat/setup/command/SetupCommandTest.java Wed Sep 02 11:26:48 2015 +0200 @@ -0,0 +1,158 @@ +/* + * Copyright 2012-2015 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.setup.command; + +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.List; + +import com.redhat.thermostat.common.cli.CommandException; +import com.redhat.thermostat.shared.config.CommonPaths; +import org.junit.Before; + +import com.redhat.thermostat.common.cli.Arguments; +import com.redhat.thermostat.common.cli.CommandContext; +import com.redhat.thermostat.common.cli.Console; +import org.junit.Test; +import org.osgi.framework.BundleContext; + +public class SetupCommandTest { + + private SetupCommand cmd; + private BundleContext context; + private CommandContext ctxt; + private Arguments mockArgs; + private Console console; + private List<String> list = new ArrayList<>(); + private ByteArrayOutputStream outputBaos, errorBaos; + private PrintStream output, error; + private CommonPaths paths; + + @Before + public void setUp() { + paths = mock(CommonPaths.class); + context = mock(BundleContext.class); + ctxt = mock(CommandContext.class); + mockArgs = mock(Arguments.class); + console = mock(Console.class); + + outputBaos = new ByteArrayOutputStream(); + output = new PrintStream(outputBaos); + + errorBaos = new ByteArrayOutputStream(); + error = new PrintStream(errorBaos); + + when(ctxt.getArguments()).thenReturn(mockArgs); + when(ctxt.getConsole()).thenReturn(console); + when(console.getError()).thenReturn(error); + when(console.getOutput()).thenReturn(output); + when(mockArgs.getNonOptionArguments()).thenReturn(list); + } + + @Test + public void testLookAndFeelIsSet() throws CommandException { + final boolean[] isSet = {false}; + cmd = new SetupCommand(context) { + @Override + void setLookAndFeel() throws InvocationTargetException, InterruptedException { + isSet[0] = true; + } + + @Override + void createMainWindowAndRun() { + //do nothing + } + }; + + cmd.setPaths(paths); + cmd.run(ctxt); + + assertTrue(isSet[0]); + } + + @Test + public void testCreateMainWindowIsCalled() throws CommandException { + final boolean[] isSet = {false}; + cmd = new SetupCommand(context) { + @Override + void setLookAndFeel() throws InvocationTargetException, InterruptedException { + //do nothing + } + + @Override + void createMainWindowAndRun() { + isSet[0] = true; + } + }; + + cmd.setPaths(paths); + cmd.run(ctxt); + + assertTrue(isSet[0]); + } + + @Test + public void testPathsNotSetFailure() { + cmd = new SetupCommand(context) { + @Override + void setLookAndFeel() throws InvocationTargetException, InterruptedException { + //do nothing + } + + @Override + void createMainWindowAndRun() { + //do nothing + } + }; + + try { + cmd.run(ctxt); + fail(); + } catch (CommandException e) { + assertTrue(e.getMessage().contains("CommonPaths dependency not available")); + } + } + +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/setup-command/command/src/test/java/com/redhat/thermostat/setup/command/internal/ActivatorTest.java Wed Sep 02 11:26:48 2015 +0200 @@ -0,0 +1,70 @@ +/* + * Copyright 2012-2015 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.setup.command.internal; + +import static com.redhat.thermostat.testutils.Asserts.assertCommandIsRegistered; +import static org.junit.Assert.*; +import static org.mockito.Mockito.mock; + +import com.redhat.thermostat.shared.config.CommonPaths; +import org.junit.Test; + +import com.redhat.thermostat.testutils.StubBundleContext; +import com.redhat.thermostat.setup.command.SetupCommand; + +public class ActivatorTest { + + @Test + public void testCommandsRegistered() throws Exception { + StubBundleContext ctx = new StubBundleContext(); + + CommonPaths paths = mock(CommonPaths.class); + ctx.registerService(CommonPaths.class, paths, null); + + Activator activator = new Activator(); + + activator.start(ctx); + + assertCommandIsRegistered(ctx, "setup", SetupCommand.class); + + activator.stop(ctx); + + assertEquals(1, ctx.getAllServices().size()); + } + +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/setup-command/command/src/test/java/com/redhat/thermostat/setup/command/internal/CredentialFinderTest.java Wed Sep 02 11:26:48 2015 +0200 @@ -0,0 +1,136 @@ +/* + * Copyright 2012-2015 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.setup.command.internal; + +import com.redhat.thermostat.shared.config.CommonPaths; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; + +import static junit.framework.Assert.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class CredentialFinderTest { + private File systemConfigDir = mock(File.class); + private File userConfigDir = mock(File.class); + + private File realFile1; + private File realFile2; + + private CommonPaths paths; + + @Before + public void setUp() throws IOException { + realFile1 = Files.createTempFile("credentialfinder-unit-test", null).toFile(); + realFile1.createNewFile(); + + realFile2 = Files.createTempFile("credentialfinder-unit-test", null).toFile(); + realFile2.createNewFile(); + + paths = mock(CommonPaths.class); + when(paths.getSystemConfigurationDirectory()).thenReturn(systemConfigDir); + when(paths.getUserConfigurationDirectory()).thenReturn(userConfigDir); + } + + @After + public void tearDown() { + realFile1.delete(); + realFile2.delete(); + } + + @Test + public void verifyFileFromUserHomeIsUsedIfSystemHomeIsNotUsable() throws Exception { + CredentialFinder finder = new CredentialFinder(paths) { + @Override + File getConfigurationFile(File directory, String name) { + if (directory == systemConfigDir) { + return new File("/does-not-exist/really-it-doesn't"); + } else if (directory == userConfigDir) { + return realFile1; + } + throw new AssertionError("Unknown test case"); + }; + }; + + File config = finder.getConfiguration("web.auth"); + assertEquals(realFile1, config); + } + + @Test + public void verifyFileFromSystemHomeIsUsedIfBothAreUsable() throws IOException { + final File systemFile = realFile1; + final File userFile = realFile2; + + CredentialFinder finder = new CredentialFinder(paths) { + @Override + File getConfigurationFile(File directory, String name) { + if (directory == systemConfigDir) { + return systemFile; + } else if (directory == userConfigDir) { + return userFile; + } + throw new AssertionError("Unknown test case"); + }; + }; + + File config = finder.getConfiguration("web.auth"); + assertEquals(systemFile, config); + } + + @Test + public void verifyFileFromSystemHomeIsUsedIfUserHomeNotUsable() throws IOException { + CredentialFinder finder = new CredentialFinder(paths) { + @Override + File getConfigurationFile(File directory, String name) { + if (directory == systemConfigDir) { + return realFile1; + } else if (directory == userConfigDir) { + return new File("/does-not-exist/really-it-doesn't"); + } + throw new AssertionError("Unknown test case"); + }; + }; + + File config = finder.getConfiguration("web.auth"); + assertEquals(realFile1, config); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/setup-command/command/src/test/java/com/redhat/thermostat/setup/command/internal/ThermostatSetupImplTest.java Wed Sep 02 11:26:48 2015 +0200 @@ -0,0 +1,444 @@ +/* + * Copyright 2012-2015 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.setup.command.internal; + +import com.redhat.thermostat.common.ActionEvent; +import com.redhat.thermostat.common.ActionListener; +import com.redhat.thermostat.common.ActionNotifier; +import com.redhat.thermostat.common.cli.AbstractStateNotifyingCommand; +import com.redhat.thermostat.common.tools.ApplicationState; +import com.redhat.thermostat.launcher.Launcher; +import com.redhat.thermostat.shared.config.CommonPaths; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintStream; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.Arrays; +import java.util.Collection; +import java.util.Properties; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.Matchers.anyBoolean; +import static org.mockito.Matchers.eq; +import static org.mockito.Matchers.isA; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.mockito.Mockito.times; + +public class ThermostatSetupImplTest { + + private Path testRoot; + private Path thermostatSysHome; + private Path thermostatUserHome; + private Path sysConfigDir; + private Path userConfigDir; + private Path userDataDir; + private Path userAgentAuth; + private Path credentialsFile; + private Path userPropertiesFile; + private Path rolesPropertiesFile; + private static final String username = "mongodevuser"; + private static final String password = "mongodevpassword"; + private static final String[] STORAGE_START_ARGS = {"storage", "--start", "--permitLocalhostException"}; + private static final String[] STORAGE_STOP_ARGS = {"storage", "--stop"}; + private static final String WEB_AUTH_FILE = "web.auth"; + private static final String USERS_PROPERTIES = "thermostat-users.properties"; + private static final String ROLES_PROPERTIES = "thermostat-roles.properties"; + private static final String THERMOSTAT_AGENT = "thermostat-agent"; + + private ThermostatSetupImpl tSetup; + private CommonPaths paths; + private Launcher mockLauncher; + private OutputStream out; + private static ActionEvent<ApplicationState> mockActionEvent; + private static Collection<ActionListener<ApplicationState>> listeners; + private CredentialFinder mockCredentialFinder; + + private void makeTempFilesAndDirectories() throws IOException { + testRoot = Files.createTempDirectory("thermostat"); + + thermostatSysHome = testRoot.resolve("system"); + Files.createDirectory(thermostatSysHome); + thermostatUserHome = testRoot.resolve("user"); + Files.createDirectory(thermostatUserHome); + + sysConfigDir = thermostatSysHome.resolve("etc"); + Files.createDirectories(sysConfigDir); + Path sysLibDir = thermostatSysHome.resolve("lib"); + Files.createDirectories(sysLibDir); + + userConfigDir = thermostatUserHome.resolve("etc"); + Files.createDirectories(userConfigDir); + userDataDir = thermostatUserHome.resolve("data"); + Files.createDirectories(userDataDir); + + userAgentAuth = userConfigDir.resolve("agent.auth"); + credentialsFile = sysConfigDir.resolve(WEB_AUTH_FILE); + userPropertiesFile = sysConfigDir.resolve(USERS_PROPERTIES); + rolesPropertiesFile = sysConfigDir.resolve(ROLES_PROPERTIES); + + //create a dummy create-user.js + Path createUserScript = sysLibDir.resolve("create-user.js"); + Files.write(createUserScript, new byte[]{}); + } + + @Before + public void setup() throws IOException, InterruptedException { + makeTempFilesAndDirectories(); + + out = new ByteArrayOutputStream(); + + paths = mock(CommonPaths.class); + when(paths.getSystemThermostatHome()).thenReturn(thermostatSysHome.toFile()); + when(paths.getUserThermostatHome()).thenReturn(thermostatUserHome.toFile()); + when(paths.getUserAgentAuthConfigFile()).thenReturn(userAgentAuth.toFile()); + when(paths.getSystemConfigurationDirectory()).thenReturn(sysConfigDir.toFile()); + when(paths.getUserConfigurationDirectory()).thenReturn(userConfigDir.toFile()); + + mockLauncher = mock(Launcher.class); + mockActionEvent = mock(ActionEvent.class); + AbstractStateNotifyingCommand mockStorageCommand = mock(AbstractStateNotifyingCommand.class); + ActionNotifier<ApplicationState> mockNotifier = mock(ActionNotifier.class); + when(mockStorageCommand.getNotifier()).thenReturn(mockNotifier); + mockActionEvent = mock(ActionEvent.class); + when(mockActionEvent.getSource()).thenReturn(mockStorageCommand); + when(mockActionEvent.getPayload()).thenReturn(new String("Test String")); + mockCredentialFinder = mock(CredentialFinder.class); + when(mockCredentialFinder.getConfiguration(WEB_AUTH_FILE)).thenReturn(credentialsFile.toFile()); + when(mockCredentialFinder.getConfiguration(USERS_PROPERTIES)).thenReturn(userPropertiesFile.toFile()); + when(mockCredentialFinder.getConfiguration(ROLES_PROPERTIES)).thenReturn(rolesPropertiesFile.toFile()); + + tSetup = new ThermostatSetupImpl(mockLauncher, paths, new PrintStream(out), mockCredentialFinder) { + @Override + int runMongo() { + //instead of running mongo through ProcessBuilder + //we need to always return 0 for success in tests + return 0; + } + }; + } + + @After + public void teardown() throws IOException { + paths = null; + mockLauncher = null; + + Files.walkFileTree(testRoot, new SimpleFileVisitor<Path>() { + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { + Files.delete(file); + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { + if (exc == null) { + Files.delete(dir); + return FileVisitResult.CONTINUE; + } else { + throw exc; + } + } + }); + } + + @Test + public void testUnlockThermostatUnlockFileCreated() throws IOException { + String fileData; + File setupCompleteFile = new File(thermostatUserHome + "/data/setup-complete.stamp"); + Path setupCompleteFilePath = Paths.get(setupCompleteFile.toString()); + + Files.createDirectories(setupCompleteFilePath.getParent()); + tSetup.unlockThermostat(); + fileData = new String(Files.readAllBytes(setupCompleteFilePath)); + + assertTrue(setupCompleteFile.exists()); + assertTrue(fileData.contains("Temporarily unlocked")); + } + + @Test + public void testSetupMongodbUser() throws IOException { + File userDoneFile = new File(userDataDir.toString() + "/mongodb-user-done.stamp"); + File setupCompleteFile = new File(userDataDir.toString() + "/setup-complete.stamp"); + + doAnswer(new Answer<Void>() { + @Override + public Void answer(InvocationOnMock invocation) throws Throwable { + Object[] args = invocation.getArguments(); + listeners = (Collection<ActionListener<ApplicationState>>) args[1]; + + when(mockActionEvent.getActionId()).thenReturn(ApplicationState.START); + + for (ActionListener<ApplicationState> listener : listeners) { + listener.actionPerformed(mockActionEvent); + } + return null; + } + }).when(mockLauncher).run(eq(STORAGE_START_ARGS), isA(Collection.class), anyBoolean()); + + boolean exTriggered = false; + try { + tSetup.createMongodbUser(username, password.toCharArray()); + } catch (MongodbUserSetupException e) { + exTriggered = true; + } + + assertFalse(exTriggered); + + verify(mockLauncher, times(1)).run(eq(STORAGE_START_ARGS), isA(Collection.class), anyBoolean()); + verify(mockLauncher, times(1)).run(eq(STORAGE_STOP_ARGS), isA(Collection.class), anyBoolean()); + verify(mockActionEvent, times(1)).getActionId(); + + assertTrue(userDoneFile.exists()); + assertTrue(setupCompleteFile.exists()); + String setupCompleteData = new String(Files.readAllBytes(setupCompleteFile.toPath())); + assertTrue(setupCompleteData.contains("Created by Thermostat Setup")); + } + + @Test + public void testStorageStartFail() { + doAnswer(new Answer<Void>() { + @Override + public Void answer(InvocationOnMock invocation) throws Throwable { + Object[] args = invocation.getArguments(); + listeners = (Collection<ActionListener<ApplicationState>>) args[1]; + + when(mockActionEvent.getActionId()).thenReturn(ApplicationState.FAIL); + + for (ActionListener<ApplicationState> listener : listeners) { + listener.actionPerformed(mockActionEvent); + } + return null; + } + }).when(mockLauncher).run(eq(STORAGE_START_ARGS), isA(Collection.class), anyBoolean()); + + try { + tSetup.createMongodbUser(username, password.toCharArray()); + //shouldn't get here + fail(); + } catch (MongodbUserSetupException e) { + assertTrue(e.getMessage().contains("Thermostat storage failed to start")); + } + } + + @Test + public void testStorageStopFail() { + doAnswer(new Answer<Void>() { + @Override + public Void answer(InvocationOnMock invocation) throws Throwable { + Object[] args = invocation.getArguments(); + listeners = (Collection<ActionListener<ApplicationState>>) args[1]; + + when(mockActionEvent.getActionId()).thenReturn(ApplicationState.START); + + for (ActionListener<ApplicationState> listener : listeners) { + listener.actionPerformed(mockActionEvent); + } + return null; + } + }).when(mockLauncher).run(eq(STORAGE_START_ARGS), isA(Collection.class), anyBoolean()); + + doAnswer(new Answer<Void>() { + @Override + public Void answer(InvocationOnMock invocation) throws Throwable { + Object[] args = invocation.getArguments(); + listeners = (Collection<ActionListener<ApplicationState>>) args[1]; + + when(mockActionEvent.getActionId()).thenReturn(ApplicationState.FAIL); + + for (ActionListener<ApplicationState> listener : listeners) { + listener.actionPerformed(mockActionEvent); + } + return null; + } + }).when(mockLauncher).run(eq(STORAGE_STOP_ARGS), isA(Collection.class), anyBoolean()); + + try { + tSetup.createMongodbUser(username, password.toCharArray()); + //shouldn't get here + fail(); + } catch (MongodbUserSetupException e) { + assertTrue(e.getMessage().contains("Thermostat storage failed to stop")); + } + } + + @Test + public void testCreateMongodbUserFail() { + tSetup = new ThermostatSetupImpl(mockLauncher, paths, new PrintStream(out), mockCredentialFinder) { + @Override + int runMongo() { + //return non-zero val to test failure + return 1; + } + }; + + doAnswer(new Answer<Void>() { + @Override + public Void answer(InvocationOnMock invocation) throws Throwable { + Object[] args = invocation.getArguments(); + listeners = (Collection<ActionListener<ApplicationState>>) args[1]; + + when(mockActionEvent.getActionId()).thenReturn(ApplicationState.START); + + for (ActionListener<ApplicationState> listener : listeners) { + listener.actionPerformed(mockActionEvent); + } + return null; + } + }).when(mockLauncher).run(eq(STORAGE_START_ARGS), isA(Collection.class), anyBoolean()); + + try { + tSetup.createMongodbUser(username, password.toCharArray()); + //shouldn't get here + fail(); + } catch (MongodbUserSetupException e) { + assertTrue(e.getMessage().contains("Mongodb user setup failed")); + } + } + + @Test + public void testSetupThermostatUser() throws IOException { + String[] agentRoles = new String[] { + UserRoles.CMD_CHANNEL_VERIFY, + UserRoles.LOGIN, + UserRoles.PREPARE_STATEMENT, + UserRoles.PURGE, + UserRoles.REGISTER_CATEGORY, + UserRoles.ACCESS_REALM, + UserRoles.SAVE_FILE, + UserRoles.WRITE, + UserRoles.GRANT_FILES_WRITE_ALL, + }; + String[] clientRoles = new String[] { + UserRoles.GRANT_AGENTS_READ_ALL, + UserRoles.CMD_CHANNEL_GENERATE, + UserRoles.GRANT_HOSTS_READ_ALL, + UserRoles.LOAD_FILE, + UserRoles.LOGIN, + UserRoles.PREPARE_STATEMENT, + UserRoles.READ, + UserRoles.ACCESS_REALM, + UserRoles.REGISTER_CATEGORY, + UserRoles.GRANT_VMS_READ_BY_USERNAME_ALL, + UserRoles.GRANT_VMS_READ_BY_VM_ID_ALL, + UserRoles.GRANT_FILES_READ_ALL, + UserRoles.WRITE, + }; + + tSetup.createThermostatUser(username, password.toCharArray(), agentRoles); + tSetup.createThermostatUser(username, password.toCharArray(), clientRoles); + + //check credentialsFile + assertTrue(credentialsFile.toFile().exists()); + String credentialsData = new String(Files.readAllBytes(credentialsFile)); + assertTrue(credentialsData.contains("storage.username=" + username)); + assertTrue(credentialsData.contains("storage.password=" + password)); + + //check agent credentials file + assertTrue(userAgentAuth.toFile().exists()); + String userAgentAuthData = new String(Files.readAllBytes(userAgentAuth)); + assertTrue(userAgentAuthData.contains("username=agent-tester")); + assertTrue(userAgentAuthData.contains("password=tester")); + + //check AgentUser file + assertTrue(userPropertiesFile.toFile().exists()); + + //check clientAdmin file + assertTrue(rolesPropertiesFile.toFile().exists()); + } + + @Test + public void testWebAppInstalledSuccess() throws IOException { + Path webAppPath = thermostatSysHome.resolve("webapp"); + Files.createDirectories(webAppPath); + assertTrue(tSetup.isWebAppInstalled()); + } + + @Test + public void testWebAppInstalledFail() throws IOException { + //Call isWebAppInstalled() without creating + //a THERMOSTAT_SYS_HOME/webapp directory + assertFalse(tSetup.isWebAppInstalled()); + } + + @Test + public void testPropertiesWriter() throws IOException { + String key = THERMOSTAT_AGENT; + String[] roles = new String[] { + UserRoles.LOGIN, + UserRoles.PREPARE_STATEMENT, + UserRoles.PURGE, + UserRoles.REGISTER_CATEGORY, + }; + StringBuilder rolesBuilder = new StringBuilder(); + for (int i = 0; i < roles.length - 1; i++) { + rolesBuilder.append(roles[i] + ", " + System.getProperty("line.separator")); + } + rolesBuilder.append(roles[roles.length - 1]); + String value = rolesBuilder.toString(); + + Properties propsToStore = new Properties(); + propsToStore.setProperty(key, value); + FileOutputStream roleStream = new FileOutputStream(rolesPropertiesFile.toFile()); + propsToStore.store(new ThermostatSetupImpl.PropertiesWriter(roleStream), null); + + Properties propsToLoad = new Properties(); + propsToLoad.load(new FileInputStream(rolesPropertiesFile.toFile())); + String[] loadedRoles = propsToLoad.getProperty(key).split(",\\s+"); + + assertTrue(Arrays.asList(roles).containsAll(Arrays.asList(loadedRoles))); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/setup-command/command/src/test/java/com/redhat/thermostat/setup/command/locale/LocaleResourcesTest.java Wed Sep 02 11:26:48 2015 +0200 @@ -0,0 +1,54 @@ +/* + * Copyright 2012-2015 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.setup.command.locale; + +import com.redhat.thermostat.testutils.AbstractLocaleResourcesTest; + +public class LocaleResourcesTest extends AbstractLocaleResourcesTest<LocaleResources> { + + @Override + protected Class<LocaleResources> getEnumClass() { + return LocaleResources.class; + } + + @Override + protected String getResourceBundle() { + return LocaleResources.RESOURCE_BUNDLE; + } + +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/setup-command/distribution/pom.xml Wed Sep 02 11:26:48 2015 +0200 @@ -0,0 +1,96 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + + Copyright 2012-2015 Red Hat, Inc. + + This file is part of Thermostat. + + Thermostat is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + Thermostat is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Thermostat; see the file COPYING. If not see + <http://www.gnu.org/licenses/>. + + Linking this code with other modules is making a combined work + based on this code. Thus, the terms and conditions of the GNU + General Public License cover the whole combination. + + As a special exception, the copyright holders of this code give + you permission to link this code with independent modules to + produce an executable, regardless of the license terms of these + independent modules, and to copy and distribute the resulting + executable under terms of your choice, provided that you also + meet, for each linked independent module, the terms and conditions + of the license of that module. An independent module is a module + which is not derived from or based on this code. If you modify + this code, you may extend this exception to your version of the + library, but you are not obligated to do so. If you do not wish + to do so, delete this exception statement from your version. + +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>com.redhat.thermostat</groupId> + <artifactId>thermostat-setup</artifactId> + <version>1.3.4-SNAPSHOT</version> + </parent> + + <artifactId>thermostat-setup-distribution</artifactId> + <packaging>pom</packaging> + + <name>Thermostat Setup distribution</name> + + <properties> + <thermostat.plugin>setup</thermostat.plugin> + </properties> + + <build> + <plugins> + <plugin> + <artifactId>maven-assembly-plugin</artifactId> + <dependencies> + <dependency> + <groupId>com.redhat.thermostat</groupId> + <artifactId>thermostat-assembly</artifactId> + <version>${project.version}</version> + </dependency> + </dependencies> + <configuration> + <descriptorRefs> + <descriptorRef>plugin-assembly</descriptorRef> + </descriptorRefs> + <appendAssemblyId>false</appendAssemblyId> + </configuration> + <executions> + <execution> + <id>assemble-plugin</id> + <phase>package</phase> + <goals> + <goal>single</goal> + </goals> + </execution> + </executions> + </plugin> + </plugins> + </build> + + <!-- Explicitly list all plug-in artifacts, transitive dependencies + are not included in assembly. --> + <dependencies> + <dependency> + <groupId>com.redhat.thermostat</groupId> + <artifactId>thermostat-setup-command</artifactId> + <version>${project.version}</version> + </dependency> + </dependencies> +</project> +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/setup-command/distribution/thermostat-plugin.xml Wed Sep 02 11:26:48 2015 +0200 @@ -0,0 +1,62 @@ +<?xml version="1.0"?> +<!-- + + Copyright 2012-2015 Red Hat, Inc. + + This file is part of Thermostat. + + Thermostat is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + Thermostat is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Thermostat; see the file COPYING. If not see + <http://www.gnu.org/licenses/>. + + Linking this code with other modules is making a combined work + based on this code. Thus, the terms and conditions of the GNU + General Public License cover the whole combination. + + As a special exception, the copyright holders of this code give + you permission to link this code with independent modules to + produce an executable, regardless of the license terms of these + independent modules, and to copy and distribute the resulting + executable under terms of your choice, provided that you also + meet, for each linked independent module, the terms and conditions + of the license of that module. An independent module is a module + which is not derived from or based on this code. If you modify + this code, you may extend this exception to your version of the + library, but you are not obligated to do so. If you do not wish + to do so, delete this exception statement from your version. + +--> +<plugin xmlns="http://icedtea.classpath.org/thermostat/plugins/v1.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://icedtea.classpath.org/thermostat/plugins/v1.0 thermostat-plugin.xsd"> + <commands> + <command> + <name>setup</name> + <summary>setup thermostat for first run</summary> + <description>setup an initial mongodb user and webapp settings. Optionally create a client admin and agent user.</description> + <environments> + <environment>cli</environment> + <environment>shell</environment> + </environments> + <bundles> + <bundle><symbolic-name>com.redhat.thermostat.setup.command</symbolic-name><version>${project.version}</version></bundle> + <bundle><symbolic-name>com.redhat.thermostat.common.core</symbolic-name><version>${project.version}</version></bundle> + <bundle><symbolic-name>com.redhat.thermostat.configuration</symbolic-name><version>${project.version}</version></bundle> + <bundle><symbolic-name>com.redhat.thermostat.client.swing</symbolic-name><version>${project.version}</version></bundle> + <bundle><symbolic-name>com.redhat.thermostat.client.core</symbolic-name><version>${project.version}</version></bundle> + <bundle><symbolic-name>com.redhat.thermostat.internal.utils.laf</symbolic-name><version>${project.version}</version></bundle> + <bundle><symbolic-name>com.redhat.thermostat.plugin.validator</symbolic-name><version>${project.version}</version></bundle> + </bundles> + </command> + </commands> +</plugin> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/setup-command/pom.xml Wed Sep 02 11:26:48 2015 +0200 @@ -0,0 +1,58 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + + Copyright 2012-2015 Red Hat, Inc. + + This file is part of Thermostat. + + Thermostat is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + Thermostat is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Thermostat; see the file COPYING. If not see + <http://www.gnu.org/licenses/>. + + Linking this code with other modules is making a combined work + based on this code. Thus, the terms and conditions of the GNU + General Public License cover the whole combination. + + As a special exception, the copyright holders of this code give + you permission to link this code with independent modules to + produce an executable, regardless of the license terms of these + independent modules, and to copy and distribute the resulting + executable under terms of your choice, provided that you also + meet, for each linked independent module, the terms and conditions + of the license of that module. An independent module is a module + which is not derived from or based on this code. If you modify + this code, you may extend this exception to your version of the + library, but you are not obligated to do so. If you do not wish + to do so, delete this exception statement from your version. + +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>com.redhat.thermostat</groupId> + <artifactId>thermostat</artifactId> + <version>1.3.4-SNAPSHOT</version> + </parent> + <artifactId>thermostat-setup</artifactId> + <packaging>pom</packaging> + + <name>Thermostat Setup command</name> + + <description>Initial Setup for thermostat</description> + + <modules> + <module>command</module> + <module>distribution</module> + </modules> +</project> +