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 }