aboutsummaryrefslogtreecommitdiff
path: root/subsonic-booter/src/main/java/net/sourceforge/subsonic/booter/agent/SubsonicAgent.java
diff options
context:
space:
mode:
Diffstat (limited to 'subsonic-booter/src/main/java/net/sourceforge/subsonic/booter/agent/SubsonicAgent.java')
-rw-r--r--subsonic-booter/src/main/java/net/sourceforge/subsonic/booter/agent/SubsonicAgent.java201
1 files changed, 201 insertions, 0 deletions
diff --git a/subsonic-booter/src/main/java/net/sourceforge/subsonic/booter/agent/SubsonicAgent.java b/subsonic-booter/src/main/java/net/sourceforge/subsonic/booter/agent/SubsonicAgent.java
new file mode 100644
index 00000000..a9bb526e
--- /dev/null
+++ b/subsonic-booter/src/main/java/net/sourceforge/subsonic/booter/agent/SubsonicAgent.java
@@ -0,0 +1,201 @@
+package net.sourceforge.subsonic.booter.agent;
+
+import java.awt.Desktop;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+import javax.swing.JOptionPane;
+import javax.swing.UIManager;
+
+import org.apache.commons.io.IOUtils;
+
+import com.jgoodies.looks.plastic.PlasticXPLookAndFeel;
+
+import net.sourceforge.subsonic.booter.deployer.DeploymentStatus;
+import net.sourceforge.subsonic.booter.deployer.SubsonicDeployerService;
+
+/**
+ * Responsible for deploying the Subsonic web app in
+ * the embedded Jetty container.
+ *
+ * @author Sindre Mehus
+ */
+public class SubsonicAgent {
+
+ private final List<SubsonicListener> listeners = new ArrayList<SubsonicListener>();
+ private final TrayController trayController;
+ private SubsonicFrame frame;
+ private final SubsonicDeployerService service;
+ private static final int POLL_INTERVAL_DEPLOYMENT_INFO_SECONDS = 5;
+ private static final int POLL_INTERVAL_SERVICE_STATUS_SECONDS = 5;
+ private String url;
+ private boolean serviceStatusPollingEnabled;
+ private boolean elevated;
+
+ public SubsonicAgent(SubsonicDeployerService service) {
+ this.service = service;
+ setLookAndFeel();
+ trayController = new TrayController(this);
+ startPolling();
+ }
+
+ public void setFrame(SubsonicFrame frame) {
+ this.frame = frame;
+ }
+
+ private void setLookAndFeel() {
+ // Set look-and-feel.
+ try {
+ UIManager.setLookAndFeel(new PlasticXPLookAndFeel());
+ } catch (Throwable x) {
+ System.err.println("Failed to set look-and-feel.\n" + x);
+ }
+ }
+
+ private void startPolling() {
+ ScheduledExecutorService executor = Executors.newScheduledThreadPool(2);
+ Runnable runnable = new Runnable() {
+ public void run() {
+ try {
+ notifyDeploymentInfo(service.getDeploymentInfo());
+ } catch (Throwable x) {
+ notifyDeploymentInfo(null);
+ }
+ }
+ };
+ executor.scheduleWithFixedDelay(runnable, 0, POLL_INTERVAL_DEPLOYMENT_INFO_SECONDS, TimeUnit.SECONDS);
+
+ runnable = new Runnable() {
+ public void run() {
+ if (serviceStatusPollingEnabled) {
+ try {
+ notifyServiceStatus(getServiceStatus());
+ } catch (Throwable x) {
+ notifyServiceStatus(null);
+ }
+ }
+ }
+ };
+ executor.scheduleWithFixedDelay(runnable, 0, POLL_INTERVAL_SERVICE_STATUS_SECONDS, TimeUnit.SECONDS);
+ }
+
+ private String getServiceStatus() throws Exception {
+ Process process = Runtime.getRuntime().exec("subsonic-service.exe -status");
+ return IOUtils.toString(process.getInputStream());
+ }
+
+ public void setServiceStatusPollingEnabled(boolean enabled) {
+ serviceStatusPollingEnabled = enabled;
+ }
+
+ public void startOrStopService(boolean start) {
+ try {
+ String cmd = "subsonic-service.exe " + (start ? "-start" : "-stop");
+ System.err.println("Executing: " + cmd);
+
+ Runtime.getRuntime().exec(cmd);
+ } catch (Exception x) {
+ x.printStackTrace();
+ }
+ }
+
+ /**
+ * If necessary, restart agent with elevated rights.
+ */
+ public void checkElevation(String... args) {
+
+ if (isElevationNeeded() && !isElevated()) {
+ try {
+ List<String> command = new ArrayList<String>();
+ command.add("cmd");
+ command.add("/c");
+ command.add("subsonic-agent-elevated.exe");
+ command.addAll(Arrays.asList(args));
+
+ ProcessBuilder builder = new ProcessBuilder();
+ builder.command(command);
+ System.err.println("Executing: " + command + " with current dir: " + System.getProperty("user.dir"));
+ builder.start();
+ System.exit(0);
+ } catch (Exception x) {
+ JOptionPane.showMessageDialog(frame, "Failed to elevate Subsonic Control Panel. " + x, "Error", JOptionPane.WARNING_MESSAGE);
+ x.printStackTrace();
+ }
+ }
+ }
+
+ public void setElevated(boolean elevated) {
+ this.elevated = elevated;
+ }
+
+ private boolean isElevated() {
+ return elevated;
+ }
+
+ /**
+ * Returns whether UAC elevation is necessary (to start/stop services etc).
+ */
+ private boolean isElevationNeeded() {
+
+ String osVersion = System.getProperty("os.version");
+ try {
+ int majorVersion = Integer.parseInt(osVersion.substring(0, osVersion.indexOf(".")));
+
+ // Elevation is necessary in Windows Vista (os.version=6.1) and later.
+ return majorVersion >= 6;
+ } catch (Exception x) {
+ System.err.println("Failed to resolve OS version from '" + osVersion + "'\n" + x);
+ return false;
+ }
+ }
+
+ public void addListener(SubsonicListener listener) {
+ listeners.add(listener);
+ }
+
+ private void notifyDeploymentInfo(DeploymentStatus status) {
+ if (status != null) {
+ url = status.getURL();
+ }
+
+ for (SubsonicListener listener : listeners) {
+ listener.notifyDeploymentStatus(status);
+ }
+ }
+
+ private void notifyServiceStatus(String status) {
+ for (SubsonicListener listener : listeners) {
+ listener.notifyServiceStatus(status);
+ }
+ }
+
+ public void showStatusPanel() {
+ frame.showStatusPanel();
+ }
+
+ public void showSettingsPanel() {
+ frame.showSettingsPanel();
+ }
+
+ public void showTrayIconMessage() {
+ trayController.showMessage();
+ }
+
+ public void exit() {
+ trayController.uninstallComponents();
+ System.exit(0);
+ }
+
+ public void openBrowser() {
+ try {
+ Desktop.getDesktop().browse(new URI(url));
+ } catch (Throwable x) {
+ x.printStackTrace();
+ }
+ }
+}