aboutsummaryrefslogtreecommitdiff
path: root/subsonic-booter/src/main/java/net/sourceforge/subsonic/booter/agent/SettingsPanel.java
diff options
context:
space:
mode:
Diffstat (limited to 'subsonic-booter/src/main/java/net/sourceforge/subsonic/booter/agent/SettingsPanel.java')
-rw-r--r--subsonic-booter/src/main/java/net/sourceforge/subsonic/booter/agent/SettingsPanel.java375
1 files changed, 375 insertions, 0 deletions
diff --git a/subsonic-booter/src/main/java/net/sourceforge/subsonic/booter/agent/SettingsPanel.java b/subsonic-booter/src/main/java/net/sourceforge/subsonic/booter/agent/SettingsPanel.java
new file mode 100644
index 00000000..c225410f
--- /dev/null
+++ b/subsonic-booter/src/main/java/net/sourceforge/subsonic/booter/agent/SettingsPanel.java
@@ -0,0 +1,375 @@
+package net.sourceforge.subsonic.booter.agent;
+
+import com.jgoodies.forms.builder.DefaultFormBuilder;
+import com.jgoodies.forms.factories.Borders;
+import com.jgoodies.forms.factories.ButtonBarFactory;
+import com.jgoodies.forms.layout.FormLayout;
+import net.sourceforge.subsonic.booter.deployer.DeploymentStatus;
+import net.sourceforge.subsonic.booter.deployer.SubsonicDeployer;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.Reader;
+import java.io.Writer;
+import java.text.DecimalFormat;
+import java.text.DecimalFormatSymbols;
+import java.text.Format;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Panel displaying the settings of the Subsonic service.
+ *
+ * @author Sindre Mehus
+ */
+public class SettingsPanel extends JPanel implements SubsonicListener {
+
+ private static final Format INTEGER_FORMAT = new DecimalFormat("0", DecimalFormatSymbols.getInstance(Locale.UK));
+
+ private final SubsonicAgent subsonicAgent;
+ private JFormattedTextField portTextField;
+ private JCheckBox httpsPortCheckBox;
+ private JFormattedTextField httpsPortTextField;
+ private JComboBox contextPathComboBox;
+ private JFormattedTextField memoryTextField;
+ private JButton defaultButton;
+ private JButton saveButton;
+ public SettingsPanel(SubsonicAgent subsonicAgent) {
+ this.subsonicAgent = subsonicAgent;
+ createComponents();
+ configureComponents();
+ layoutComponents();
+ addBehaviour();
+ readValues();
+ subsonicAgent.addListener(this);
+ }
+
+ public void readValues() {
+ portTextField.setValue(getPortFromOptionsFile());
+ memoryTextField.setValue(getMemoryLimitFromOptionsFile());
+ contextPathComboBox.setSelectedItem(getContextPathFromOptionsFile());
+ int httpsPort = getHttpsPortFromOptionsFile();
+ boolean httpsEnabled = httpsPort != 0;
+ httpsPortTextField.setValue(httpsEnabled ? httpsPort : 4443);
+ httpsPortTextField.setEnabled(httpsEnabled);
+ httpsPortCheckBox.setSelected(httpsEnabled);
+ }
+
+ private int getHttpsPortFromOptionsFile() {
+ try {
+ String s = grep("-Dsubsonic.httpsPort=(\\d+)");
+ return Integer.parseInt(s);
+ } catch (Exception x) {
+ x.printStackTrace();
+ return SubsonicDeployer.DEFAULT_HTTPS_PORT;
+ }
+ }
+
+ private int getPortFromOptionsFile() {
+ try {
+ String s = grep("-Dsubsonic.port=(\\d+)");
+ return Integer.parseInt(s);
+ } catch (Exception x) {
+ x.printStackTrace();
+ return SubsonicDeployer.DEFAULT_PORT;
+ }
+ }
+
+ private int getMemoryLimitFromOptionsFile() {
+ try {
+ String s = grep("-Xmx(\\d+)m");
+ return Integer.parseInt(s);
+ } catch (Exception x) {
+ x.printStackTrace();
+ return SubsonicDeployer.DEFAULT_MEMORY_LIMIT;
+ }
+ }
+
+ private String getContextPathFromOptionsFile() {
+ try {
+ String s = grep("-Dsubsonic.contextPath=(.*)");
+ if (s == null) {
+ throw new NullPointerException();
+ }
+ return s;
+ } catch (Exception x) {
+ x.printStackTrace();
+ return SubsonicDeployer.DEFAULT_CONTEXT_PATH;
+ }
+ }
+
+ private void createComponents() {
+ portTextField = new JFormattedTextField(INTEGER_FORMAT);
+ httpsPortTextField = new JFormattedTextField(INTEGER_FORMAT);
+ httpsPortCheckBox = new JCheckBox("Enable https on port");
+ contextPathComboBox = new JComboBox();
+ memoryTextField = new JFormattedTextField(INTEGER_FORMAT);
+ defaultButton = new JButton("Restore defaults");
+ saveButton = new JButton("Save settings");
+ }
+
+ private void configureComponents() {
+ contextPathComboBox.setEditable(true);
+ contextPathComboBox.addItem("/");
+ contextPathComboBox.addItem("/subsonic");
+ contextPathComboBox.addItem("/music");
+ }
+
+ private void layoutComponents() {
+ FormLayout layout = new FormLayout("d, 6dlu, max(d;30dlu):grow");
+ DefaultFormBuilder builder = new DefaultFormBuilder(layout);
+ builder.append("Port number", portTextField);
+ builder.append(httpsPortCheckBox, httpsPortTextField);
+ builder.append("Memory limit (MB)", memoryTextField);
+ builder.append("Context path", contextPathComboBox);
+
+ setBorder(Borders.DIALOG_BORDER);
+
+ setLayout(new BorderLayout(12, 12));
+ add(builder.getPanel(), BorderLayout.CENTER);
+ add(ButtonBarFactory.buildCenteredBar(defaultButton, saveButton), BorderLayout.SOUTH);
+ }
+
+ private void addBehaviour() {
+ saveButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ try {
+ subsonicAgent.checkElevation("-settings", getMemoryLimit() + "," + getPort() + "," + getHttpsPort() + "," + getContextPath());
+ saveSettings(getMemoryLimit(), getPort(), getHttpsPort(), getContextPath());
+ } catch (Exception x) {
+ JOptionPane.showMessageDialog(SettingsPanel.this, x.getMessage(), "Error", JOptionPane.WARNING_MESSAGE);
+ }
+ }
+ });
+
+ defaultButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ portTextField.setValue(SubsonicDeployer.DEFAULT_PORT);
+ httpsPortTextField.setValue(4443);
+ httpsPortTextField.setEnabled(false);
+ httpsPortCheckBox.setSelected(false);
+ memoryTextField.setValue(SubsonicDeployer.DEFAULT_MEMORY_LIMIT);
+ contextPathComboBox.setSelectedItem(SubsonicDeployer.DEFAULT_CONTEXT_PATH);
+ }
+ });
+
+ httpsPortCheckBox.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ httpsPortTextField.setEnabled(httpsPortCheckBox.isSelected());
+ }
+ });
+ }
+
+ private String getContextPath() throws SettingsException {
+ String contextPath = (String) contextPathComboBox.getSelectedItem();
+ if (contextPath.contains(" ") || !contextPath.startsWith("/")) {
+ throw new SettingsException("Please specify a valid context path.");
+ }
+ return contextPath;
+ }
+
+ private int getMemoryLimit() throws SettingsException {
+ int memoryLimit;
+ try {
+ memoryLimit = ((Number) memoryTextField.getValue()).intValue();
+ if (memoryLimit < 5) {
+ throw new Exception();
+ }
+ } catch (Exception x) {
+ throw new SettingsException("Please specify a valid memory limit.", x);
+ }
+ return memoryLimit;
+ }
+
+ private int getPort() throws SettingsException {
+ int port;
+ try {
+ port = ((Number) portTextField.getValue()).intValue();
+ if (port < 1 || port > 65535) {
+ throw new Exception();
+ }
+ } catch (Exception x) {
+ throw new SettingsException("Please specify a valid port number.", x);
+ }
+ return port;
+ }
+
+ private int getHttpsPort() throws SettingsException {
+ if (!httpsPortCheckBox.isSelected()) {
+ return 0;
+ }
+
+ int port;
+ try {
+ port = ((Number) httpsPortTextField.getValue()).intValue();
+ if (port < 1 || port > 65535) {
+ throw new Exception();
+ }
+ } catch (Exception x) {
+ throw new SettingsException("Please specify a valid https port number.", x);
+ }
+ return port;
+ }
+
+ public void saveSettings(int memoryLimit, int port, int httpsPort, String contextPath) throws SettingsException {
+ File file = getOptionsFile();
+
+ java.util.List<String> lines = readLines(file);
+ java.util.List<String> newLines = new ArrayList<String>();
+
+ boolean memoryLimitAdded = false;
+ boolean portAdded = false;
+ boolean httpsPortAdded = false;
+ boolean contextPathAdded = false;
+
+ for (String line : lines) {
+ if (line.startsWith("-Xmx")) {
+ newLines.add("-Xmx" + memoryLimit + "m");
+ memoryLimitAdded = true;
+ } else if (line.startsWith("-Dsubsonic.port=")) {
+ newLines.add("-Dsubsonic.port=" + port);
+ portAdded = true;
+ } else if (line.startsWith("-Dsubsonic.httpsPort=")) {
+ newLines.add("-Dsubsonic.httpsPort=" + httpsPort);
+ httpsPortAdded = true;
+ } else if (line.startsWith("-Dsubsonic.contextPath=")) {
+ newLines.add("-Dsubsonic.contextPath=" + contextPath);
+ contextPathAdded = true;
+ } else {
+ newLines.add(line);
+ }
+ }
+
+ if (!memoryLimitAdded) {
+ newLines.add("-Xmx" + memoryLimit + "m");
+ }
+ if (!portAdded) {
+ newLines.add("-Dsubsonic.port=" + port);
+ }
+ if (!httpsPortAdded) {
+ newLines.add("-Dsubsonic.httpsPort=" + httpsPort);
+ }
+ if (!contextPathAdded) {
+ newLines.add("-Dsubsonic.contextPath=" + contextPath);
+ }
+
+ writeLines(file, newLines);
+
+ JOptionPane.showMessageDialog(SettingsPanel.this,
+ "Please restart Subsonic for the new settings to take effect.",
+ "Settings changed", JOptionPane.INFORMATION_MESSAGE);
+
+ }
+
+ private File getOptionsFile() throws SettingsException {
+ File file = new File("subsonic-service.exe.vmoptions");
+ if (!file.isFile() || !file.exists()) {
+ throw new SettingsException("File " + file.getAbsolutePath() + " not found.");
+ }
+ return file;
+ }
+
+ private List<String> readLines(File file) throws SettingsException {
+ List<String> lines = new ArrayList<String>();
+ BufferedReader reader = null;
+ try {
+ reader = new BufferedReader(new FileReader(file));
+ for (String line = reader.readLine(); line != null; line = reader.readLine()) {
+ lines.add(line);
+ }
+ return lines;
+ } catch (IOException x) {
+ throw new SettingsException("Failed to read from file " + file.getAbsolutePath(), x);
+ } finally {
+ closeQuietly(reader);
+ }
+ }
+
+ private void writeLines(File file, List<String> lines) throws SettingsException {
+ PrintWriter writer = null;
+ try {
+ writer = new PrintWriter(new FileWriter(file));
+ for (String line : lines) {
+ writer.println(line);
+ }
+ } catch (IOException x) {
+ throw new SettingsException("Failed to write to file " + file.getAbsolutePath(), x);
+ } finally {
+ closeQuietly(writer);
+ }
+ }
+
+ private String grep(String regexp) throws SettingsException {
+ Pattern pattern = Pattern.compile(regexp);
+ File file = getOptionsFile();
+ for (String line : readLines(file)) {
+ Matcher matcher = pattern.matcher(line);
+ if (matcher.matches()) {
+ return matcher.group(1);
+ }
+ }
+ return null;
+ }
+
+ private void closeQuietly(Reader reader) {
+ if (reader == null) {
+ return;
+ }
+
+ try {
+ reader.close();
+ } catch (IOException x) {
+ // Intentionally ignored.
+ }
+ }
+
+ private void closeQuietly(Writer writer) {
+ if (writer == null) {
+ return;
+ }
+
+ try {
+ writer.close();
+ } catch (IOException x) {
+ // Intentionally ignored.
+ }
+ }
+
+ public void notifyDeploymentStatus(DeploymentStatus deploymentStatus) {
+ // Nothing here yet.
+ }
+
+ public void notifyServiceStatus(String serviceStatus) {
+ // Nothing here yet.
+ }
+
+ public static class SettingsException extends Exception {
+
+ public SettingsException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public SettingsException(String message) {
+ this(message, null);
+ }
+
+ @Override
+ public String getMessage() {
+ if (getCause() == null || getCause().getMessage() == null) {
+ return super.getMessage();
+ }
+ return super.getMessage() + " " + getCause().getMessage();
+ }
+ }
+}