KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jgroups > blocks > ReplicatedTree


1 // $Id: ReplicatedTree.java,v 1.9 2005/02/19 13:23:34 belaban Exp $
2

3 package org.jgroups.blocks;
4
5
6 import org.apache.commons.logging.Log;
7 import org.apache.commons.logging.LogFactory;
8 import org.jgroups.*;
9 import org.jgroups.util.Queue;
10 import org.jgroups.util.QueueClosedException;
11 import org.jgroups.util.Util;
12
13 import java.io.Serializable JavaDoc;
14 import java.util.*;
15
16
17
18
19 /**
20  * A tree-like structure that is replicated across several members. Updates will be multicast to all group
21  * members reliably and in the same order.
22  * @author Bela Ban Jan 17 2002
23  * @author <a HREF="mailto:aolias@yahoo.com">Alfonso Olias-Sanz</a>
24  * @deprecated This class is unsupported; use JBossCache instead: http://www.jboss.com/products/jbosscache
25  */

26 public class ReplicatedTree implements Runnable JavaDoc, MessageListener, MembershipListener {
27     public static final String JavaDoc SEPARATOR="/";
28     final static int INDENT=4;
29     Node root=new Node(SEPARATOR, SEPARATOR, null, null);
30     final Vector listeners=new Vector();
31     final Queue request_queue=new Queue();
32     Thread JavaDoc request_handler=null;
33     JChannel channel=null;
34     PullPushAdapter adapter=null;
35     String JavaDoc groupname="ReplicatedTree-Group";
36     final Vector members=new Vector();
37     long state_fetch_timeout=10000;
38
39     protected final Log log=LogFactory.getLog(this.getClass());
40
41
42     /** Whether or not to use remote calls. If false, all methods will be invoked directly on this
43      instance rather than sending a message to all replicas and only then invoking the method.
44      Useful for testing */

45     boolean remote_calls=true;
46     String JavaDoc props="UDP(mcast_addr=224.0.0.36;mcast_port=55566;ip_ttl=32;" +
47             "mcast_send_buf_size=150000;mcast_recv_buf_size=80000):" +
48             "PING(timeout=2000;num_initial_members=3):" +
49             "MERGE2(min_interval=5000;max_interval=10000):" +
50             "FD_SOCK:" +
51             "VERIFY_SUSPECT(timeout=1500):" +
52             "pbcast.STABLE(desired_avg_gossip=20000):" +
53             "pbcast.NAKACK(gc_lag=50;retransmit_timeout=600,1200,2400,4800):" +
54             "UNICAST(timeout=5000):" +
55             "FRAG(frag_size=16000;down_thread=false;up_thread=false):" +
56             "pbcast.GMS(join_timeout=5000;join_retry_timeout=2000;" +
57             "shun=false;print_local_addr=true):" +
58             "pbcast.STATE_TRANSFER";
59     // "PERF(details=true)";
60

61     /** Determines when the updates have to be sent across the network, avoids sending unnecessary
62      * messages when there are no member in the group */

63     private boolean send_message = false;
64
65
66
67     public interface ReplicatedTreeListener {
68         void nodeAdded(String JavaDoc fqn);
69
70         void nodeRemoved(String JavaDoc fqn);
71
72         void nodeModified(String JavaDoc fqn);
73
74         void viewChange(View new_view); // might be MergeView after merging
75
}
76
77
78     /**
79      * Creates a channel with the given properties. Connects to the channel, then creates a PullPushAdapter
80      * and starts it
81      */

82     public ReplicatedTree(String JavaDoc groupname, String JavaDoc props, long state_fetch_timeout) throws Exception JavaDoc {
83         if(groupname != null)
84             this.groupname=groupname;
85         if(props != null)
86             this.props=props;
87         this.state_fetch_timeout=state_fetch_timeout;
88         channel=new JChannel(this.props);
89         channel.connect(this.groupname);
90         start();
91     }
92
93     public ReplicatedTree() {
94     }
95
96
97     /**
98      * Expects an already connected channel. Creates a PullPushAdapter and starts it
99      */

100     public ReplicatedTree(JChannel channel) throws Exception JavaDoc {
101         this.channel=channel;
102         start();
103     }
104
105
106     public void setRemoteCalls(boolean flag) {
107         remote_calls=flag;
108     }
109
110     public void setRootNode(Node n) {
111         root=n;
112     }
113
114     public Address getLocalAddress() {
115         return channel != null? channel.getLocalAddress() : null;
116     }
117
118     public Vector getMembers() {
119         return members;
120     }
121
122
123     /**
124      * Fetch the group state from the current coordinator. If successful, this will trigger setState().
125      */

126     public void fetchState(long timeout) throws ChannelClosedException, ChannelNotConnectedException {
127         boolean rc=channel.getState(null, timeout);
128         if(rc)
129             if(log.isInfoEnabled()) log.info("state was retrieved successfully");
130         else
131             if(log.isInfoEnabled()) log.info("state could not be retrieved (first member)");
132     }
133
134
135     public void addReplicatedTreeListener(ReplicatedTreeListener listener) {
136         if(!listeners.contains(listener))
137             listeners.addElement(listener);
138     }
139
140
141     public void removeReplicatedTreeListener(ReplicatedTreeListener listener) {
142         listeners.removeElement(listener);
143     }
144
145
146     public void start() throws Exception JavaDoc {
147         if(request_handler == null) {
148             request_handler=new Thread JavaDoc(this, "ReplicatedTree.RequestHandler thread");
149             request_handler.setDaemon(true);
150             request_handler.start();
151         }
152         adapter=new PullPushAdapter(channel, this, this);
153         adapter.setListener(this);
154         channel.setOpt(Channel.GET_STATE_EVENTS, Boolean.TRUE);
155         boolean rc=channel.getState(null, state_fetch_timeout);
156         if(rc)
157             if(log.isInfoEnabled()) log.info("state was retrieved successfully");
158         else
159             if(log.isInfoEnabled()) log.info("state could not be retrieved (first member)");
160     }
161
162
163     public void stop() {
164         if(request_handler != null && request_handler.isAlive()) {
165             request_queue.close(true);
166             request_handler=null;
167         }
168
169         request_handler=null;
170         if(channel != null) {
171             channel.close();
172         }
173         if(adapter != null) {
174             adapter.stop();
175             adapter=null;
176         }
177         channel=null;
178     }
179
180
181     /**
182      * Adds a new node to the tree and sets its data. If the node doesn not yet exist, it will be created.
183      * Also, parent nodes will be created if not existent. If the node already has data, then the new data
184      * will override the old one. If the node already existed, a nodeModified() notification will be generated.
185      * Otherwise a nodeCreated() motification will be emitted.
186      * @param fqn The fully qualified name of the new node
187      * @param data The new data. May be null if no data should be set in the node.
188      */

189     public void put(String JavaDoc fqn, HashMap data) {
190         if(!remote_calls) {
191             _put(fqn, data);
192             return;
193         }
194
195         //Changes done by <aos>
196
//if true, propagate action to the group
197
if(send_message == true) {
198             if(channel == null) {
199                 if(log.isErrorEnabled()) log.error("channel is null, cannot broadcast PUT request");
200                 return;
201             }
202             try {
203                 channel.send(
204                         new Message(
205                                 null,
206                                 null,
207                                 new Request(Request.PUT, fqn, data)));
208             }
209             catch(Exception JavaDoc ex) {
210                 if(log.isErrorEnabled()) log.error("failure bcasting PUT request: " + ex);
211             }
212         }
213         else {
214             _put(fqn, data);
215         }
216     }
217
218
219     /**
220      * Adds a key and value to a given node. If the node doesn't exist, it will be created. If the node
221      * already existed, a nodeModified() notification will be generated. Otherwise a
222      * nodeCreated() motification will be emitted.
223      * @param fqn The fully qualified name of the node
224      * @param key The key
225      * @param value The value
226      */

227     public void put(String JavaDoc fqn, String JavaDoc key, Object JavaDoc value) {
228         if(!remote_calls) {
229             _put(fqn, key, value);
230             return;
231         }
232
233         //Changes done by <aos>
234
//if true, propagate action to the group
235
if(send_message == true) {
236
237             if(channel == null) {
238                 if(log.isErrorEnabled()) log.error("channel is null, cannot broadcast PUT request");
239                 return;
240             }
241             try {
242                 channel.send(
243                         new Message(
244                                 null,
245                                 null,
246                                 new Request(Request.PUT, fqn, key, value)));
247             }
248             catch(Exception JavaDoc ex) {
249                 if(log.isErrorEnabled()) log.error("failure bcasting PUT request: " + ex);
250             }
251         }
252         else {
253             _put(fqn, key, value);
254         }
255     }
256
257
258     /**
259      * Removes the node from the tree.
260      * @param fqn The fully qualified name of the node.
261      */

262     public void remove(String JavaDoc fqn) {
263         if(!remote_calls) {
264             _remove(fqn);
265             return;
266         }
267         //Changes done by <aos>
268
//if true, propagate action to the group
269
if(send_message == true) {
270             if(channel == null) {
271                 if(log.isErrorEnabled()) log.error("channel is null, cannot broadcast REMOVE request");
272                 return;
273             }
274             try {
275                 channel.send(
276                         new Message(null, null, new Request(Request.REMOVE, fqn)));
277             }
278             catch(Exception JavaDoc ex) {
279                 if(log.isErrorEnabled()) log.error("failure bcasting REMOVE request: " + ex);
280             }
281         }
282         else {
283             _remove(fqn);
284         }
285     }
286
287
288     /**
289      * Removes <code>key</code> from the node's hashmap
290      * @param fqn The fullly qualified name of the node
291      * @param key The key to be removed
292      */

293     public void remove(String JavaDoc fqn, String JavaDoc key) {
294         if(!remote_calls) {
295             _remove(fqn, key);
296             return;
297         }
298         //Changes done by <aos>
299
//if true, propagate action to the group
300
if(send_message == true) {
301             if(channel == null) {
302                 if(log.isErrorEnabled()) log.error("channel is null, cannot broadcast REMOVE request");
303                 return;
304             }
305             try {
306                 channel.send(
307                         new Message(
308                                 null,
309                                 null,
310                                 new Request(Request.REMOVE, fqn, key)));
311             }
312             catch(Exception JavaDoc ex) {
313                 if(log.isErrorEnabled()) log.error("failure bcasting REMOVE request: " + ex);
314             }
315         }
316         else {
317             _remove(fqn, key);
318         }
319     }
320
321
322     /**
323      * Checks whether a given node exists in the tree
324      * @param fqn The fully qualified name of the node
325      * @return boolean Whether or not the node exists
326      */

327     public boolean exists(String JavaDoc fqn) {
328         if(fqn == null) return false;
329         return findNode(fqn) != null? true : false;
330     }
331
332
333     /**
334      * Gets the keys of the <code>data</code> map. Returns all keys as Strings. Returns null if node
335      * does not exist.
336      * @param fqn The fully qualified name of the node
337      * @return Set A set of keys (as Strings)
338      */

339     public Set getKeys(String JavaDoc fqn) {
340         Node n=findNode(fqn);
341         Map data;
342
343         if(n == null) return null;
344         data=n.getData();
345         if(data == null) return null;
346         return data.keySet();
347     }
348
349
350     /**
351      * Finds a node given its name and returns the value associated with a given key in its <code>data</code>
352      * map. Returns null if the node was not found in the tree or the key was not found in the hashmap.
353      * @param fqn The fully qualified name of the node.
354      * @param key The key.
355      */

356     public Object JavaDoc get(String JavaDoc fqn, String JavaDoc key) {
357         Node n=findNode(fqn);
358
359         if(n == null) return null;
360         return n.getData(key);
361     }
362
363
364     /**
365      * Returns the data hashmap for a given node. This method can only be used by callers that are inside
366      * the same package. The reason is that callers must not modify the return value, as these modifications
367      * would not be replicated, thus rendering the replicas inconsistent.
368      * @param fqn The fully qualified name of the node
369      * @return HashMap The data hashmap for the given node
370      */

371     HashMap get(String JavaDoc fqn) {
372         Node n=findNode(fqn);
373
374         if(n == null) return null;
375         return n.getData();
376     }
377
378
379     /**
380      * Prints a representation of the node defined by <code>fqn</code>. Output includes name, fqn and
381      * data.
382      */

383     public String JavaDoc print(String JavaDoc fqn) {
384         Node n=findNode(fqn);
385         if(n == null) return null;
386         return n.toString();
387     }
388
389
390     /**
391      * Returns all children of a given node
392      * @param fqn The fully qualified name of the node
393      * @return Set A list of child names (as Strings)
394      */

395     public Set getChildrenNames(String JavaDoc fqn) {
396         Node n=findNode(fqn);
397         Map m;
398
399         if(n == null) return null;
400         m=n.getChildren();
401         if(m != null)
402             return m.keySet();
403         else
404             return null;
405     }
406
407
408     public String JavaDoc toString() {
409         StringBuffer JavaDoc sb=new StringBuffer JavaDoc();
410         int indent=0;
411         Map children;
412
413         children=root.getChildren();
414         if(children != null && children.size() > 0) {
415             Collection nodes=children.values();
416             for(Iterator it=nodes.iterator(); it.hasNext();) {
417                 ((Node)it.next()).print(sb, indent);
418                 sb.append('\n');
419             }
420         }
421         else
422             sb.append(SEPARATOR);
423         return sb.toString();
424     }
425
426    /**
427     * Returns the name of the group that the DistributedTree is connected to
428     * @return String
429     */

430     public String JavaDoc getGroupName() {return groupname;}
431         
432    /**
433     * Returns the Channel the DistributedTree is connected to
434     * @return Channel
435     */

436     public Channel getChannel() {return channel;}
437
438    /**
439     * Returns the number of current members joined to the group
440     * @return int
441     */

442     public int getGroupMembersNumber() {return members.size();}
443
444
445
446
447     /* --------------------- Callbacks -------------------------- */
448
449
450     public void _put(String JavaDoc fqn, HashMap data) {
451         Node n;
452         StringHolder child_name=new StringHolder();
453         boolean child_exists=false;
454
455         if(fqn == null) return;
456         n=findParentNode(fqn, child_name, true); // create all nodes if they don't exist
457
if(child_name.getValue() != null) {
458             child_exists=n.childExists(child_name.getValue());
459             n.createChild(child_name.getValue(), fqn, n, data);
460         }
461         else {
462             child_exists=true;
463             n.setData(data);
464         }
465         if(child_exists)
466             notifyNodeModified(fqn);
467         else
468             notifyNodeAdded(fqn);
469     }
470
471
472     public void _put(String JavaDoc fqn, String JavaDoc key, Object JavaDoc value) {
473         Node n;
474         StringHolder child_name=new StringHolder();
475         boolean child_exists=false;
476
477         if(fqn == null || key == null || value == null) return;
478         n=findParentNode(fqn, child_name, true);
479         if(child_name.getValue() != null) {
480             child_exists=n.childExists(child_name.getValue());
481             n.createChild(child_name.getValue(), fqn, n, key, value);
482         }
483         else {
484             child_exists=true;
485             n.setData(key, value);
486         }
487         if(child_exists)
488             notifyNodeModified(fqn);
489         else
490             notifyNodeAdded(fqn);
491     }
492
493
494     public void _remove(String JavaDoc fqn) {
495         Node n;
496         StringHolder child_name=new StringHolder();
497
498         if(fqn == null) return;
499         if(fqn.equals(SEPARATOR)) {
500             root.removeAll();
501             notifyNodeRemoved(fqn);
502             return;
503         }
504         n=findParentNode(fqn, child_name, false);
505         if(n == null) return;
506         n.removeChild(child_name.getValue(), fqn);
507         notifyNodeRemoved(fqn);
508     }
509
510
511     public void _remove(String JavaDoc fqn, String JavaDoc key) {
512         Node n;
513
514         if(fqn == null || key == null) return;
515         n=findNode(fqn);
516         if(n != null)
517             n.removeData(key);
518     }
519
520
521     public void _removeData(String JavaDoc fqn) {
522         Node n;
523
524         if(fqn == null) return;
525         n=findNode(fqn);
526         if(n != null)
527             n.removeData();
528     }
529
530
531     /* ----------------- End of Callbacks ---------------------- */
532
533
534
535
536
537
538     /*-------------------- MessageListener ----------------------*/
539
540     /** Callback. Process the contents of the message; typically an _add() or _set() request */
541     public void receive(Message msg) {
542         Request req=null;
543
544         if(msg == null || msg.getLength() == 0)
545             return;
546         try {
547             req=(Request)msg.getObject();
548             request_queue.add(req);
549         }
550         catch(QueueClosedException queue_closed_ex) {
551             if(log.isErrorEnabled()) log.error("request queue is null");
552         }
553         catch(Exception JavaDoc ex) {
554             if(log.isErrorEnabled()) log.error("failed unmarshalling request: " + ex);
555             return;
556         }
557     }
558
559     /** Return a copy of the current cache (tree) */
560     public byte[] getState() {
561         try {
562             return Util.objectToByteBuffer(root.clone());
563         }
564         catch(Throwable JavaDoc ex) {
565             if(log.isErrorEnabled()) log.error("exception returning cache: " + ex);
566             return null;
567         }
568     }
569
570     /** Set the cache (tree) to this value */
571     public void setState(byte[] new_state) {
572         Node new_root=null;
573         Object JavaDoc obj;
574
575         if(new_state == null) {
576             if(log.isInfoEnabled()) log.info("new cache is null");
577             return;
578         }
579         try {
580             obj=Util.objectFromByteBuffer(new_state);
581             new_root=(Node)((Node)obj).clone();
582             root=new_root;
583             notifyAllNodesCreated(root);
584         }
585         catch(Throwable JavaDoc ex) {
586             if(log.isErrorEnabled()) log.error("could not set cache: " + ex);
587         }
588     }
589
590     /*-------------------- End of MessageListener ----------------------*/
591
592
593
594
595
596     /*----------------------- MembershipListener ------------------------*/
597
598     public void viewAccepted(View new_view) {
599         Vector new_mbrs=new_view.getMembers();
600
601         // todo: if MergeView, fetch and reconcile state from coordinator
602
// actually maybe this is best left up to the application ? we just notify them and let
603
// the appl handle it ?
604

605         if(new_mbrs != null) {
606             notifyViewChange(new_view);
607             members.removeAllElements();
608             for(int i=0; i < new_mbrs.size(); i++)
609                 members.addElement(new_mbrs.elementAt(i));
610         }
611         //if size is bigger than one, there are more peers in the group
612
//otherwise there is only one server.
613
if(members.size() > 1) {
614             send_message=true;
615         }
616         else {
617             send_message=false;
618         }
619     }
620
621
622     /** Called when a member is suspected */
623     public void suspect(Address suspected_mbr) {
624         ;
625     }
626
627
628     /** Block sending and receiving of messages until viewAccepted() is called */
629     public void block() {
630     }
631
632     /*------------------- End of MembershipListener ----------------------*/
633
634
635
636     /** Request handler thread */
637     public void run() {
638         Request req;
639         String JavaDoc fqn=null;
640
641         while(request_handler != null) {
642             try {
643                 req=(Request)request_queue.remove(0);
644                 fqn=req.fqn;
645                 switch(req.type) {
646                     case Request.PUT:
647                         if(req.key != null && req.value != null)
648                             _put(fqn, req.key, req.value);
649                         else
650                             _put(fqn, req.data);
651                         break;
652                     case Request.REMOVE:
653                         if(req.key != null)
654                             _remove(fqn, req.key);
655                         else
656                             _remove(fqn);
657                         break;
658                     default:
659                         if(log.isErrorEnabled()) log.error("type " + req.type + " unknown");
660                         break;
661                 }
662             }
663             catch(QueueClosedException queue_closed_ex) {
664                 request_handler=null;
665                 break;
666             }
667             catch(Throwable JavaDoc other_ex) {
668                 if(log.isWarnEnabled()) log.warn("exception processing request: " + other_ex);
669             }
670         }
671     }
672
673
674     /**
675      * Find the node just <em>above</em> the one indicated by <code>fqn</code>. This is needed in many cases,
676      * e.g. to add a new node or remove an existing node.
677      * @param fqn The fully qualified name of the node.
678      * @param child_name Will be filled with the name of the child when this method returns. The child name
679      * is the last relative name of the <code>fqn</code>, e.g. in "/a/b/c" it would be "c".
680      * @param create_if_not_exists Create parent nodes along the way if they don't exist. Otherwise, this method
681      * will return when a node cannot be found.
682      */

683     Node findParentNode(String JavaDoc fqn, StringHolder child_name, boolean create_if_not_exists) {
684         Node curr=root, node;
685         StringTokenizer tok;
686         String JavaDoc name;
687         StringBuffer JavaDoc sb=null;
688
689         if(fqn == null || fqn.equals(SEPARATOR) || "".equals(fqn))
690             return curr;
691
692         sb=new StringBuffer JavaDoc();
693         tok=new StringTokenizer(fqn, SEPARATOR);
694         while(tok.countTokens() > 1) {
695             name=tok.nextToken();
696             sb.append(SEPARATOR).append(name);
697             node=curr.getChild(name);
698             if(node == null && create_if_not_exists)
699                 node=curr.createChild(name, sb.toString(), null, null);
700             if(node == null)
701                 return null;
702             else
703                 curr=node;
704         }
705
706         if(tok.countTokens() > 0 && child_name != null)
707             child_name.setValue(tok.nextToken());
708         return curr;
709     }
710
711
712     /**
713      * Returns the node at fqn. This method should not be used by clients (therefore it is package-private):
714      * it is only used internally (for navigation). C++ 'friend' would come in handy here...
715      * @param fqn The fully qualified name of the node
716      * @return Node The node at fqn
717      */

718     Node findNode(String JavaDoc fqn) {
719         StringHolder sh=new StringHolder();
720         Node n=findParentNode(fqn, sh, false);
721         String JavaDoc child_name=sh.getValue();
722
723         if(fqn == null || fqn.equals(SEPARATOR) || "".equals(fqn))
724             return root;
725
726         if(n == null || child_name == null)
727             return null;
728         else
729             return n.getChild(child_name);
730     }
731
732
733     void notifyNodeAdded(String JavaDoc fqn) {
734         for(int i=0; i < listeners.size(); i++)
735             ((ReplicatedTreeListener)listeners.elementAt(i)).nodeAdded(fqn);
736     }
737
738     void notifyNodeRemoved(String JavaDoc fqn) {
739         for(int i=0; i < listeners.size(); i++)
740             ((ReplicatedTreeListener)listeners.elementAt(i)).nodeRemoved(fqn);
741     }
742
743     void notifyNodeModified(String JavaDoc fqn) {
744         for(int i=0; i < listeners.size(); i++)
745             ((ReplicatedTreeListener)listeners.elementAt(i)).nodeModified(fqn);
746     }
747
748     void notifyViewChange(View v) {
749         for(int i=0; i < listeners.size(); i++)
750             ((ReplicatedTreeListener)listeners.elementAt(i)).viewChange(v);
751     }
752
753     /** Generates NodeAdded notifications for all nodes of the tree. This is called whenever the tree is
754      initially retrieved (state transfer) */

755     void notifyAllNodesCreated(Node curr) {
756         Node n;
757         Map children;
758
759         if(curr == null) return;
760         notifyNodeAdded(curr.fqn);
761         if((children=curr.getChildren()) != null) {
762             for(Iterator it=children.values().iterator(); it.hasNext();) {
763                 n=(Node)it.next();
764                 notifyAllNodesCreated(n);
765             }
766         }
767     }
768
769
770     public static class Node implements Serializable JavaDoc {
771         String JavaDoc name=null; // relative name (e.g. "Security")
772
String JavaDoc fqn=null; // fully qualified name (e.g. "/federations/fed1/servers/Security")
773
Node parent=null; // parent node
774
TreeMap children=null; // keys: child name, value: Node
775
HashMap data=null; // data for current node
776
// Address creator=null; // member that created this node (needed ?)
777

778
779         private Node(String JavaDoc child_name, String JavaDoc fqn, Node parent, HashMap data) {
780             name=child_name;
781             this.fqn=fqn;
782             this.parent=parent;
783             if(data != null) this.data=(HashMap)data.clone();
784         }
785
786         private Node(String JavaDoc child_name, String JavaDoc fqn, Node parent, String JavaDoc key, Object JavaDoc value) {
787             name=child_name;
788             this.fqn=fqn;
789             this.parent=parent;
790             if(data == null) data=new HashMap();
791             data.put(key, value);
792         }
793
794         void setData(Map data) {
795             if(data == null) return;
796             if(this.data == null)
797                 this.data=new HashMap();
798             this.data.putAll(data);
799         }
800
801         void setData(String JavaDoc key, Object JavaDoc value) {
802             if(this.data == null)
803                 this.data=new HashMap();
804             this.data.put(key, value);
805         }
806
807         HashMap getData() {
808             return data;
809         }
810
811         Object JavaDoc getData(String JavaDoc key) {
812             return data != null? data.get(key) : null;
813         }
814
815
816         boolean childExists(String JavaDoc child_name) {
817             if(child_name == null) return false;
818             return children != null? children.containsKey(child_name) : false;
819         }
820
821
822         Node createChild(String JavaDoc child_name, String JavaDoc fqn, Node parent, HashMap data) {
823             Node child=null;
824
825             if(child_name == null) return null;
826             if(children == null) children=new TreeMap();
827             child=(Node)children.get(child_name);
828             if(child != null)
829                 child.setData(data);
830             else {
831                 child=new Node(child_name, fqn, parent, data);
832                 children.put(child_name, child);
833             }
834             return child;
835         }
836
837         Node createChild(String JavaDoc child_name, String JavaDoc fqn, Node parent, String JavaDoc key, Object JavaDoc value) {
838             Node child=null;
839
840             if(child_name == null) return null;
841             if(children == null) children=new TreeMap();
842             child=(Node)children.get(child_name);
843             if(child != null)
844                 child.setData(key, value);
845             else {
846                 child=new Node(child_name, fqn, parent, key, value);
847                 children.put(child_name, child);
848             }
849             return child;
850         }
851
852
853         Node getChild(String JavaDoc child_name) {
854             return child_name == null? null : children == null? null : (Node)children.get(child_name);
855         }
856
857         Map getChildren() {
858             return children;
859         }
860
861         void removeData(String JavaDoc key) {
862             if(data != null)
863                 data.remove(key);
864         }
865
866         void removeData() {
867             if(data != null)
868                 data.clear();
869         }
870
871         void removeChild(String JavaDoc child_name, String JavaDoc fqn) {
872             if(child_name != null && children != null && children.containsKey(child_name)) {
873                 children.remove(child_name);
874             }
875         }
876
877         void removeAll() {
878             if(children != null)
879                 children.clear();
880         }
881
882         void print(StringBuffer JavaDoc sb, int indent) {
883             printIndent(sb, indent);
884             sb.append(SEPARATOR).append(name);
885             if(children != null && children.size() > 0) {
886                 Collection values=children.values();
887                 for(Iterator it=values.iterator(); it.hasNext();) {
888                     sb.append('\n');
889                     ((Node)it.next()).print(sb, indent + INDENT);
890                 }
891             }
892         }
893
894         void printIndent(StringBuffer JavaDoc sb, int indent) {
895             if(sb != null) {
896                 for(int i=0; i < indent; i++)
897                     sb.append(' ');
898             }
899         }
900
901
902         public String JavaDoc toString() {
903             StringBuffer JavaDoc sb=new StringBuffer JavaDoc();
904             if(name != null) sb.append("\nname=" + name);
905             if(fqn != null) sb.append("\nfqn=" + fqn);
906             if(data != null) sb.append("\ndata=" + data);
907             return sb.toString();
908         }
909
910
911         public Object JavaDoc clone() throws CloneNotSupportedException JavaDoc {
912             Node n=new Node(name, fqn, parent != null? (Node)parent.clone() : null, data);
913             if(children != null) n.children=(TreeMap)children.clone();
914             return n;
915         }
916
917     }
918
919
920     private static class StringHolder {
921         String JavaDoc s=null;
922
923         private StringHolder() {
924         }
925
926         private StringHolder(String JavaDoc s) {
927             this.s=s;
928         }
929
930         void setValue(String JavaDoc s) {
931             this.s=s;
932         }
933
934         String JavaDoc getValue() {
935             return s;
936         }
937     }
938
939
940     /**
941      * Class used to multicast add(), remove() and set() methods to all members.
942      */

943     private static class Request implements Serializable JavaDoc {
944         static final int PUT=1;
945         static final int REMOVE=2;
946
947         int type=0;
948         String JavaDoc fqn=null;
949         String JavaDoc key=null;
950         Object JavaDoc value=null;
951         HashMap data=null;
952
953         private Request(int type, String JavaDoc fqn) {
954             this.type=type;
955             this.fqn=fqn;
956         }
957
958         private Request(int type, String JavaDoc fqn, HashMap data) {
959             this(type, fqn);
960             this.data=data;
961         }
962
963         private Request(int type, String JavaDoc fqn, String JavaDoc key) {
964             this(type, fqn);
965             this.key=key;
966         }
967
968         private Request(int type, String JavaDoc fqn, String JavaDoc key, Object JavaDoc value) {
969             this(type, fqn);
970             this.key=key;
971             this.value=value;
972         }
973
974         public String JavaDoc toString() {
975             StringBuffer JavaDoc sb=new StringBuffer JavaDoc();
976             sb.append(type2String(type)).append(" (");
977             if(fqn != null) sb.append(" fqn=" + fqn);
978             switch(type) {
979                 case PUT:
980                     if(data != null) sb.append(", data=" + data);
981                     if(key != null) sb.append(", key=" + key);
982                     if(value != null) sb.append(", value=" + value);
983                     break;
984                 case REMOVE:
985                     if(key != null) sb.append(", key=" + key);
986                     break;
987                 default:
988                     break;
989             }
990             sb.append(')');
991             return sb.toString();
992         }
993
994         static String JavaDoc type2String(int t) {
995             switch(t) {
996                 case PUT:
997                     return "PUT";
998                 case REMOVE:
999                     return "REMOVE";
1000                default:
1001                    return "UNKNOWN";
1002            }
1003        }
1004
1005    }
1006
1007
1008    public static void main(String JavaDoc[] args) {
1009
1010
1011        ReplicatedTree tree=null;
1012        HashMap m=new HashMap();
1013        String JavaDoc props;
1014
1015        props="UDP(mcast_addr=224.0.0.36;mcast_port=55566;ip_ttl=32;" +
1016                "mcast_send_buf_size=150000;mcast_recv_buf_size=80000):" +
1017                "PING(timeout=2000;num_initial_members=3):" +
1018                "MERGE2(min_interval=5000;max_interval=10000):" +
1019                "FD_SOCK:" +
1020                "VERIFY_SUSPECT(timeout=1500):" +
1021                "pbcast.STABLE(desired_avg_gossip=20000):" +
1022                "pbcast.NAKACK(gc_lag=50;retransmit_timeout=600,1200,2400,4800):" +
1023                "UNICAST(timeout=5000):" +
1024                "FRAG(frag_size=16000;down_thread=false;up_thread=false):" +
1025                "pbcast.GMS(join_timeout=5000;join_retry_timeout=2000;" +
1026                "shun=false;print_local_addr=true):" +
1027                "pbcast.STATE_TRANSFER";
1028        // "PERF(details=true)";
1029

1030        try {
1031
1032            tree=new ReplicatedTree(null, props, 10000);
1033            // tree.setRemoteCalls(false);
1034
tree.addReplicatedTreeListener(new MyListener());
1035            tree.put("/a/b/c", null);
1036            tree.put("/a/b/c1", null);
1037            tree.put("/a/b/c2", null);
1038            tree.put("/a/b1/chat", null);
1039            tree.put("/a/b1/chat2", null);
1040            tree.put("/a/b1/chat5", null);
1041            System.out.println(tree);
1042            m.put("name", "Bela Ban");
1043            m.put("age", new Integer JavaDoc(36));
1044            m.put("cube", "240-17");
1045            tree.put("/a/b/c", m);
1046            System.out.println("info for for \"/a/b/c\" is " + tree.print("/a/b/c"));
1047            tree.put("/a/b/c", "age", new Integer JavaDoc(37));
1048            System.out.println("info for for \"/a/b/c\" is " + tree.print("/a/b/c"));
1049            tree.remove("/a/b");
1050            System.out.println(tree);
1051        }
1052        catch(Exception JavaDoc ex) {
1053            System.err.println(ex);
1054        }
1055    }
1056
1057
1058    static class MyListener implements ReplicatedTreeListener {
1059
1060        public void nodeAdded(String JavaDoc fqn) {
1061            System.out.println("** node added: " + fqn);
1062        }
1063
1064        public void nodeRemoved(String JavaDoc fqn) {
1065            System.out.println("** node removed: " + fqn);
1066        }
1067
1068        public void nodeModified(String JavaDoc fqn) {
1069            System.out.println("** node modified: " + fqn);
1070        }
1071
1072        public void viewChange(View new_view) {
1073            System.out.println("** view change: " + new_view);
1074        }
1075
1076    }
1077
1078
1079}
1080
1081
1082
Popular Tags