KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > cache > UnversionedNode


1 /*
2  * JBoss, Home of Professional Open Source
3  *
4  * Distributable under LGPL license.
5  * See terms of license at gnu.org.
6  */

7 package org.jboss.cache;
8
9 import org.apache.commons.logging.Log;
10 import org.apache.commons.logging.LogFactory;
11 import org.jboss.cache.lock.IdentityLock;
12 import org.jboss.cache.marshall.MethodCall;
13 import org.jboss.cache.marshall.MethodCallFactory;
14 import org.jboss.cache.marshall.MethodDeclarations;
15 import org.jboss.cache.optimistic.DataVersion;
16 import org.jboss.cache.util.MapCopy;
17
18 import java.io.Serializable JavaDoc;
19 import java.util.AbstractSet JavaDoc;
20 import java.util.Collections JavaDoc;
21 import java.util.HashMap JavaDoc;
22 import java.util.HashSet JavaDoc;
23 import java.util.Iterator JavaDoc;
24 import java.util.Map JavaDoc;
25 import java.util.Set JavaDoc;
26 import java.util.concurrent.ConcurrentHashMap JavaDoc;
27
28 /**
29  * Basic data node class.
30  */

31 public class UnversionedNode extends AbstractNode implements NodeSPI
32 {
33
34    /**
35     * Default output indent for printing.
36     */

37    private static final int INDENT = 4;
38
39    /**
40     * Debug log.
41     */

42    private static Log log = LogFactory.getLog(UnversionedNode.class);
43
44    /**
45     * True if all children have been loaded. This is set when CacheImpl.getChildrenNames() is called.
46     */

47    private boolean childrenLoaded = false;
48
49    /**
50     * True if data has been loaded from the cache loader.
51     */

52    private boolean dataLoaded = false;
53
54    /**
55     * Lock manager that manages locks to be acquired when accessing the node inside a transaction. Lazy set just in case
56     * locking is not needed.
57     */

58    private transient IdentityLock lock_ = null;
59
60    /**
61     * A reference of the CacheImpl instance.
62     */

63    private transient CacheImpl cache;
64
65    /**
66     * Map of general data keys to values.
67     */

68    private final Map JavaDoc data = new HashMap JavaDoc();
69
70    /**
71     * Constructs a new node with an FQN of Root.
72     */

73    public UnversionedNode()
74    {
75       this(Fqn.ROOT);
76    }
77
78    /**
79     * Constructs a new node with an FQN.
80     */

81    public UnversionedNode(Fqn fqn)
82    {
83       this.fqn = fqn;
84    }
85
86    /**
87     * Constructs a new node with a name, etc.
88     */

89    public UnversionedNode(Object JavaDoc child_name, Fqn fqn, Map JavaDoc data, CacheSPI cache)
90    {
91       init(child_name, fqn, cache);
92       if (data != null)
93       {
94          this.data.putAll(data);
95       }
96    }
97
98    /**
99     * Constructs a new node with a name, etc.
100     *
101     * @param mapSafe <code>true</code> if param <code>data</code> can safely be directly assigned to this object's
102     * {@link #data} field; <code>false</code> if param <code>data</code>'s contents should be copied into
103     * this object's {@link #data} field.
104     */

105    public UnversionedNode(Object JavaDoc child_name, Fqn fqn, Map JavaDoc data, boolean mapSafe, CacheSPI cache)
106    {
107       init(child_name, fqn, cache);
108       if (data != null)
109       {
110          this.data.putAll(data);// ? is this safe
111
}
112    }
113
114    /**
115     * Initializes with a name and FQN and cache.
116     */

117    private void init(Object JavaDoc child_name, Fqn fqn, CacheSPI cache)
118    {
119       if (cache == null)
120       {
121          throw new IllegalArgumentException JavaDoc("no cache init for " + fqn);
122       }
123       this.cache = (CacheImpl) cache;
124       this.fqn = fqn;
125       if (!fqn.isRoot() && !child_name.equals(fqn.getLastElement()))
126       {
127          throw new IllegalArgumentException JavaDoc("Child " + child_name + " must be last part of " + fqn);
128       }
129    }
130
131    /**
132     * Returns a parent by checking the TreeMap by name.
133     */

134    public NodeSPI getParent()
135    {
136       if (fqn.isRoot())
137       {
138          return null;
139       }
140       return cache.peek(fqn.getParent());
141    }
142
143    private synchronized void initLock()
144    {
145       if (lock_ == null)
146       {
147          lock_ = new IdentityLock(cache.getConfiguration().getIsolationLevel(), this);
148       }
149    }
150
151    private synchronized Map JavaDoc<Object JavaDoc, Node> children()
152    {
153       if (children == null)
154       {
155          if (getFqn().isRoot())
156          {
157             children = new ConcurrentHashMap JavaDoc<Object JavaDoc, Node>(64, .5f, 16);
158          }
159          else
160          {
161             // Less segments to save memory
162
children = new ConcurrentHashMap JavaDoc<Object JavaDoc, Node>(4, .75f, 4);
163          }
164       }
165       return children;
166    }
167
168    public void setCache(CacheSPI cache)
169    {
170       this.cache = (CacheImpl) cache;
171       this.lock_ = null;
172       if (children != null)
173       {
174          for (Node n : children.values())
175          {
176             ((UnversionedNode) n).setCache(cache);
177          }
178       }
179    }
180
181    public CacheSPI getCache()
182    {
183       return cache;
184    }
185
186    public boolean getChildrenLoaded()
187    {
188       return childrenLoaded;
189    }
190
191    public void setChildrenLoaded(boolean flag)
192    {
193       childrenLoaded = flag;
194    }
195
196    public Object JavaDoc get(Object JavaDoc key)
197    {
198       return cache.get(getFqn(), key);
199    }
200
201    public synchronized Object JavaDoc getDirect(Object JavaDoc key)
202    {
203       return data == null ? null : data.get(key);
204    }
205
206
207    private boolean isReadLocked()
208    {
209       return lock_ != null && lock_.isReadLocked();
210    }
211
212    private boolean isWriteLocked()
213    {
214       return lock_ != null && lock_.isWriteLocked();
215    }
216
217    public IdentityLock getLock()
218    {
219       initLock();
220       return lock_;
221    }
222
223    public Map JavaDoc<Object JavaDoc, Object JavaDoc> getData()
224    {
225       if (cache == null) return Collections.emptyMap();
226       Map JavaDoc<Object JavaDoc, Object JavaDoc> dMap = new HashMap JavaDoc<Object JavaDoc, Object JavaDoc>();
227       for (Object JavaDoc k : cache.getKeys(getFqn()))
228       {
229          dMap.put(k, cache.get(fqn, k));
230       }
231       return Collections.unmodifiableMap(dMap);
232    }
233
234    public synchronized Map JavaDoc<Object JavaDoc, Object JavaDoc> getDataDirect()
235    {
236       return new MapCopy(data);
237    }
238
239
240    public Object JavaDoc put(Object JavaDoc key, Object JavaDoc value)
241    {
242       return cache.put(getFqn(), key, value);
243    }
244
245    public synchronized Object JavaDoc putDirect(Object JavaDoc key, Object JavaDoc value)
246    {
247       return data.put(key, value);
248    }
249
250    public NodeSPI getOrCreateChild(Object JavaDoc child_name, GlobalTransaction gtx)
251    {
252       return getOrCreateChild(child_name, gtx, true);
253    }
254
255    private synchronized NodeSPI getOrCreateChild(Object JavaDoc child_name, GlobalTransaction gtx, boolean createIfNotExists)
256    {
257
258       NodeSPI child;
259       if (child_name == null)
260       {
261          throw new IllegalArgumentException JavaDoc("null child name");
262       }
263
264       child = (NodeSPI) children().get(child_name);
265       if (createIfNotExists && child == null)
266       {
267          // construct the new child outside the synchronized block to avoid
268
// spending any more time than necessary in the synchronized section
269
Fqn child_fqn = new Fqn(this.fqn, child_name);
270          NodeSPI newChild = (NodeSPI) cache.getConfiguration().getRuntimeConfig().getNodeFactory().createNode(child_name, this, null);
271          if (newChild == null)
272          {
273             throw new IllegalStateException JavaDoc();
274          }
275          synchronized (this)
276          {
277             // check again to see if the child exists
278
// after acquiring exclusive lock
279
child = (NodeSPI) children().get(child_name);
280             if (child == null)
281             {
282                cache.getNotifier().notifyNodeCreated(child_fqn, true, true);
283                child = newChild;
284                children.put(child_name, child);
285                if (gtx != null)
286                {
287                   MethodCall undo_op = MethodCallFactory.create(MethodDeclarations.removeNodeMethodLocal, gtx,
288                           child_fqn, false);
289                   cache.addUndoOperation(gtx, undo_op);
290                   // add the node name to the list maintained for the current tx
291
// (needed for abort/rollback of transaction)
292
// cache.addNode(gtx, child.getFqn());
293
}
294             }
295          }
296
297          // notify if we actually created a new child
298
if (newChild == child)
299          {
300             if (log.isTraceEnabled())
301             {
302                log.trace("created child: fqn=" + child_fqn);
303             }
304             cache.getNotifier().notifyNodeCreated(child_fqn, false, true);
305          }
306       }
307       return child;
308
309    }
310
311    public Object JavaDoc remove(Object JavaDoc key)
312    {
313       return cache.remove(getFqn(), key);
314    }
315
316    public synchronized Object JavaDoc removeDirect(Object JavaDoc key)
317    {
318       if (data == null) return null;
319       return data.remove(key);
320    }
321
322    public void printDetails(StringBuffer JavaDoc sb, int indent)
323    {
324       printDetailsInMap(sb, indent);
325    }
326
327    /**
328     * Returns a debug string.
329     */

330    @Override JavaDoc
331    public String JavaDoc toString()
332    {
333       StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
334       sb.append(getClass().getSimpleName());
335       if (deleted)
336       {
337          sb.append(" (deleted) [ ").append(fqn);
338       }
339       else
340       {
341          sb.append("[ ").append(fqn);
342       }
343       synchronized (this)
344       {
345          if (data != null)
346          {
347             sb.append(" data=").append(data.keySet());
348          }
349       }
350       if (children != null && !children.isEmpty())
351       {
352          sb.append(" child=").append(getChildrenDirect(false));
353       }
354       if (lock_ != null)
355       {
356          if (isReadLocked())
357          {
358             sb.append(" RL");
359          }
360          if (isWriteLocked())
361          {
362             sb.append(" WL");
363          }
364       }
365       sb.append("]");
366       return sb.toString();
367    }
368
369    public Node addChild(Fqn f)
370    {
371       Fqn nf = new Fqn(getFqn(), f);
372       cache.put(nf, null);
373       return getChild(f);
374    }
375
376    public NodeSPI addChildDirect(Fqn f)
377    {
378       if (f.size() == 1)
379       {
380          GlobalTransaction gtx = cache.getInvocationContext().getGlobalTransaction();
381          return getOrCreateChild(f.getLastElement(), gtx);
382       }
383       else
384       {
385          throw new UnsupportedOperationException JavaDoc("Cannot directly create children which aren't directly under the current node.");
386       }
387
388    }
389
390    public void clearData()
391    {
392       cache.removeData(getFqn());
393    }
394
395    public synchronized void clearDataDirect()
396    {
397       if (data != null) data.clear();
398    }
399
400    public Node getChild(Fqn fqn)
401    {
402       return cache.get(new Fqn(getFqn(), fqn));
403    }
404
405    public NodeSPI getChildDirect(Fqn fqn)
406    {
407       if (fqn.size() == 1)
408       {
409          return getChildDirect(fqn.getLastElement());
410       }
411       else
412       {
413          NodeSPI currentNode = this;
414          for (int i = 0; i < fqn.size(); i++)
415          {
416             Object JavaDoc nextChildName = fqn.get(i);
417             currentNode = currentNode.getChildDirect(nextChildName);
418             if (currentNode == null) return null;
419          }
420          return currentNode;
421       }
422    }
423
424    public Set JavaDoc<Object JavaDoc> getChildrenNames()
425    {
426       return cache.getChildrenNames(getFqn());
427    }
428
429    public Set JavaDoc<Object JavaDoc> getChildrenNamesDirect()
430    {
431       return Collections.unmodifiableSet(new HashSet JavaDoc(new ChildrenNames()));
432    }
433
434    public Set JavaDoc<Object JavaDoc> getKeys()
435    {
436       Set JavaDoc keys = cache.getKeys(getFqn());
437       return keys == null ? Collections.emptySet() : Collections.unmodifiableSet(keys);
438    }
439
440    public synchronized Set JavaDoc<Object JavaDoc> getKeysDirect()
441    {
442       if (data == null)
443       {
444          return Collections.emptySet();
445       }
446       return Collections.unmodifiableSet(new HashSet JavaDoc(data.keySet()));
447    }
448
449    public boolean hasChild(Fqn f)
450    {
451       return cache.exists(new Fqn(getFqn(), f));
452    }
453
454    public void putIfAbsent(Object JavaDoc k, Object JavaDoc v)
455    {
456       throw new UnsupportedOperationException JavaDoc("This operation was only added in 2.0.0 to finalise the API. This will not be implemented till 2.1.0.");
457    }
458
459    public void putIfAbsent(Map JavaDoc m)
460    {
461       throw new UnsupportedOperationException JavaDoc("This operation was only added in 2.0.0 to finalise the API. This will not be implemented till 2.1.0.");
462    }
463
464    public void removeChild(Fqn fqn)
465    {
466       cache.removeNode(new Fqn(getFqn(), fqn));
467    }
468
469    public void removeChild(Object JavaDoc childName)
470    {
471       removeChild(new Fqn(getFqn(), childName));
472    }
473
474    public synchronized void removeChildDirect(Object JavaDoc childName)
475    {
476       children().remove(childName);
477    }
478
479    public void removeChildDirect(Fqn f)
480    {
481       if (f.size() == 1)
482       {
483          removeChildDirect(f.getLastElement());
484       }
485       else
486       {
487          NodeSPI child = getChildDirect(f);
488          if (child != null) child.getParent().removeChildDirect(f.getLastElement());
489       }
490    }
491
492    public synchronized Map JavaDoc<Object JavaDoc, Node> getChildrenMapDirect()
493    {
494       return new MapCopy(children());
495    }
496
497    public synchronized void setChildrenMapDirect(Map JavaDoc<Object JavaDoc, Node> children)
498    {
499       this.children().clear();
500       this.children.putAll(children);
501    }
502
503    public void put(Map JavaDoc data)
504    {
505       cache.put(fqn, data);
506    }
507
508    public synchronized void putDirect(Map JavaDoc data)
509    {
510       if (data == null) return;
511       this.data.putAll(data);
512    }
513
514    public synchronized void removeChildrenDirect()
515    {
516       if (children != null)
517       {
518          children.clear();
519       }
520       children = null;
521    }
522
523    public void print(StringBuffer JavaDoc sb, int indent)
524    {
525       printIndent(sb, indent);
526       sb.append(Fqn.SEPARATOR).append(getName()).append(" ").append(getDataDirect().size());
527       if (children != null)
528       {
529          for (Node node : children.values())
530          {
531             sb.append("\n");
532             ((NodeSPI) node).print(sb, indent + INDENT);
533          }
534       }
535    }
536
537    // versioning
538

539    public void setVersion(DataVersion version)
540    {
541       throw new UnsupportedOperationException JavaDoc("Versioning not supported");
542    }
543
544    public DataVersion getVersion()
545    {
546       throw new UnsupportedOperationException JavaDoc("Versioning not supported");
547    }
548
549    private void printIndent(StringBuffer JavaDoc sb, int indent)
550    {
551       if (sb != null)
552       {
553          for (int i = 0; i < indent; i++)
554          {
555             sb.append(" ");
556          }
557       }
558    }
559
560    public void addChild(Object JavaDoc child_name, Node n)
561    {
562       if (child_name != null)
563       {
564          children().put(child_name, n);
565       }
566    }
567
568    /**
569     * Returns the name of this node.
570     */

571    private Object JavaDoc getName()
572    {
573       return fqn.getLastElement();
574    }
575
576    /**
577     * Returns the name of this node.
578     */

579    public Fqn getFqn()
580    {
581       return fqn;
582    }
583
584    public void setFqn(Fqn fqn)
585    {
586       if (log.isTraceEnabled())
587       {
588          log.trace(getFqn() + " set FQN " + fqn);
589       }
590       this.fqn = fqn;
591
592       if (children == null)
593       {
594          return;
595       }
596
597       // process children
598
for (Map.Entry JavaDoc<Object JavaDoc, ? extends Node> me : children.entrySet())
599       {
600          NodeSPI n = (NodeSPI) me.getValue();
601          Fqn cfqn = new Fqn(fqn, me.getKey());
602          n.setFqn(cfqn);
603       }
604    }
605
606    public Node getChild(Object JavaDoc childName)
607    {
608       return cache.get(new Fqn(getFqn(), childName));
609    }
610
611    public synchronized NodeSPI getChildDirect(Object JavaDoc childName)
612    {
613       if (childName == null) return null;
614       return (NodeSPI) (children == null ? null : children.get(childName));
615    }
616
617    public Set JavaDoc<Node> getChildren()
618    {
619       if (cache == null) return Collections.emptySet();
620       Set JavaDoc<Node> children = new HashSet JavaDoc<Node>();
621       for (Object JavaDoc c : cache.getChildrenNames(getFqn()))
622       {
623          Node n = cache.get(new Fqn(getFqn(), c));
624          if (n != null) children.add(n);
625       }
626       return Collections.unmodifiableSet(children);
627    }
628
629    public synchronized Set JavaDoc<NodeSPI> getChildrenDirect()
630    {
631       // strip out deleted child nodes...
632
if (children == null || children.size() == 0) return Collections.emptySet();
633
634       Set JavaDoc<NodeSPI> exclDeleted = new HashSet JavaDoc<NodeSPI>();
635       for (Node n : children.values())
636       {
637          NodeSPI spi = (NodeSPI) n;
638          if (!spi.isDeleted()) exclDeleted.add(spi);
639       }
640       return Collections.unmodifiableSet(exclDeleted);
641    }
642
643    public synchronized Set JavaDoc<NodeSPI> getChildrenDirect(boolean includeMarkedForRemoval)
644    {
645       if (includeMarkedForRemoval)
646       {
647          if (children != null && !children.isEmpty())
648          {
649             return Collections.unmodifiableSet(new HashSet JavaDoc(children.values()));
650          }
651          else
652          {
653             return Collections.emptySet();
654          }
655       }
656       else
657       {
658          return getChildrenDirect();
659       }
660    }
661
662    /**
663     * Adds details of the node into a map as strings.
664     */

665    private void printDetailsInMap(StringBuffer JavaDoc sb, int indent)
666    {
667       printIndent(sb, indent);
668       indent += 2;// increse it
669
if (!(getFqn()).isRoot())
670       {
671          sb.append(Fqn.SEPARATOR);
672       }
673       sb.append(getName());
674       sb.append(" ");
675       sb.append(data);
676       if (children != null)
677       {
678          for (Node n : children.values())
679          {
680             sb.append("\n");
681             ((NodeSPI) n).printDetails(sb, indent);
682          }
683       }
684    }
685
686    /**
687     * Returns true if the data was loaded from the cache loader.
688     */

689    public boolean getDataLoaded()
690    {
691       return dataLoaded;
692    }
693
694    /**
695     * Sets if the data was loaded from the cache loader.
696     */

697    public void setDataLoaded(boolean dataLoaded)
698    {
699       this.dataLoaded = dataLoaded;
700    }
701
702    private class ChildrenNames extends AbstractSet JavaDoc implements Serializable JavaDoc
703    {
704
705       /**
706        * Since writeReplace() returns a different class, this isn't really necessary.
707        */

708       private static final long serialVersionUID = 5468697840097489795L;
709
710       @Override JavaDoc
711       public Iterator JavaDoc iterator()
712       {
713          if (children == null)
714          {
715             return Collections.emptySet().iterator();
716          }
717          return children.keySet().iterator();
718       }
719
720       @Override JavaDoc
721       public boolean contains(Object JavaDoc o)
722       {
723          return children != null && children.containsKey(o);
724       }
725
726       @Override JavaDoc
727       public int size()
728       {
729          if (children == null)
730          {
731             return 0;
732          }
733          return children.size();
734       }
735
736       private Object JavaDoc writeReplace()
737       {
738          if (children == null)
739          {
740             return Collections.emptySet();
741          }
742          return Collections.unmodifiableSet(new HashSet JavaDoc(children.keySet()));
743       }
744
745    }
746
747    /*
748    private class ChildrenNodes<T> extends AbstractSet
749    {
750       private boolean includeDeleted;
751
752       public ChildrenNodes(boolean includeDeleted)
753       {
754          this.includeDeleted = includeDeleted;
755       }
756
757       @Override
758       public boolean contains(Object o)
759       {
760          return children != null && children.containsValue(o);
761       }
762
763       @Override
764       public Iterator iterator()
765       {
766          if (children == null)
767          {
768             return Collections.emptySet().iterator();
769          }
770          return children.values().iterator();
771       }
772
773       // although the map is empty
774       @Override
775       public void clear()
776       {
777          throw new UnsupportedOperationException();
778       }
779
780       @Override
781       public int size()
782       {
783          if (children == null)
784          {
785             return 0;
786          }
787          return children.size();
788       }
789
790    }
791    */

792
793 }
794
Popular Tags