package de.bitocean.zkrc; /** * * A monitor which monitors data and existence in a ZooKeeper * node. It works with the asynchronous ZooKeeper APIs. * */ import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.logging.Level; import java.util.logging.Logger; import org.apache.zookeeper.KeeperException; import org.apache.zookeeper.WatchedEvent; import org.apache.zookeeper.Watcher; import org.apache.zookeeper.ZooKeeper; import org.apache.zookeeper.AsyncCallback.StatCallback; import org.apache.zookeeper.CreateMode; import org.apache.zookeeper.KeeperException.Code; import org.apache.zookeeper.ZooDefs.Ids; import org.apache.zookeeper.data.ACL; import org.apache.zookeeper.data.Stat; public class DataMonitor implements Watcher, StatCallback { protected static final ArrayList<ACL> NO_ACL = Ids.OPEN_ACL_UNSAFE; String clientID = "DEMO"; ZooKeeper zk; String znode; Watcher chainedWatcher; boolean dead; DataMonitorListener listener; byte prevData[]; public DataMonitor(String clientID, ZooKeeper zk, String znode, Watcher chainedWatcher, DataMonitorListener listener) { this.clientID = clientID; this.zk = zk; this.znode = znode; this.chainedWatcher = chainedWatcher; this.listener = listener; // sayHallo to the server sayHallo(); // Get things started by checking if the node exists. We are going // to be completely event driven zk.exists(znode, true, this, null); } private void sayHallo() { try { Date date = new Date( System.currentTimeMillis() ); boolean isNew = false; try { zk.create(znode+"/"+clientID, date.toString().getBytes(), NO_ACL, CreateMode.PERSISTENT); isNew = true; } catch(Exception ex) { System.err.println( ex.getMessage() ); System.out.println( ">>> znode exists ..."); } if ( isNew ) { System.out.println( ">>> lets define some values in zNode ..."); zk.create(znode + "/" + clientID +"/started", date.toString().getBytes(), NO_ACL, CreateMode.PERSISTENT); //zk.create(znode + "/" + clientID +"/status", "good".getBytes(), NO_ACL, CreateMode.PERSISTENT); //zk.create(znode + "/" + clientID +"/spool", "empty".getBytes(), NO_ACL, CreateMode.PERSISTENT_SEQUENTIAL); } } catch (KeeperException ex) { Logger.getLogger(DataMonitor.class.getName()).log(Level.SEVERE, null, ex); } catch (InterruptedException ex) { Logger.getLogger(DataMonitor.class.getName()).log(Level.SEVERE, null, ex); } } /** * Other classes use the DataMonitor by implementing this method */ public interface DataMonitorListener { /** * The existence status of the node has changed. */ void exists(byte data[]); /** * The ZooKeeper session is no longer valid. * * @param rc * the ZooKeeper reason code */ void closing(int rc); public void setCMD(String data); } public void process(WatchedEvent event) { String path = event.getPath(); if (event.getType() == Event.EventType.None) { // We are are being told that the state of the // connection has changed switch (event.getState()) { case SyncConnected: // In this particular example we don't need to do anything // here - watches are automatically re-registered with // server and any watches triggered while the client was // disconnected will be delivered (in order of course) break; case Expired: // It's all over dead = true; listener.closing(KeeperException.Code.SessionExpired); break; } } else { if (path != null && path.equals(znode)) { // Something has changed on the node, let's find out zk.exists(znode, true, this, null); } } if (chainedWatcher != null) { chainedWatcher.process(event); } } public void processResult(int rc, String path, Object ctx, Stat stat) { boolean exists; switch (rc) { case Code.Ok: exists = true; break; case Code.NoNode: exists = false; break; case Code.SessionExpired: case Code.NoAuth: dead = true; listener.closing(rc); return; default: // Retry errors zk.exists(znode, true, this, null); return; } byte b[] = null; if (exists) { try { b = zk.getData(znode + "/" + clientID, false, null); String data = new String(b); listener.setCMD( data ); System.out.println( "... b={" + data + "}\n"); } catch (KeeperException e) { // We don't need to worry about recovering now. The watch // callbacks will kick off any exception handling e.printStackTrace(); } catch (InterruptedException e) { return; } } if ((b == null && b != prevData) || (b != null && !Arrays.equals(prevData, b))) { listener.exists(b); prevData = b; } } }