View Javadoc

1   /*   Open Source Java Caching Service
2    *    Copyright (C) 2002 Frank Karlstrøm
3    *    This library is free software; you can redistribute it and/or
4    *    modify it under the terms of the GNU Lesser General Public
5    *    License as published by the Free Software Foundation; either
6    *    version 2.1 of the License, or (at your option) any later version.
7    *
8    *    This library is distributed in the hope that it will be useful,
9    *    but WITHOUT ANY WARRANTY; without even the implied warranty of
10   *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11   *    Lesser General Public License for more details.
12   *
13   *    You should have received a copy of the GNU Lesser General Public
14   *    License along with this library; if not, write to the Free Software
15   *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16   *
17   *    The author can be contacted by email: fjankk@users.sourceforge.net
18   */
19  package org.fjank.jcache;
20  
21  import java.io.Serializable;
22  import java.util.Collection;
23  import java.util.HashMap;
24  import java.util.Iterator;
25  import java.util.Map;
26  import java.util.Set;
27  import org.fjank.jcache.collection.CollectionProxy;
28  import org.fjank.jcache.collection.SetProxy;
29  import EDU.oswego.cs.dl.util.concurrent.ConcurrentHashMap;
30  
31  /**
32   * Class for representin grouops in the cache. Groups can contain CacheObjects
33   * and other groups.
34   *
35   * @author Frank Karlstrøm
36   */
37  public class CacheGroup implements Serializable {
38      /** the name of this group. */
39      protected String name;
40      /** the attributes for this group */
41      private AttributesImpl attributes = new AttributesImpl();
42      /** the current number of objects in this group. */
43      private int currentSize;
44      /** The number of objects in this group*/
45      private int objectCount;
46      /** the WeakReference objects in this group. */
47      protected transient Map weakReferenceObjects = new ConcurrentHashMap();
48      private transient final Map groups = new HashMap();
49      /** the actual objects in this group. These objects are here until they expire
50       * when they have expired, this map is cleared, 
51       * then the weakReference is also cleared, if and only if no other
52       * code references the objects. */
53      final transient Map objects = new ConcurrentHashMap();
54  
55      Map getGroups() {
56          return groups;
57      }
58  
59      /**
60       * Creates a new CacheGroup object.
61       *
62       * @param name the name of the CacheGroup to create
63       */
64      public CacheGroup(final String name) {
65          this(name, null);
66      }
67  
68      /**
69       * Creates a new CacheGroup object.
70       *
71       * @param name the name of the CacheGroup to create
72       * @param attributes the attributes of the group to create
73       */
74      public CacheGroup(final String name, final AttributesImpl attributes) {
75          setName(name);
76          setAttributes(attributes);
77      }
78  
79      /**
80       * sets the attribute for this group
81       *
82       * @param attributes the attributes to set.
83       */
84      private void setAttributes(final AttributesImpl attributes) {
85          if (attributes == null) {
86              return;
87          }
88          this.attributes = attributes;
89      }
90  
91      /**
92       * sets the name of this group.
93       *
94       * @param name the name to set.
95       */
96      private void setName(final String name) {
97          this.name = name;
98      }
99  
100     /**
101      * gets an object from this group.
102      *
103      * @param name the name of the object to retrieve.
104      *
105      * @return the named object, or null if it is not found.
106      *
107      */
108     public Object get(final Object aName) {
109         //      2004/09-FB
110         if ((aName != null) && aName.equals(name)) {
111             return this;
112         }
113         Object obj = weakReferenceObjects.get(aName);
114         if (obj == null) {
115             //      2004/09-FB
116             for (Iterator iter = groups.keySet().iterator(); iter.hasNext();) {
117                 Object groupName = iter.next();
118                 CacheGroup group = (CacheGroup) groups.get(groupName);
119                 obj = group.get(aName);
120                 if (obj != null) {
121                     return obj;
122                 }
123             }
124         }
125         return obj;
126     }
127 
128     /**
129      * puts the named object into this group.
130      *
131      * @param name the name of the object
132      * @param object the object to insert.
133      *
134      */
135     public void put(final Object name, final CacheObject object, final Object realObject) {
136         currentSize += object.getAttributes().getSize();
137         increaseObjectCount();
138         weakReferenceObjects.put(name, object);
139         objects.put(name, realObject);
140     }
141 
142     /**
143      * puts the group into this group
144      *
145      * @param object the group to put.
146      *
147      */
148     public void put(final CacheGroup group) {
149         currentSize += group.getAttributes().getSize();
150         groups.put(group.getName(), group);
151     }
152 
153     /**
154      * returns the attributes for this group.
155      *
156      * @return the attributes for this group.
157      */
158     AttributesImpl getAttributes() {
159         return this.attributes;
160     }
161 
162     /**
163      * Will create a new version of the object indentified by the name,
164      * replacing the current version with the object specified. If the object
165      * doesn't exist in the cache, replace is equivalent to a put. The
166      * attributes will be inherited from the existing object or if no object
167      * exists, from the group or region the object associated with. Names are
168      * in the scope of a region so they must be unique within the region they
169      * are placed. This method is not valid on a disk, StreamAccess or Group
170      * Object.
171      *
172      * @param name the name of the object to replace.
173      * @param object The new object to be put in the cache.
174      *
175      * @return a reference to the newly replaced object.
176      */
177     public CacheObject replace(final Object name, final CacheObject object) {
178         CacheObject oldObj = (CacheObject) weakReferenceObjects.get(name);
179         if (oldObj != null) {
180             if (oldObj.getAttributes() != null) {
181                 object.setAttributes(oldObj.getAttributes());
182             }
183             weakReferenceObjects.remove(name);
184             objects.remove(name);
185         } else {
186             increaseObjectCount();
187         }
188         weakReferenceObjects.put(name, object);
189         objects.put(name, object.get());
190         return object;
191     }
192 
193     /**
194      * Setter for property valid.
195      */
196     public void invalidate() {
197         Iterator iter = weakReferenceObjects.keySet().iterator();
198         while (iter.hasNext()) {
199             Object key = iter.next();
200             CacheObject obj = (CacheObject) weakReferenceObjects.get(key);
201             obj.invalidate();
202         }
203         objects.clear();
204         iter = groups.keySet().iterator();
205         while (iter.hasNext()) {
206             Object key = iter.next();
207             CacheGroup obj = (CacheGroup) groups.get(key);
208             obj.invalidate();
209         }
210         this.objectCount = 0;
211     }
212 
213     /**
214      * Destroys this group and all its children.
215      *
216      */
217     public void destroy() {
218         this.attributes = null;
219         this.currentSize = 0;
220         this.name = null;
221         for (Iterator iter = weakReferenceObjects.keySet().iterator(); iter.hasNext();) {
222             ((CacheObject) weakReferenceObjects.get(iter.next())).destroy();
223         }
224         for (Iterator iter = groups.keySet().iterator(); iter.hasNext();) {
225             ((CacheGroup) groups.get(iter.next())).destroy();
226         }
227         weakReferenceObjects.clear();
228         objects.clear();
229         groups.clear();
230         weakReferenceObjects = null;
231     }
232 
233     /**
234      * Checks wether this group contains the specified objects
235      * @param aName the name of the object to check
236      *
237      * @return a boolean indicating wether the object was present or not in
238      *         this group.
239      */
240     public boolean contains(final Object aName) {
241         if ((aName != null) && aName.equals(name)) {
242             return true;
243         }
244         //check the real objects instead.
245         if (objects.containsKey(aName))
246             return true;
247         //        for(Iterator iter = weakReferenceObjects.keySet().iterator();iter.hasNext();) {
248         //			CacheObject obj = (CacheObject)weakReferenceObjects.get(iter.next());
249         //            if ((obj.getKey() != null)
250         //                && obj.getKey().equals(aName)) {
251         //                return true;
252         //            }
253         //        }
254         for (Iterator iter = groups.keySet().iterator(); iter.hasNext();) {
255             Object groupName = iter.next();
256             CacheGroup group = (CacheGroup) groups.get(groupName);
257             if (group.contains(aName)) {
258                 return true;
259             }
260         }
261         return false;
262     }
263 
264     /**
265      * removes the object from this group.
266      *
267      * @param object the object to remove.
268      */
269     public void removeMe(final CacheObject object) {
270         Iterator iter = weakReferenceObjects.keySet().iterator();
271         while (iter.hasNext()) {
272             if (((CacheObject) weakReferenceObjects.get(iter.next())) == object) {
273                 iter.remove();
274                 objects.remove(object.getKey());
275                 decreaseObjectCount();
276                 currentSize -= object.getAttributes().getSize();
277                 break;
278             }
279         }
280     }
281 
282     private void decreaseObjectCount() {
283         this.objectCount = objectCount - 1;
284     }
285 
286     private void increaseObjectCount() {
287         this.objectCount = objectCount + 1;
288     }
289 
290     /**
291      * gets the current size (in bytes) of th3e objects in this group.
292      *
293      * @return the current size (in bytes) of th3e objects in this group.
294      */
295     int getCurrentSize() {
296         return currentSize;
297     }
298 
299     /**
300      * gets the named group from this group.
301      * If no group with the specified name is found, <code>null</code> is returned.
302      * @param group the group to get.
303      *
304      * @return the named group.
305      *
306      */
307     public CacheGroup getGroup(final String group) {
308         return (CacheGroup) groups.get(group);
309     }
310 
311     /**
312      * gets the name of this group.
313      *
314      * @return the name of this group.
315      */
316     public String getName() {
317         return name;
318     }
319 
320     /** Return the current number of objects in this group.
321      * @return the current number of objects in this group.
322      */
323     public int getObjectCount() {
324         if (groups.isEmpty()) {
325             return objectCount;
326         }
327         int count = objectCount;
328         for (Iterator iter = groups.keySet().iterator(); iter.hasNext();) {
329             Object key = iter.next();
330             CacheGroup gr = (CacheGroup) groups.get(key);
331             count += gr.getObjectCount();
332         }
333         return count;
334     }
335 
336     /**returns a boolean indicating wether this value is present 
337      * in the cache root.
338      * @param value the value to check
339      * @return <code>true</code> if the value is present, <code>false</code> otherwise.
340      */
341     public boolean containsValue(Object value) {
342         return objects.containsValue(value);
343     }
344 
345     public Set keySet() {
346         return new SetProxy(weakReferenceObjects.keySet(), this);
347     }
348 
349     public Collection values() {
350         return new CollectionProxy(weakReferenceObjects.values(), this);
351     }
352 
353     public Set entrySet() {
354         return new SetProxy(weakReferenceObjects.entrySet(), this);
355     }
356 
357     void removeObjectReference(Object key) {
358         //if(objects.containsKey(key)) {
359         objects.remove(key);
360         //decreaseObjectCount();
361         //}
362     }
363 
364     Map getObjectReferences() {
365         return objects;
366     }
367 }