package de.bitocean.zkrc; /** * * Based on the data stored in ZNode this program starts and * stops executables. A DataMonitor is used. * * The program watches the specified znode and saves the data that * corresponds to the znode in the filesystem. It also starts the * specified program with the specified arguments when the znode * exists and kills the program if the znode goes away. * * Adding or deleting a ZNode triggers activity on the remote nodes, which * watch out for this ZNode. * */ import de.bitocean.zkrc.DataMonitor; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import org.apache.zookeeper.KeeperException; import org.apache.zookeeper.WatchedEvent; import org.apache.zookeeper.Watcher; import org.apache.zookeeper.ZooKeeper; public class Executor implements Watcher, Runnable, DataMonitor.DataMonitorListener { static Executor getExecutor(String[] args) { Executor ex = null; if (args.length < 4) { System.err .println("USAGE: Executor hostPort znode filename program [args ...]"); System.exit(2); } String hostPort = args[0]; String znode = args[1]; String filename = args[2]; String clientID = args[3]; String exec[] = new String[args.length - 4]; System.arraycopy(args, 4, exec, 0, exec.length); try { for( String e : exec ) { System.out.println( e ); } ex = new Executor( hostPort, znode, filename, exec, clientID ); } catch (Exception e) { e.printStackTrace(); } return ex; } // the ZNode we are watching for String znode; // a DataMonitor dm; ZooKeeper zk; String filename; public String exec[]; Process child; public Executor(String hostPort, String znode, String filename, String exec[], String clientID) throws KeeperException, IOException { this.filename = filename; this.exec = exec; zk = new ZooKeeper(hostPort, 3000, this); dm = new DataMonitor(clientID, zk, znode, null, this ); System.out.println(">>> Executor was started ... clientID="+clientID); } /** * @param args */ public static void main(String[] args) { Executor exec = Executor.getExecutor(args); exec.run(); } public static void stop() { System.out.println(">>> ZooView will be closed soon ... ***~~~ Have a nice day ~~~***"); } /*************************************************************************** * We do process any events ourselves, we just need to forward them on. * * @see org.apache.zookeeper.Watcher#process(org.apache.zookeeper.proto.WatcherEvent) */ public void process(WatchedEvent event) { dm.process(event); } public void run() { try { synchronized (this) { while (!dm.dead) { wait(); } } } catch (InterruptedException e) { } } public void closing(int rc) { synchronized (this) { notifyAll(); } } @Override public void setCMD(String data) { int lastEntry = exec.length-1; exec[ lastEntry ] = "-Dcmd="+data; } static class StreamWriter extends Thread { OutputStream os; InputStream is; StreamWriter(InputStream is, OutputStream os) { this.is = is; this.os = os; start(); } public void run() { byte b[] = new byte[80]; int rc; try { while ((rc = is.read(b)) > 0) { os.write(b, 0, rc); } } catch (IOException e) { } } } public void exists(byte[] data) { if (data == null) { if (child != null) { System.out.println("Killing process"); child.destroy(); try { child.waitFor(); } catch (InterruptedException e) { } } child = null; } else { if (child != null) { System.out.println("Stopping child"); child.destroy(); try { child.waitFor(); } catch (InterruptedException e) { e.printStackTrace(); } } try { FileOutputStream fos = new FileOutputStream(filename); fos.write(data); fos.close(); } catch (IOException e) { e.printStackTrace(); } try { System.out.println("Starting child"); child = Runtime.getRuntime().exec(exec); new StreamWriter(child.getInputStream(), System.out); new StreamWriter(child.getErrorStream(), System.err); } catch (IOException e) { e.printStackTrace(); } } } }