<packaging>jar</packaging>
<name>/monitor</name>
<dependencies>
+ <dependency>
+ <groupId>org.wamblee</groupId>
+ <artifactId>wamblee-support-general</artifactId>
+ </dependency>
<dependency>
<groupId>org.teleal.cling</groupId>
<artifactId>cling-core</artifactId>
--- /dev/null
+package org.wamblee.upnpmonitor;
+
+import java.util.Properties;
+
+public class Config {
+
+ public static final String INTERVAL_SECONDS = "org.wamblee.upnpmonitor.intervalSeconds";
+ public static final String STARTUP_COMMAND = "org.wamblee.upnpmonitor.startupCommand";
+ public static final String SHUTDOWN_COMMAND = "org.wamblee.upnpmonitor.shutdownCommand";
+ public static final String PATTERN = "org.wamblee.upnpmonitor.pattern";
+
+ private int intervalSeconds;
+ private String startupCommand;
+ private String shutdownCommand;
+ private String pattern;
+
+ public static Config parse(Properties aProperties) {
+ return new Config(Integer.parseInt(aProperties.getProperty(
+ INTERVAL_SECONDS, "30")), aProperties.getProperty(STARTUP_COMMAND),
+ aProperties.getProperty(SHUTDOWN_COMMAND),
+ aProperties.getProperty(PATTERN));
+ }
+
+ public Config(int aIntervalSeconds, String aStartupCommand,
+ String aShutdownCommand, String aPattern) {
+ intervalSeconds = aIntervalSeconds;
+ startupCommand = aStartupCommand;
+ shutdownCommand = aShutdownCommand;
+ pattern = aPattern;
+ }
+
+ public int getIntervalSeconds() {
+ return intervalSeconds;
+ }
+
+ public String getStartupCommand() {
+ return startupCommand;
+ }
+
+ public String getShutdownCommand() {
+ return shutdownCommand;
+ }
+
+ public String getPattern() {
+ return pattern;
+ }
+}
import java.util.logging.Logger;
-import org.teleal.cling.UpnpService;
-import org.teleal.cling.UpnpServiceImpl;
-import org.teleal.cling.controlpoint.ControlPoint;
-import org.teleal.cling.model.message.header.DeviceTypeHeader;
-import org.teleal.cling.model.meta.Device;
-import org.teleal.cling.model.types.DeviceType;
-import org.teleal.cling.registry.DefaultRegistryListener;
-import org.teleal.cling.registry.Registry;
-import org.teleal.cling.registry.RegistryListener;
-
public class Main {
private static final Logger LOGGER = Logger.getLogger(Main.class.getName());
- public static class UpnpStack {
- private UpnpService upnpService;
- private ControlPoint controlPoint;
- private DeviceType deviceType;
-
- public UpnpStack() {
- RegistryListener listener = new DefaultRegistryListener() {
- @Override
- public void deviceAdded(Registry aRegistry, Device aDevice) {
- super.deviceAdded(aRegistry, aDevice);
- System.out.println("Device added: " +
- aDevice.getDisplayString());
- System.out.println(aDevice.getType());
- }
-
- @Override
- public void deviceRemoved(Registry aRegistry, Device aDevice) {
- super.deviceRemoved(aRegistry, aDevice);
- System.out.println("Device removed: " +
- aDevice.getDisplayString());
- }
- };
- upnpService = new UpnpServiceImpl(listener);
- controlPoint = upnpService.getControlPoint();
- deviceType = new DeviceType("schemas-upnp-org", "MediaServer");
-
- }
-
- public void search() {
- controlPoint.search(new DeviceTypeHeader(deviceType));
- }
+ public static void main(String[] aArgs) throws Exception {
- public void shutdown() {
- upnpService.shutdown();
- }
- }
+ Config config = new Config(30, "echo starting", "echo stopping",
+ "mediatomb");
- public static void main(String[] aArgs) throws Exception {
+ final Monitor monitor = new Monitor(config);
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
- System.out.println("Shutdown hook");
+ System.out.println("Signal caught, terminating monitor");
+ monitor.stop();
}
});
- for (;;) {
- UpnpStack stack = new UpnpStack();
- stack.search();
- Thread.sleep(10000);
- stack.shutdown();
-
- }
-
+ monitor.start();
}
}
--- /dev/null
+package org.wamblee.upnpmonitor;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.concurrent.ScheduledThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.wamblee.io.SimpleProcess;
+
+public class Monitor implements Runnable {
+
+ private static final Logger LOGGER = Logger.getLogger(Monitor.class
+ .getName());
+
+ private ScheduledThreadPoolExecutor executor;
+ private Config config;
+ private boolean serviceFound;
+ private UpnpStack stack;
+
+ public Monitor(Config aConfig) {
+ config = aConfig;
+ executor = new ScheduledThreadPoolExecutor(1);
+ }
+
+ public void start() {
+ serviceFound = true;
+ executor.scheduleWithFixedDelay(this, 0, config.getIntervalSeconds(),
+ TimeUnit.SECONDS);
+ executeCommand(config.getStartupCommand());
+ }
+
+ public synchronized void setServiceFound(boolean aServiceFound) {
+ serviceFound = aServiceFound;
+ }
+
+ public synchronized void run() {
+
+ if (!serviceFound) {
+ LOGGER.info("UPNP service is down, executing recovery");
+ // we need to execute recovery.
+ executeCommand(config.getShutdownCommand());
+ executeCommand(config.getStartupCommand());
+ setServiceFound(true);
+ // give process a chance to startup.
+ return;
+ }
+
+ shutdownStack();
+
+ setServiceFound(false);
+
+ stack = new UpnpStack(new UpnpStack.Listener() {
+ @Override
+ public void deviceAdded(String aDeviceString) {
+ LOGGER.fine("Device added: " + aDeviceString);
+ if (aDeviceString.toLowerCase().contains(
+ config.getPattern().toLowerCase())) {
+ synchronized (Monitor.this) {
+ setServiceFound(true);
+ }
+ }
+ }
+
+ @Override
+ public void deviceRemoved(String aDeviceString) {
+ LOGGER.fine("Device removed:" + aDeviceString);
+ }
+ });
+ stack.search();
+ }
+
+ private void shutdownStack() {
+ if (stack != null) {
+ stack.shutdown();
+ stack = null;
+ }
+ }
+
+ private void executeCommand(String command) {
+ LOGGER.info("Executing command: " + command);
+ SimpleProcess process = new SimpleProcess(new File("."), new String[] {
+ "sh", "-c", command });
+
+ try {
+ int ret = process.run();
+ LOGGER.info(process.getStdout());
+ LOGGER.info(process.getStderr());
+ LOGGER.info("Exit status: " + ret);
+ } catch (IOException e) {
+ LOGGER.log(Level.INFO, "Problem executing command", e);
+ }
+ }
+
+ public void stop() {
+ executor.shutdown();
+ shutdownStack();
+ executeCommand(config.getShutdownCommand());
+ }
+}
--- /dev/null
+package org.wamblee.upnpmonitor;
+
+import org.teleal.cling.UpnpService;
+import org.teleal.cling.UpnpServiceImpl;
+import org.teleal.cling.controlpoint.ControlPoint;
+import org.teleal.cling.model.message.header.DeviceTypeHeader;
+import org.teleal.cling.model.meta.Device;
+import org.teleal.cling.model.types.DeviceType;
+import org.teleal.cling.registry.DefaultRegistryListener;
+import org.teleal.cling.registry.Registry;
+import org.teleal.cling.registry.RegistryListener;
+
+public class UpnpStack {
+
+ public static interface Listener {
+
+ void deviceAdded(String aDeviceString);
+
+ void deviceRemoved(String aDeviceString);
+ }
+
+ private UpnpService upnpService;
+ private ControlPoint controlPoint;
+ private DeviceType deviceType;
+
+ public UpnpStack(final Listener aListener) {
+ RegistryListener listener = new DefaultRegistryListener() {
+ @Override
+ public void deviceAdded(Registry aRegistry, Device aDevice) {
+ super.deviceAdded(aRegistry, aDevice);
+ aListener.deviceAdded(aDevice.getDisplayString());
+ }
+
+ @Override
+ public void deviceRemoved(Registry aRegistry, Device aDevice) {
+ super.deviceRemoved(aRegistry, aDevice);
+ aListener.deviceRemoved(aDevice.getDisplayString());
+ }
+ };
+ upnpService = new UpnpServiceImpl(listener);
+ controlPoint = upnpService.getControlPoint();
+ deviceType = new DeviceType("schemas-upnp-org", "MediaServer");
+
+ }
+
+ public void search() {
+ controlPoint.search(new DeviceTypeHeader(deviceType));
+ }
+
+ public void shutdown() {
+ upnpService.shutdown();
+ }
+}
\ No newline at end of file
<dependencyManagement>
<dependencies>
<dependency>
+ <groupId>org.wamblee</groupId>
+ <artifactId>wamblee-support-general</artifactId>
+ <version>0.7</version>
+ </dependency>
+ <dependency>
<groupId>org.teleal.cling</groupId>
<artifactId>cling-core</artifactId>
<version>1.0.5</version>