KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > ha > framework > server > DistributedStateImpl


1 /*
2   * JBoss, Home of Professional Open Source
3   * Copyright 2005, JBoss Inc., and individual contributors as indicated
4   * by the @authors tag. See the copyright.txt in the distribution for a
5   * full listing of individual contributors.
6   *
7   * This is free software; you can redistribute it and/or modify it
8   * under the terms of the GNU Lesser General Public License as
9   * published by the Free Software Foundation; either version 2.1 of
10   * the License, or (at your option) any later version.
11   *
12   * This software is distributed in the hope that it will be useful,
13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15   * Lesser General Public License for more details.
16   *
17   * You should have received a copy of the GNU Lesser General Public
18   * License along with this software; if not, write to the Free
19   * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20   * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
21   */

22 package org.jboss.ha.framework.server;
23
24
25 import java.io.Serializable JavaDoc;
26 import java.util.ArrayList JavaDoc;
27 import java.util.Collection JavaDoc;
28 import java.util.Collections JavaDoc;
29 import java.util.HashMap JavaDoc;
30 import java.util.HashSet JavaDoc;
31 import java.util.Iterator JavaDoc;
32 import java.util.Map JavaDoc;
33 import java.util.Set JavaDoc;
34
35 import org.jboss.cache.AbstractCacheListener;
36 import org.jboss.cache.Cache;
37 import org.jboss.cache.CacheException;
38 import org.jboss.cache.Fqn;
39 import org.jboss.cache.Node;
40 import org.jboss.ha.framework.interfaces.HAPartition;
41 import org.jboss.logging.Logger;
42 import org.jboss.system.ServiceMBeanSupport;
43
44 /**
45  * This class manages distributed state across the cluster.
46  *
47  * @author <a HREF="mailto:sacha.labourey@cogito-info.ch">Sacha Labourey</a>.
48  * @author <a HREF="mailto:bill@burkecentral.com">Bill Burke</a>.
49  * @author Scott.Stark@jboss.org
50  * @version $Revision: 58569 $
51  */

