You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
375 lines
13 KiB
375 lines
13 KiB
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();
|
|
}
|
|
}
|
|
}
|
|
|