123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903 |
- <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
- <html>
- <head>
- <META http-equiv="Content-Type" content="text/html; charset=UTF-8">
- <meta content="Apache Forrest" name="Generator">
- <meta name="Forrest-version" content="0.8">
- <meta name="Forrest-skin-name" content="pelt">
- <title>ZooKeeper Java Example</title>
- <link type="text/css" href="skin/basic.css" rel="stylesheet">
- <link media="screen" type="text/css" href="skin/screen.css" rel="stylesheet">
- <link media="print" type="text/css" href="skin/print.css" rel="stylesheet">
- <link type="text/css" href="skin/profile.css" rel="stylesheet">
- <script src="skin/getBlank.js" language="javascript" type="text/javascript"></script><script src="skin/getMenu.js" language="javascript" type="text/javascript"></script><script src="skin/fontsize.js" language="javascript" type="text/javascript"></script>
- <link rel="shortcut icon" href="images/favicon.ico">
- </head>
- <body onload="init()">
- <script type="text/javascript">ndeSetTextSize();</script>
- <div id="top">
- <!--+
- |breadtrail
- +-->
- <div class="breadtrail">
- <a href="http://www.apache.org/">Apache</a> > <a href="http://hadoop.apache.org/">Hadoop</a> > <a href="http://hadoop.apache.org/zookeeper/">ZooKeeper</a><script src="skin/breadcrumbs.js" language="JavaScript" type="text/javascript"></script>
- </div>
- <!--+
- |header
- +-->
- <div class="header">
- <!--+
- |start group logo
- +-->
- <div class="grouplogo">
- <a href="http://hadoop.apache.org/"><img class="logoImage" alt="Hadoop" src="images/hadoop-logo.jpg" title="Apache Hadoop"></a>
- </div>
- <!--+
- |end group logo
- +-->
- <!--+
- |start Project Logo
- +-->
- <div class="projectlogo">
- <a href="http://hadoop.apache.org/zookeeper/"><img class="logoImage" alt="ZooKeeper" src="images/zookeeper_small.gif" title="ZooKeeper: distributed coordination"></a>
- </div>
- <!--+
- |end Project Logo
- +-->
- <!--+
- |start Search
- +-->
- <div class="searchbox">
- <form action="http://www.google.com/search" method="get" class="roundtopsmall">
- <input value="hadoop.apache.org" name="sitesearch" type="hidden"><input onFocus="getBlank (this, 'Search the site with google');" size="25" name="q" id="query" type="text" value="Search the site with google">
- <input name="Search" value="Search" type="submit">
- </form>
- </div>
- <!--+
- |end search
- +-->
- <!--+
- |start Tabs
- +-->
- <ul id="tabs">
- <li>
- <a class="unselected" href="http://hadoop.apache.org/zookeeper/">Project</a>
- </li>
- <li>
- <a class="unselected" href="http://wiki.apache.org/hadoop/ZooKeeper">Wiki</a>
- </li>
- <li class="current">
- <a class="selected" href="index.html">ZooKeeper 3.3 Documentation</a>
- </li>
- </ul>
- <!--+
- |end Tabs
- +-->
- </div>
- </div>
- <div id="main">
- <div id="publishedStrip">
- <!--+
- |start Subtabs
- +-->
- <div id="level2tabs"></div>
- <!--+
- |end Endtabs
- +-->
- <script type="text/javascript"><!--
- document.write("Last Published: " + document.lastModified);
- // --></script>
- </div>
- <!--+
- |breadtrail
- +-->
- <div class="breadtrail">
-
- </div>
- <!--+
- |start Menu, mainarea
- +-->
- <!--+
- |start Menu
- +-->
- <div id="menu">
- <div onclick="SwitchMenu('menu_1.1', 'skin/')" id="menu_1.1Title" class="menutitle">Overview</div>
- <div id="menu_1.1" class="menuitemgroup">
- <div class="menuitem">
- <a href="index.html">Welcome</a>
- </div>
- <div class="menuitem">
- <a href="zookeeperOver.html">Overview</a>
- </div>
- <div class="menuitem">
- <a href="zookeeperStarted.html">Getting Started</a>
- </div>
- <div class="menuitem">
- <a href="releasenotes.html">Release Notes</a>
- </div>
- </div>
- <div onclick="SwitchMenu('menu_selected_1.2', 'skin/')" id="menu_selected_1.2Title" class="menutitle" style="background-image: url('skin/images/chapter_open.gif');">Developer</div>
- <div id="menu_selected_1.2" class="selectedmenuitemgroup" style="display: block;">
- <div class="menuitem">
- <a href="api/index.html">API Docs</a>
- </div>
- <div class="menuitem">
- <a href="zookeeperProgrammers.html">Programmer's Guide</a>
- </div>
- <div class="menupage">
- <div class="menupagetitle">Java Example</div>
- </div>
- <div class="menuitem">
- <a href="zookeeperTutorial.html">Barrier and Queue Tutorial</a>
- </div>
- <div class="menuitem">
- <a href="recipes.html">Recipes</a>
- </div>
- </div>
- <div onclick="SwitchMenu('menu_1.3', 'skin/')" id="menu_1.3Title" class="menutitle">BookKeeper</div>
- <div id="menu_1.3" class="menuitemgroup">
- <div class="menuitem">
- <a href="bookkeeperStarted.html">Getting started</a>
- </div>
- <div class="menuitem">
- <a href="bookkeeperOverview.html">Overview</a>
- </div>
- <div class="menuitem">
- <a href="bookkeeperConfig.html">Setup guide</a>
- </div>
- <div class="menuitem">
- <a href="bookkeeperProgrammer.html">Programmer's guide</a>
- </div>
- </div>
- <div onclick="SwitchMenu('menu_1.4', 'skin/')" id="menu_1.4Title" class="menutitle">Admin & Ops</div>
- <div id="menu_1.4" class="menuitemgroup">
- <div class="menuitem">
- <a href="zookeeperAdmin.html">Administrator's Guide</a>
- </div>
- <div class="menuitem">
- <a href="zookeeperQuotas.html">Quota Guide</a>
- </div>
- <div class="menuitem">
- <a href="zookeeperJMX.html">JMX</a>
- </div>
- </div>
- <div onclick="SwitchMenu('menu_1.5', 'skin/')" id="menu_1.5Title" class="menutitle">Contributor</div>
- <div id="menu_1.5" class="menuitemgroup">
- <div class="menuitem">
- <a href="zookeeperInternals.html">ZooKeeper Internals</a>
- </div>
- </div>
- <div onclick="SwitchMenu('menu_1.6', 'skin/')" id="menu_1.6Title" class="menutitle">Miscellaneous</div>
- <div id="menu_1.6" class="menuitemgroup">
- <div class="menuitem">
- <a href="http://wiki.apache.org/hadoop/ZooKeeper">Wiki</a>
- </div>
- <div class="menuitem">
- <a href="http://wiki.apache.org/hadoop/ZooKeeper/FAQ">FAQ</a>
- </div>
- <div class="menuitem">
- <a href="http://hadoop.apache.org/zookeeper/mailing_lists.html">Mailing Lists</a>
- </div>
- </div>
- <div id="credit"></div>
- <div id="roundbottom">
- <img style="display: none" class="corner" height="15" width="15" alt="" src="skin/images/rc-b-l-15-1body-2menu-3menu.png"></div>
- <!--+
- |alternative credits
- +-->
- <div id="credit2"></div>
- </div>
- <!--+
- |end Menu
- +-->
- <!--+
- |start content
- +-->
- <div id="content">
- <div title="Portable Document Format" class="pdflink">
- <a class="dida" href="javaExample.pdf"><img alt="PDF -icon" src="skin/images/pdfdoc.gif" class="skin"><br>
- PDF</a>
- </div>
- <h1>ZooKeeper Java Example</h1>
- <div id="minitoc-area">
- <ul class="minitoc">
- <li>
- <a href="#ch_Introduction">A Simple Watch Client</a>
- <ul class="minitoc">
- <li>
- <a href="#sc_requirements">Requirements</a>
- </li>
- <li>
- <a href="#sc_design">Program Design</a>
- </li>
- </ul>
- </li>
- <li>
- <a href="#sc_executor">The Executor Class</a>
- </li>
- <li>
- <a href="#sc_DataMonitor">The DataMonitor Class</a>
- </li>
- <li>
- <a href="#sc_completeSourceCode">Complete Source Listings</a>
- </li>
- </ul>
- </div>
-
-
-
- <a name="N10009"></a><a name="ch_Introduction"></a>
- <h2 class="h3">A Simple Watch Client</h2>
- <div class="section">
- <p>To introduce you to the ZooKeeper Java API, we develop here a very simple
- watch client. This ZooKeeper client watches a ZooKeeper node for changes
- and responds to by starting or stopping a program.</p>
- <a name="N10012"></a><a name="sc_requirements"></a>
- <h3 class="h4">Requirements</h3>
- <p>The client has four requirements:</p>
- <ul>
- <li>
- <p>It takes as parameters:</p>
-
- <ul>
-
- <li>
- <p>the address of the ZooKeeper service</p>
- </li>
-
- <li>
- <p>then name of a znode - the one to be watched</p>
- </li>
-
- <li>
- <p>an executable with arguments.</p>
- </li>
- </ul>
- </li>
-
- <li>
- <p>It fetches the data associated with the znode and starts the executable.</p>
- </li>
-
- <li>
- <p>If the znode changes, the client refetches the contents and restarts the executable.</p>
- </li>
-
- <li>
- <p>If the znode disappears, the client kills the executable.</p>
- </li>
- </ul>
- <a name="N1003B"></a><a name="sc_design"></a>
- <h3 class="h4">Program Design</h3>
- <p>Conventionally, ZooKeeper applications are broken into two units, one which maintains the connection,
- and the other which monitors data. In this application, the class called the <strong>Executor</strong>
- maintains the ZooKeeper connection, and the class called the <strong>DataMonitor</strong> monitors the data
- in the ZooKeeper tree. Also, Executor contains the main thread and contains the execution logic.
- It is responsible for what little user interaction there is, as well as interaction with the exectuable program you
- pass in as an argument and which the sample (per the requirements) shuts down and restarts, according to the
- state of the znode.</p>
- </div>
-
- <a name="N1004C"></a><a name="sc_executor"></a>
- <h2 class="h3">The Executor Class</h2>
- <div class="section">
- <p>The Executor object is the primary container of the sample application. It contains
- both the <strong>ZooKeeper</strong> object, <strong>DataMonitor</strong>, as described above in
- <a href="#sc_design">Program Design</a>. </p>
- <pre class="code">
- // from the Executor class...
-
- public static void main(String[] args) {
- 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 exec[] = new String[args.length - 3];
- System.arraycopy(args, 3, exec, 0, exec.length);
- try {
- new Executor(hostPort, znode, filename, exec).run();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- public Executor(String hostPort, String znode, String filename,
- String exec[]) throws KeeperException, IOException {
- this.filename = filename;
- this.exec = exec;
- zk = new ZooKeeper(hostPort, 3000, this);
- dm = new DataMonitor(zk, znode, null, this);
- }
- public void run() {
- try {
- synchronized (this) {
- while (!dm.dead) {
- wait();
- }
- }
- } catch (InterruptedException e) {
- }
- }
- </pre>
- <p>
- Recall that the Executor's job is to starts and stop the executable whose name you pass in on the command line.
- It does this in response to events fired by the ZooKeeper object. As you can see in the code above, the Executor passes
- a reference to itself as the Watcher argument in the ZooKeeper constructor. It also passes a reference to itself
- as DataMonitorListener argument to the DataMonitor constructor. Per the Executor's definition, it implements both these
- interfaces:
- </p>
- <pre class="code">
- public class Executor implements Watcher, Runnable, DataMonitor.DataMonitorListener {
- ...</pre>
- <p>The <strong>Watcher</strong> interface is defined by the ZooKeeper Java API.
- ZooKeeper uses it to communicate back to its container. It supports only one method, <span class="codefrag command">process()</span>, and ZooKeeper uses
- it to communciates generic events that the main thread would be intersted in, such as the state of the ZooKeeper connection or the ZooKeeper session.The Executor
- in this example simply forwards those events down to the DataMonitor to decide what to do with them. It does this simply to illustrate
- the point that, by convention, the Executor or some Executor-like object "owns" the ZooKeeper connection, but it is free to delegate the events to other
- events to other objects. It also uses this as the default channel on which to fire watch events. (More on this later.)</p>
- <pre class="code">
- public void process(WatchedEvent event) {
- dm.process(event);
- }
- </pre>
- <p>The <strong>DataMonitorListener</strong>
- interface, on the other hand, is not part of the the ZooKeeper API. It is a completely custom interface,
- designed for this sample application. The DataMonitor object uses it to communicate back to its container, which
- is also the the Executor object.The DataMonitorListener interface looks like this:</p>
- <pre class="code">
- 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);
- }
- </pre>
- <p>This interface is defined in the DataMonitor class and implemented in the Executor class.
- When <span class="codefrag command">Executor.exists()</span> is invoked,
- the Executor decides whether to start up or shut down per the requirements. Recall that the requires say to kill the executable when the
- znode ceases to <em>exist</em>. </p>
- <p>When <span class="codefrag command">Executor.closing()</span>
- is invoked, the Executor decides whether or not to shut itself down in response to the ZooKeeper connection permanently disappearing.</p>
- <p>As you might have guessed, DataMonitor is the object that invokes
- these methods, in response to changes in ZooKeeper's state.</p>
- <p>Here are Executor's implementation of
- <span class="codefrag command">DataMonitorListener.exists()</span> and <span class="codefrag command">DataMonitorListener.closing</span>:
- </p>
- <pre class="code">
- 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();
- }
- }
- }
- public void closing(int rc) {
- synchronized (this) {
- notifyAll();
- }
- }
- </pre>
- </div>
- <a name="N100A0"></a><a name="sc_DataMonitor"></a>
- <h2 class="h3">The DataMonitor Class</h2>
- <div class="section">
- <p>
- The DataMonitor class has the meat of the ZooKeeper logic. It is mostly
- asynchronous and event driven. DataMonitor kicks things off in the constructor with:</p>
- <pre class="code">
- public DataMonitor(ZooKeeper zk, String znode, Watcher chainedWatcher,
- DataMonitorListener listener) {
- this.zk = zk;
- this.znode = znode;
- this.chainedWatcher = chainedWatcher;
- this.listener = listener;
-
- // Get things started by checking if the node exists. We are going
- // to be completely event driven
- <strong>zk.exists(znode, true, this, null);</strong>
- }
- </pre>
- <p>The call to <span class="codefrag command">ZooKeeper.exists()</span> checks for the existence of the znode,
- sets a watch, and passes a reference to itself (<span class="codefrag command">this</span>)
- as the completion callback object. In this sense, it kicks things off, since the
- real processing happens when the watch is triggered.</p>
- <div class="note">
- <div class="label">Note</div>
- <div class="content">
- <p>Don't confuse the completion callback with the watch callback. The <span class="codefrag command">ZooKeeper.exists()</span>
- completion callback, which happens to be the method <span class="codefrag command">StatCallback.processResult()</span> implemented
- in the DataMonitor object, is invoked when the asynchronous <em>setting of the watch</em> operation
- (by <span class="codefrag command">ZooKeeper.exists()</span>) completes on the server. </p>
- <p>
- The triggering of the watch, on the other hand, sends an event to the <em>Executor</em> object, since
- the Executor registered as the Watcher of the ZooKeeper object.</p>
- <p>As an aside, you might note that the DataMonitor could also register itself as the Watcher
- for this particular watch event. This is new to ZooKeeper 3.0.0 (the support of multiple Watchers). In this
- example, however, DataMonitor does not register as the Watcher.</p>
- </div>
- </div>
- <p>When the <span class="codefrag command">ZooKeeper.exists()</span> operation completes on the server, the ZooKeeper API invokes this completion callback on
- the client:</p>
- <pre class="code">
- 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 {
- <strong>b = zk.getData(znode, false, null);</strong>
- } 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))) {
- <strong>listener.exists(b);</strong>
- prevData = b;
- }
- }
- </pre>
- <p>
- The code first checks the error codes for znode existence, fatal errors, and
- recoverable errors. If the file (or znode) exists, it gets the data from the znode, and
- then invoke the exists() callback of Executor if the state has changed. Note,
- it doesn't have to do any Exception processing for the getData call because it
- has watches pending for anything that could cause an error: if the node is deleted
- before it calls <span class="codefrag command">ZooKeeper.getData()</span>, the watch event set by
- the <span class="codefrag command">ZooKeeper.exists()</span> triggers a callback;
- if there is a communication error, a connection watch event fires when
- the connection comes back up.
- </p>
- <p>Finally, notice how DataMonitor processes watch events: </p>
- <pre class="code">
- 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);
- }
- }
- </pre>
- <p>
- If the client-side ZooKeeper libraries can re-establish the
- communication channel (SyncConnected event) to ZooKeeper before
- session expiration (Expired event) all of the session's watches will
- automatically be re-established with the server (auto-reset of watches
- is new in ZooKeeper 3.0.0). See <a href="zookeeperProgrammers.html#ch_zkWatches">ZooKeeper Watches</a>
- in the programmer guide for more on this. A bit lower down in this
- function, when DataMonitor gets an event for a znode, it calls
- <span class="codefrag command">ZooKeeper.exists()</span> to find out what has changed.
- </p>
- </div>
- <a name="N10104"></a><a name="sc_completeSourceCode"></a>
- <h2 class="h3">Complete Source Listings</h2>
- <div class="section">
- <div class="note example">
- <div class="label">Executor.java</div>
- <div class="content">
- <title>Executor.java</title>
- <pre class="code">
- /**
- * A simple example program to use DataMonitor to start and
- * stop executables based on a znode. 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.
- */
- 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
- {
- String znode;
- DataMonitor dm;
- ZooKeeper zk;
- String filename;
- String exec[];
- Process child;
- public Executor(String hostPort, String znode, String filename,
- String exec[]) throws KeeperException, IOException {
- this.filename = filename;
- this.exec = exec;
- zk = new ZooKeeper(hostPort, 3000, this);
- dm = new DataMonitor(zk, znode, null, this);
- }
- /**
- * @param args
- */
- public static void main(String[] args) {
- 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 exec[] = new String[args.length - 3];
- System.arraycopy(args, 3, exec, 0, exec.length);
- try {
- new Executor(hostPort, znode, filename, exec).run();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- /***************************************************************************
- * 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();
- }
- }
- 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();
- }
- }
- }
- }
- </pre>
-
- </div>
- </div>
- <div class="note example">
- <div class="label">DataMonitor.java</div>
- <div class="content">
-
- <title>DataMonitor.java</title>
-
- <pre class="code">
- /**
- * A simple class that monitors the data and existence of a ZooKeeper
- * node. It uses asynchronous ZooKeeper APIs.
- */
- import java.util.Arrays;
- 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.KeeperException.Code;
- import org.apache.zookeeper.data.Stat;
- public class DataMonitor implements Watcher, StatCallback {
- ZooKeeper zk;
- String znode;
- Watcher chainedWatcher;
- boolean dead;
- DataMonitorListener listener;
- byte prevData[];
- public DataMonitor(ZooKeeper zk, String znode, Watcher chainedWatcher,
- DataMonitorListener listener) {
- this.zk = zk;
- this.znode = znode;
- this.chainedWatcher = chainedWatcher;
- this.listener = listener;
- // Get things started by checking if the node exists. We are going
- // to be completely event driven
- zk.exists(znode, true, this, null);
- }
- /**
- * 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 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, false, null);
- } 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;
- }
- }
- }
- </pre>
- </div>
- </div>
- </div>
- <p align="right">
- <font size="-2"></font>
- </p>
- </div>
- <!--+
- |end content
- +-->
- <div class="clearboth"> </div>
- </div>
- <div id="footer">
- <!--+
- |start bottomstrip
- +-->
- <div class="lastmodified">
- <script type="text/javascript"><!--
- document.write("Last Published: " + document.lastModified);
- // --></script>
- </div>
- <div class="copyright">
- Copyright ©
- 2008 <a href="http://www.apache.org/licenses/">The Apache Software Foundation.</a>
- </div>
- <!--+
- |end bottomstrip
- +-->
- </div>
- </body>
- </html>
|