52 public class DistributedStateImpl
53    extends ServiceMBeanSupport
54    implements DistributedStateImplMBean
55 {
56    // Constants -----------------------------------------------------
57

58    protected final static String JavaDoc SERVICE_NAME = "DistributedState";
59
60    protected final static Class JavaDoc[] set_types=new Class JavaDoc[]{String JavaDoc.class, Serializable JavaDoc.class, Serializable JavaDoc.class};
61    protected final static Class JavaDoc[] remove_types=new Class JavaDoc[]{String JavaDoc.class, Serializable JavaDoc.class};
62
63    // Attributes ----------------------------------------------------
64

65    protected HashMap JavaDoc keyListeners = new HashMap JavaDoc ();
66    protected HAPartition partition;
67    protected Logger log;
68 // protected MBeanServer mbeanServer = null;
69
protected String JavaDoc name = null;
70    protected Cache cache;
71    private DSCacheListener cacheListener;
72
73    public static final String JavaDoc ROOT = "__DISTRIBUTED_STATE__";
74
75    public static final Fqn ROOTFQN = new Fqn(new Object JavaDoc[] { ROOT });
76
77    public static final int ROOTFQNSIZE = ROOTFQN.size();
78
79    // Static --------------------------------------------------------c
80

81    // Constructors --------------------------------------------------
82

83    public DistributedStateImpl ()
84    {
85       super();
86       this.log = Logger.getLogger (this.getClass ());
87       this.cacheListener = new DSCacheListener();
88    }
89
90    // Public --------------------------------------------------------
91

92    
93 // public void init () throws Exception
94
// {
95
// ObjectName name = new ObjectName("jboss.cache:service=ClusterTreeCache");
96
// cache = null;
97
// if (name == null) {
98
// log.debug("DistributedState - failed to get name for ClusterTreeCache MBean");
99
// }
100
// else {
101
// String method = "getInstance";
102
// Object o = mbeanServer.invoke(name, method, null, null);
103
// if (o == null) {
104
// log.debug("DistributedState - ClusterTreeCache instance is null");
105
// }
106
// else {
107
// log.debug("DistributedState - ClusterTreeCache instance is "+o.getClass().getName());
108
// cache = (TreeCache)o;
109
// }
110
// }
111
// cache.addTreeCacheListener(this);
112
//
113
// // subscribed this "sub-service" of HAPartition with JMX
114
// // TODO: In the future (when state transfer issues will be completed),
115
// // we will need to redesign the way HAPartitions and its sub-protocols are
116
// // registered with JMX. They will most probably be independant JMX services.
117
// //
118
// this.name = "jboss:service=" + SERVICE_NAME +
119
// ",partitionName=" + this.partition.getPartitionName();
120
// ObjectName jmxName = new ObjectName(this.name);
121
// mbeanServer.registerMBean(this, jmxName);
122
// Registry.bind (this.name, this);
123
// }
124

125    protected void createService() throws Exception JavaDoc
126    {
127       super.createService();
128       //cache.addTreeCacheListener(this);
129
}
130
131    public void startService() throws Exception JavaDoc
132    {
133       super.startService();
134    }
135
136    public void stopService() throws Exception JavaDoc
137    {
138       super.stopService();
139       // JBCLUSTER-38 move to destroy
140
// Registry.unbind (this.name);
141
// ObjectName jmxName = new ObjectName(this.name);
142
// mbeanServer.unregisterMBean (jmxName);
143
}
144    
145    public void destroyService() throws Exception JavaDoc
146    {
147       super.destroyService();
148       cache.removeCacheListener(cacheListener);
149 // Registry.unbind (this.name);
150
// ObjectName jmxName = new ObjectName(this.name);
151
// mbeanServer.unregisterMBean (jmxName);
152

153    }
154
155    public String JavaDoc listContent () throws Exception JavaDoc
156    {
157       StringBuffer JavaDoc result = new StringBuffer JavaDoc ();
158       Collection JavaDoc cats = this.getAllCategories ();
159       Iterator JavaDoc catsIter = cats.iterator ();
160       while (catsIter.hasNext ())
161       {
162          String JavaDoc category = (String JavaDoc)catsIter.next ();
163          Iterator JavaDoc keysIter = this.getAllKeys(category).iterator ();
164
165          result.append ("-----------------------------------------------\n");
166          result.append ("Logger : ").append (category).append ("\n\n");
167          result.append ("KEY\t:\tVALUE\n");
168
169          while (keysIter.hasNext ())
170          {
171             Serializable JavaDoc key = (Serializable JavaDoc) keysIter.next ();
172             String JavaDoc value = this.get (category, key).toString ();
173             result.append ("'").append(key);
174             result.append ("'\t:\t'");
175             result.append (value);
176             result.append("'\n");
177          }
178          result.append ("\n");
179       }
180       return result.toString ();
181    }
182
183    public String JavaDoc listXmlContent () throws Exception JavaDoc
184    {
185       StringBuffer JavaDoc result = new StringBuffer JavaDoc ();
186       Collection JavaDoc cats = this.getAllCategories ();
187       Iterator JavaDoc catsIter = cats.iterator ();
188
189       result.append ("<DistributedState>\n");
190
191       while (catsIter.hasNext ())
192       {
193          String JavaDoc category = (String JavaDoc)catsIter.next ();
194          Iterator JavaDoc keysIter = this.getAllKeys(category).iterator ();
195
196          result.append ("\t<Logger>\n");
197          result.append ("\t\t<LoggerName>").append (category).append ("</LoggerName>\n");
198
199          while (keysIter.hasNext ())
200          {
201             Serializable JavaDoc key = (Serializable JavaDoc) keysIter.next ();
202             String JavaDoc value = this.get (category, key).toString ();
203             result.append ("\t\t<Entry>\n");
204             result.append ("\t\t\t<Key>").append (key).append ("</Key>\n");
205             result.append ("\t\t\t<Value>").append (value).append ("</Value>\n");
206             result.append ("\t\t</Entry>\n");
207          }
208          result.append ("\t</Logger>\n");
209       }
210       result.append ("</DistributedState>\n");
211
212       return result.toString ();
213    }
214
215    public Cache getClusteredCache()
216    {
217       return cache;
218    }
219
220    public void setClusteredCache(Cache cache)
221    {
222       this.cache = cache;
223       this.cache.addCacheListener(cacheListener);
224    }
225
226    // DistributedState implementation ----------------------------------------------
227

228    /*
229     * (non-Javadoc)
230     *
231     * @see org.jboss.ha.framework.interfaces.DistributedState#set(java.lang.String,
232     * java.io.Serializable, java.io.Serializable)
233     */

234    public void set(String JavaDoc category, Serializable JavaDoc key, Serializable JavaDoc value)
235          throws Exception JavaDoc {
236       cache.put(buildFqn(category), key, value);
237       notifyKeyListeners (category, key, value, true);
238    }
239
240    /*
241     * (non-Javadoc)
242     *
243     * @see org.jboss.ha.framework.interfaces.DistributedState#set(java.lang.String,
244     * java.io.Serializable, java.io.Serializable, boolean) @param
245     * asynchronousCall is not supported yet. TreeCache cannot switch this
246     * on the fly. Will take value from TreeCache-config instead.
247     */

248    public void set(String JavaDoc category, Serializable JavaDoc key, Serializable JavaDoc value,
249          boolean asynchronousCall) throws Exception JavaDoc {
250       // TODO does not support asynchronousCall yet. TreeCache cannot switch this on the fly
251
set(category, key, value);
252    }
253
254    /*
255      * (non-Javadoc)
256      *
257      * @see org.jboss.ha.framework.interfaces.DistributedState#remove(java.lang.String,
258      * java.io.Serializable) @return - returns null in case of
259      * CacheException
260      */

261    public Serializable JavaDoc remove(String JavaDoc category, Serializable JavaDoc key)
262          throws Exception JavaDoc {
263       return remove(category, key, true);
264    }
265
266    /*
267     * (non-Javadoc)
268     *
269     * @see org.jboss.ha.framework.interfaces.DistributedState#remove(java.lang.String,
270     * java.io.Serializable, boolean) @param asynchronousCall is not
271     * supported yet. TreeCache cannot switch this on the fly. Will take
272     * value from TreeCache-config instead. @return returns null in case of
273     * CacheException!
274     */

275    public Serializable JavaDoc remove(String JavaDoc category, Serializable JavaDoc key,
276          boolean asynchronousCall) throws Exception JavaDoc {
277       Serializable JavaDoc retVal = get(category, key);
278       if(retVal != null){
279          cache.remove(buildFqn(category), key);
280          notifyKeyListenersOfRemove(category, key, retVal, true);
281       }
282
283         return retVal;
284     }
285
286    /*
287      * (non-Javadoc)
288      *
289      * @see org.jboss.ha.framework.interfaces.DistributedState#get(java.lang.String,
290      * java.io.Serializable)
291      */

292    public Serializable JavaDoc get(String JavaDoc category, Serializable JavaDoc key) {
293       try {
294          return (Serializable JavaDoc) cache.get(buildFqn(category), key);
295       } catch (CacheException ce) {
296          return null;
297         }
298
299     }
300
301    public Collection JavaDoc getAllCategories ()
302    {
303       try {
304          Node base = cache.getChild(ROOTFQN);
305          Collection JavaDoc keys = (base == null ? null : base.getChildrenNames());
306          if(keys != null && keys.size() > 0) {
307             keys = Collections.unmodifiableCollection(keys);
308          }
309          return keys;
310       }
311       catch(CacheException ce) {
312          return null;
313       }
314    }
315
316    /*
317      * (non-Javadoc)
318      *
319      * @see org.jboss.ha.framework.interfaces.DistributedState#getAllKeys(java.lang.String)
320      * @return - returns null in case of CacheException
321      */

322    public Collection JavaDoc getAllKeys(String JavaDoc category) {
323       try {
324          Node nodeLogger = getLogger(category);
325          if (nodeLogger==null)
326             return null;
327          return nodeLogger.getKeys();
328       } catch (CacheException ce) {
329          return null;
330         }
331     }
332
333    /*
334      * (non-Javadoc)
335      *
336      * @see org.jboss.ha.framework.interfaces.DistributedState#getAllValues(java.lang.String)
337      * @return - returns null in case of CacheException
338      */

339    public Collection JavaDoc getAllValues(String JavaDoc category) {
340       try {
341          Node categoryNode = getLogger(category);
342          if (categoryNode == null) {
343             return null;
344          }
345          Set JavaDoc childNodes = categoryNode.getKeys();
346          if (childNodes == null) {
347             return null;
348          }
349          Map JavaDoc entries = categoryNode.getData();
350          if (entries == null)
351             return null;
352          Collection JavaDoc retVal = new HashSet JavaDoc(entries.values());
353          return Collections.unmodifiableCollection(retVal);
354       } catch (CacheException ce) {
355          return null;
356         }
357     }
358
359
360    public void registerDSListenerEx (String JavaDoc category, DSListenerEx subscriber)
361    {
362       registerListener(category, subscriber);
363    }
364    public void unregisterDSListenerEx (String JavaDoc category, DSListenerEx subscriber)
365    {
366       unregisterListener(category, subscriber);
367    }
368    public void registerDSListener (String JavaDoc category, DSListener subscriber)
369    {
370       registerListener(category, subscriber);
371    }
372    public void unregisterDSListener (String JavaDoc category, DSListener subscriber)
373    {
374       unregisterListener(category, subscriber);
375    }
376
377    // Package protected ---------------------------------------------
378

379    // Protected -----------------------------------------------------
380

381    protected void registerListener (String JavaDoc category, Object JavaDoc subscriber)
382    {
383       synchronized(this.keyListeners)
384       {
385          ArrayList JavaDoc listeners = (ArrayList JavaDoc)keyListeners.get (category);
386          if (listeners == null)
387          {
388             listeners = new ArrayList JavaDoc ();
389             keyListeners.put (category, listeners);
390          }
391          listeners.add (subscriber);
392       }
393    }
394
395    protected void unregisterListener (String JavaDoc category, Object JavaDoc subscriber)
396    {
397       synchronized(this.keyListeners)
398       {
399          ArrayList JavaDoc listeners = (ArrayList JavaDoc)keyListeners.get (category);
400          if (listeners == null) return;
401
402          listeners.remove (subscriber);
403          if (listeners.size () == 0)
404          {
405             keyListeners.remove (category);
406          }
407       }
408    }
409
410    protected void notifyKeyListeners (String JavaDoc category, Serializable JavaDoc key,
411                                       Serializable JavaDoc value, boolean locallyModified)
412    {
413       synchronized(this.keyListeners)
414       {
415          ArrayList JavaDoc listeners = (ArrayList JavaDoc)keyListeners.get (category);
416          if (listeners == null)
417             return;
418          String JavaDoc strKey = key.toString();
419
420          for (int i = 0; i < listeners.size (); i++)
421          {
422             Object JavaDoc listener = listeners.get (i);
423             if( listener instanceof DSListener )
424             {
425                DSListener dslistener = (DSListener) listener;
426                dslistener.valueHasChanged (category, strKey, value, locallyModified);
427             }
428             else
429             {
430                DSListenerEx dslistener = (DSListenerEx) listener;
431                dslistener.valueHasChanged (category, key, value, locallyModified);
432             }
433          }
434       }
435    }
436
437    protected void notifyKeyListenersOfRemove (String JavaDoc category, Serializable JavaDoc key,
438                                               Serializable JavaDoc oldContent, boolean locallyModified)
439    {
440       synchronized(this.keyListeners)
441       {
442          ArrayList JavaDoc listeners = (ArrayList JavaDoc)keyListeners.get (category);
443          if (listeners == null)
444             return;
445          String JavaDoc strKey = key.toString();
446
447          for (int i = 0; i < listeners.size (); i++)
448          {
449             Object JavaDoc listener = listeners.get (i);
450             if( listener instanceof DSListener )
451             {
452                DSListener dslistener = (DSListener) listener;
453                dslistener.keyHasBeenRemoved (category, strKey, oldContent, locallyModified);
454             }
455             else
456             {
457                DSListenerEx dslistener = (DSListenerEx) listener;
458                dslistener.keyHasBeenRemoved (category, key, oldContent, locallyModified);
459             }
460          }
461       }
462    }
463
464    protected void cleanupKeyListeners ()
465    {
466       // NOT IMPLEMENTED YET
467
}
468
469    /** ExtendedTreeCacheListener methods */
470
471
472    // Private -------------------------------------------------------
473
protected Fqn buildFqn(String JavaDoc category) {
474       return new Fqn(ROOTFQN, category);
475    }
476
477    protected Fqn buildFqn(String JavaDoc category, Serializable JavaDoc key) {
478       return new Fqn(new Object JavaDoc[] { ROOT, category, key });
479    }
480
481    protected Fqn buildFqn(String JavaDoc category, Serializable JavaDoc key, Serializable JavaDoc value) {
482       return new Fqn(new Object JavaDoc[] { ROOT, category, key, value });
483    }
484
485    // FIXME Why is this method named "getLogger"??? Suspect a bug here!
486
protected Node getLogger(String JavaDoc category) throws CacheException {
487       return cache.getChild(buildFqn(category));
488    }
489
490    // Inner classes -------------------------------------------------
491

492    private class DSCacheListener extends AbstractCacheListener
493    {
494       /**
495        * Called when a node is about to be evicted or has been evicted from the
496        * in-memory cache.
497        * Note: Currently TreeCacheListener has {@link TreeCacheListener#nodeEvicted(Fqn)}
498        * which will be merged with method in release 1.3.
499        *
500        * @param fqn
501        * @param pre
502        * @see TreeCacheListener#nodeEvicted(Fqn)
503        */

504       public void nodeEvict(Fqn fqn, boolean pre) {}
505
506       /**
507        * Called when a node is about to be removed or has been removed from the
508        * in-memory cache.
509        * Note: Currently TreeCacheListener has {@link TreeCacheListener#nodeRemoved(Fqn)}
510        * which will be merged with this method in release 1.3.
511        *
512        * @param fqn
513        * @param pre
514        * @param isLocal
515        * @see TreeCacheListener#nodeRemoved(Fqn)
516        *
517        * FIXME JBAS-3473
518        */

519       public void nodeRemove(Fqn fqn, boolean pre, boolean isLocal) {
520          // we're not interested in pre events or changes to another root in a shared cache instance
521
// we're also not interested in local changes as we issue our own notification
522
if (isLocal || pre || !fqn.isChildOf(ROOTFQN))
523             return;
524          
525          // this logic currently doesn't work because key isn't stored as a node
526
/*
527          if (fqn.size() == ROOTFQNSIZE + 2) {
528             String category = (String) fqn.get(ROOTFQNSIZE);
529             Serializable key = (Serializable) fqn.get(ROOTFQNSIZE + 1);
530             try
531             {
532                Serializable value = (Serializable) cache.get(fqn);
533                // show value about to be deleted
534                notifyKeyListenersOfRemove(category, key, value, isLocal);
535             }
536             catch (CacheException e)
537             {
538                log.error("Caught exception getting value for category " + category +
539                          ", key " + key);
540             }
541          }
542          */

543          // for now, just return category name
544
DistributedStateImpl.this.notifyKeyListenersOfRemove((String JavaDoc)fqn.get(ROOTFQNSIZE), "", "", isLocal);
545       }
546
547       /**
548        * Called when a node is about to be modified or has been modified.
549        * Note: Currently TreeCacheListener has {@link TreeCacheListener#nodeModified(Fqn)}
550        * which will be merged with this method in release 1.3.
551        *
552        * @param fqn
553        * @param pre
554        * @param isLocal
555        * @see TreeCacheListener#nodeModified(Fqn)
556        */

557       public void nodeModify(Fqn fqn, boolean pre, boolean isLocal) {
558          // we're not interested in pre events or changes to another root in a shared cache instance
559
// we're also not interested in local changes as we issue our own notification
560
if (isLocal || pre || !fqn.isChildOf(ROOTFQN))
561             return;
562          
563          // this logic currently doesn't work because key isn't stored as a node
564
/*
565          if (fqn.size() == ROOTFQNSIZE + 2) {
566             String category = (String) fqn.get(ROOTFQNSIZE);
567             Serializable key = (Serializable)fqn.get(ROOTFQNSIZE + 1);
568             try
569             {
570                Serializable value = (Serializable) cache.get(fqn);
571                
572                if (value != null) { // show new value
573                   notifyKeyListeners(category, key, value, isLocal);
574                }
575             }
576             catch (CacheException e)
577             {
578                log.error("Caught exception getting value for category " + category +
579                          ", key " + key);
580             }
581          }
582          */

583          // for now, just return category name
584
DistributedStateImpl.this.notifyKeyListeners((String JavaDoc)fqn.get(ROOTFQNSIZE), "", "", isLocal);
585       }
586    }
587
588 }
589
Popular Tags