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.File;
22 import java.io.Serializable;
23 import java.util.Iterator;
24 import javax.util.jcache.Attributes;
25 import javax.util.jcache.CacheException;
26 import javax.util.jcache.CacheFullException;
27 import javax.util.jcache.CacheLoader;
28 import javax.util.jcache.CacheLogger;
29 import javax.util.jcache.DiskCacheException;
30 import javax.util.jcache.NotARetrievableObjectException;
31 import javax.util.jcache.ObjectNotFoundException;
32 import org.fjank.jcache.persistence.DiskCache;
33
34
35 /**
36 * An optimized implementation of CacheAccess.
37 * No exceptions is thrown excpet in really exceptional situations.
38 * The Map interface uses this class directly,
39 * while the old CacheAccessImpl interface should be reprogrammed
40 * to work with this class.
41 */
42 public final class CacheAccessImpl2 {
43 /** a boolean indication wether this obejct is valid or not. */
44 private boolean valid = true;
45 /** the current region this CacheAccess applies to. */
46 private CacheRegion region;
47 private Class lastException;
48 private String lastMessage;
49
50 /**
51 * Creates a new CacheAccessImpl object.
52 *
53 * @param aCache the the cahce the region belopngs to.
54 * @param aRegion the region to get an CacheAccessImpl to.
55 */
56 CacheAccessImpl2(final CacheRegion aRegion) {
57 this.region = aRegion;
58 }
59
60 /**
61 * terminates the request for a reply from the previous invalidate or
62 * update. If a response was requested, the either cancelResponse or
63 * waitForResponse should be called to terminate the request and free up
64 * related structures. If the waitForResponse method times out,
65 * cancelResponse should be called. All response associated with the
66 * CacheAccess object are canceled. If the object is local or a reply has
67 * not been requested, this call returns immediantely.
68 * @todo Implement me.
69 */
70 public void cancelResponse() {
71 if (!isValid()) {
72 return;
73 }
74 }
75
76 /**
77 * Will check if close() has been called.
78 * @return <code>true</code> if this CacheAccess is valid, <code>false</code>
79 * otherwise.
80 */
81 private boolean isValid() {
82 if (this.valid) {
83 return true;
84 }
85 return false;
86 }
87
88 /**
89 * will return the CacheAccess object to the cache. Any attempt to use a
90 * CacheAccess object after it has been closed will be ignored.
91 */
92 public void close() {
93 if (!isValid()) {
94 return;
95 }
96 region = null;
97 this.valid = false;
98 }
99
100 /**
101 * Is used to create a new group object. The attributes of the region or
102 * group the new group is associated with are used.
103 *
104 * @param name the name of the new group.
105 */
106 public void defineGroup(final String name) {
107 if (!isValid()) {
108 return;
109 }
110 defineGroupImpl(name, null, this.getAttributes());
111 }
112
113 /**
114 * Is used to create a new group object. The attrbutes-parameter are used as
115 * the attributes for the new group.
116 * @param name the group the new group should be associated with.
117 * @param attributes the attributes of the new group.
118 *
119 */
120 public void defineGroup(final String name, final Attributes attributes) {
121 if (!isValid()) {
122 return;
123 }
124 defineGroupImpl(name, null, attributes);
125 }
126
127 /**
128 * Is used to create a new group which belongs to another group.
129 * The attributes of the group the new group is attached to are used
130 * as the attrbutes for the new group.
131 * @param name the name of the new group.
132 * @param group the group the new group should be associated with.
133 *
134 */
135 public void defineGroup(final String name, final String group) {
136 if (!isValid()) {
137 return;
138 }
139 defineGroupImpl(name, group, null);
140 }
141
142 /**
143 * Is used to create a new group which belongs to another group.
144 * The attrbutes-parameter are used as
145 * the attributes for the new group.
146 * @param name the name of the new group.
147 * @param groupName the group the new group should be associated with.
148 * @param attributes the attributes of the new group.
149 */
150 public void defineGroup(final String name, final String groupName, final Attributes attributes) {
151 if (!isValid()) {
152 return;
153 }
154 defineGroupImpl(name, groupName, attributes);
155 }
156
157 /**
158 * The actual implementation of defineGroup.
159 * @param name the name of the group to define.
160 * @param groupName the groupName the group should belong to.
161 * @param attributes the attributes of the new group.
162 */
163 private void defineGroupImpl(final String name, final String groupName, final Attributes attributes) {
164 if (name == null) {
165 return;
166 }
167 if (name.equals("")) {
168 return;
169 }
170 CacheGroup group;
171 if (groupName == null) {
172 group = region;
173 } else {
174 group = region.getGroup(groupName);
175 if (group == null) {
176 return;
177 }
178 }
179 group.put(new CacheGroup(name, new AttributesImpl(attributes)));
180 }
181
182 /**
183 * is used to specify the attributes to associate with an object when it is
184 * loaded. This can include the loader object, cache event handlers, and
185 * spesific attributes for the object such as distribute, spool, etc.
186 * Attributes (with the exception of the CacheLoader object itself) can also
187 * be specified within the load method of the CacheLoader object using the
188 * setAttributes method, if the attributes for an object are not defined,
189 * the attributes of the region will be used.
190 *
191 * @param name the name of the object to associate the attributes with.
192 * @param attributes the attributes to associate.
193 *
194 */
195 public void defineObject(final Object name, final Attributes attributes) {
196 if (!isValid()) {
197 return;
198 }
199 putImpl(name, null, attributes, NullObject.getInstance());
200 }
201
202 /**
203 * See defineObject(Object, Attributes)
204 *
205 * @param name the name of the object to associate the attributes with.
206 * @param group the group the object to associate the attributes with is
207 * contained in.
208 * @param attributes the attributes to associate.
209 *
210 */
211 public void defineObject(final Object name, final String group, final Attributes attributes) {
212 if (!isValid()) {
213 return;
214 }
215 putImpl(name, group, attributes, NullObject.getInstance());
216 }
217
218 /**
219 * Will invalidate all objects within the region for this CacheAccess
220 * object, and the region itself. All references to the objects and any
221 * loaders registered will be destroyed. This object is unusable after this
222 * operation, will be closed and returned to the cache pool.
223 *
224 */
225 public void destroy() {
226 if (!isValid()) {
227 return;
228 }
229 if (region.getName() != null) {
230 destroy(region.getName());
231 } else {
232 region.destroy();
233 }
234 close();
235 }
236
237 /**
238 * Will invalidate all objects in the named region and the named region.
239 *
240 * @param name the name of the region to destroy.
241 *
242 *
243 * @see #destroy()
244 */
245 public void destroy(final Object name) {
246 if (!isValid()) {
247 return;
248 }
249 CacheImpl.getCache(true).destroyRegion(name);
250 }
251
252 /**
253 * Returns a reference to the object accosiated with the specified name. If
254 * the object is a streamAccess object, an {@link java.io.InputStream}is
255 * returned, if the object is a disk object, a {@link java.lang.String}
256 * containg the full path to the object is returned. The name parameter must
257 * override the {@link java.lang.Object#equals(Object)}and {@link
258 * java.lang.Object#hashCode()} methods. If a loader object has not been
259 * registered for the object the default load method will do a netSearch for
260 * the object. A CacheAccess will only maintain a reference to one cached
261 * object at any gived time. If get is called multiple times, the object
262 * accessed previously, will be released.
263 *
264 * @param name the name of the object to get.
265 *
266 * @return a reference to a shared object. Will always return the latest
267 * version of the object.
268 *
269 */
270 public Object get(final Object name) {
271 if (!isValid()) {
272 return null;
273 }
274 return getImpl(name, null, null);
275 }
276
277 /**
278 * Gets the object from the cache. If the object is not currently in the
279 * cache and a loader object has been registered, the object will be loaded
280 * into the cache with the arguments specified.
281 *
282 * @param name the name of the object to get.
283 * @param arguments the arguments wich is passed to the load method of the
284 * CacheLoader, if registered.
285 *
286 * @return a reference to a shared object. Will always return the latest
287 * version of the object.
288 * @see #get(Object)
289 */
290 public Object get(final Object name, final Object arguments) {
291 if (!isValid()) {
292 return null;
293 }
294 return getImpl(name, null, arguments);
295 }
296
297 /**Gets an object from the cache.
298 * @param name the name of the object to get
299 * @param arguments the arguments to send to the loader, if any.
300 * @return the object which is stored in the cache.
301 */
302 private Object getImpl(final Object name, final String group, final Object arguments) {
303 CacheObject objHandle = getCacheObject(name, group);
304 if (objHandle == null) {
305 return null;
306 }
307 return getTrueObject(objHandle, arguments);
308 }
309
310 private Object getTrueObject(final CacheObject objHandle, final Object arguments) {
311 if (objHandle.needsLoading(arguments)) {
312 Attributes attribs = objHandle.getAttributes();
313 CacheLoader loader = attribs.getLoader();
314 Object retrievedObject;
315 try {
316 retrievedObject = loader.load(objHandle, arguments);
317 if (retrievedObject == null) {
318 throw new ObjectNotFoundException("The returned object from the CacheLoader " + loader.getClass().getName() + " was null.");
319 }
320 if (retrievedObject instanceof CacheOutputStream) {
321 /*
322 * a CacheLoader has created an OutputStream, and loaded the
323 * object. Get the owner object for the stream, and return
324 * the corresponding InputStream. The StreamObjects are
325 * created in the CacheLoader, but the regular memory
326 * objects are created below, is this correct? And a double
327 * creation is also done... once before the load, and once
328 * further down, but this is not called as we have multiple
329 * return points in this method.... well, if it works, dont
330 * touch it! Refactor when we are moving towards a
331 * production release.
332 *
333 */
334 return ((CacheOutputStream) retrievedObject).getStreamObject().getInputStream();
335 } else if (retrievedObject instanceof File) {
336 /*
337 * The object was a DiskObject, return the path to the
338 * diskfile.
339 */
340 return ((File) retrievedObject).getAbsolutePath();
341 }
342 attribs.setCreateTime(System.currentTimeMillis());
343 } catch (CacheException e) {
344 this.lastException = e.getClass();
345 this.lastMessage = e.getMessage();
346 return null;
347 }
348 CacheGroup group = objHandle.getGroup();
349 CacheObject newRef = new CacheObject(objHandle.getKey(), retrievedObject, group, region, CacheImpl.getCache().getReferenceQueue());
350 group.replace(objHandle.getKey(), newRef);
351 return newRef.get();
352 }
353 return objHandle.get();
354 }
355
356 /**
357 * gets a cacheobject from the cache.
358 * @param name the name of the object to get.
359 * @param group the group to get the object from.
360 * @return an cacheobject.
361 *
362 */
363 private CacheObject getCacheObject(final Object name, final String group) {
364 Object object = null;
365 //first check the memory cache
366 CacheGroup parentCacheObject = region;
367 if (group != null) {
368 parentCacheObject = region.getGroup(group);
369 if (parentCacheObject == null) {
370 return null;
371 }
372 }
373 if (parentCacheObject.contains(name)) {
374 object = parentCacheObject.get(name);
375 } else if (name instanceof Serializable) {
376 //second, check the disk cache.
377 try {
378 DiskCache diskCache = CacheImpl.getCache().getDiskCache();
379 if (diskCache != null) {
380 object = diskCache.getObject((Serializable) name);
381 if (object == null) {
382 return null;
383 }
384 }
385 } catch (DiskCacheException e) {
386 this.lastException = DiskCacheException.class;
387 this.lastMessage = e.getMessage();
388 return null;
389 }
390 }
391 if (object == null) {
392 return null;
393 }
394 if (object instanceof CacheGroup) {
395 this.lastException = NotARetrievableObjectException.class;
396 this.lastMessage = ("This object is a group and cannot be retrieved.");
397 return null;
398 }
399 CacheObject objHandle = (CacheObject) object;
400 return objHandle;
401 }
402
403 /**
404 * Gets the object from the specified group. If the object is not currently
405 * in the cache, and a loader object has been registered, the object will be
406 * loaded into the cache and accosiated with the specified group.
407 *
408 * @param name the name of the object to get.
409 * @param group The group the Object is associated with.
410 * @param arguments the arguments wich is passed to the load method of the
411 * CacheLoader, if registered.
412 *
413 * @return a reference to a shared object. Will always return the latest
414 * version of the object.
415 *
416 * @see #get(Object)
417 */
418 public Object get(final Object name, final String group, final Object arguments) {
419 if (!isValid()) {
420 return null;
421 }
422 return getImpl(name, group, arguments);
423 }
424
425 /**
426 * Will return an attribute object describing the current attributes
427 * associated for the region for this CacheAccess.
428 *
429 * @return an Attributes object for the region of this CacheAccess.
430 *
431 */
432 public Attributes getAttributes() {
433 if (!isValid()) {
434 return null;
435 }
436 return region.getAttributes();
437 }
438
439 /**
440 * will return an attribute object describing the current attributes
441 * associated with the object name.
442 *
443 * @param name the name of the object to get the attributes for.
444 *
445 * @return an Attributes object for the named object.
446 *
447 */
448 public Attributes getAttributes(final Object name) {
449 if (!isValid()) {
450 return null;
451 }
452 if (name == null) {
453 return null;
454 }
455 Object obj = region.get(name);
456 if (obj == null) {
457 return null;
458 }
459 if (obj instanceof CacheObject) {
460 return ((CacheObject) obj).getAttributes();
461 } else if (obj instanceof CacheGroup) {
462 return ((CacheGroup) obj).getAttributes();
463 }
464 this.lastException = CacheException.class;
465 this.lastMessage = "The object " + name + " is not valid. (" + obj.getClass().getName() + ')';
466 return null;
467 }
468
469 /**
470 * will claim ownership for the named object for this instance of
471 * CacheAccess. If ownership is not available, this method will block for
472 * the specified timeout. The local cache is checked first, if the local
473 * cache does not hold ownership of the object, a message is sent to all
474 * other caches in the system. Ownership is only relevant for synchronized
475 * objects. Ownership is maintained until an update or invalidation
476 * completes (this includes the reciept of replies when applicable) or until
477 * ownership is explicitly released with a call to releaseOwnership(). An
478 * instance of CacheAccess con only hold ownership of one object at a time.
479 * Ownership only applies to individual objects, it is not available on
480 * groups.
481 *
482 * @param name the name of the object to claim ownership for.
483 * @param timeout number of milliseconds to wait for the ownership claim.
484 *
485 * @return true if ownership was obtained, false otherwise.
486 *
487 *
488 *
489 * @todo not implemented.
490 */
491 public boolean getOwnership(final Object name, final int timeout) {
492 if (!isValid()) {
493 return false;
494 }
495 return false;
496 }
497
498 /**
499 * Will mark all objects in the region as invalid.
500 * @todo distribution of this event
501 */
502 public void invalidate() {
503 if (!isValid()) {
504 return;
505 }
506 region.invalidate();
507 // TODO: distribution of this event
508 }
509
510 /**
511 * Will mark all objects withing the scope of the specified name as invalid.
512 * If the name refers to a group object, the invalidate will cascade to all
513 * objects associated with the group or any subgroups. Invalidate does not
514 * "unregister" an object. The loader object will remain associated with the
515 * object name. To completely remove any knowledge of an object from the
516 * cache, destroy must be called.
517 *
518 * @param name the name of the object to invalidate.
519 *
520 *
521 */
522 public void invalidate(final Object name) {
523 if (!isValid()) {
524 return;
525 }
526 invalidateWithoutDistribution(name);
527 if (CacheImpl.getCache().isDistributed()) {
528 CacheImpl.getCache().getDistributionEngine().cacheObjectInvalidated(getRegionName(), (Serializable) name);
529 }
530 }
531
532 private void invalidateWithoutDistribution(final Object name) {
533 if (!region.contains(name)) {
534 return;
535 }
536 Object object = region.get(name);
537 if (object == null) {
538 return;
539 }
540 if (object instanceof CacheGroup) {
541 CacheGroup group = (CacheGroup) object;
542 group.invalidate();
543 } else {
544 // 2004/09-FB
545 if (object instanceof CacheObject) {
546 CacheObject obj = (CacheObject) object;
547 obj.invalidate();
548 }
549 }
550 }
551
552 /**
553 * Check the existence of a valid copy of the named object in the region
554 * associated with this CacheAccess object.
555 *
556 * @param name the name of the object to check the existence for.
557 *
558 * @return true if a valid copy was found, false otherwise.
559 */
560 public boolean isPresent(final Object name) {
561 if (!isValid()) {
562 return false;
563 }
564 return region.contains(name);
565 }
566
567 /**
568 * This method allows for asynchronous loading of object into the cache.
569 * This method will schedule a background task to the registered load
570 * method, then return. Any exception that occur during the load, will be
571 * written to the log, if logging is on and a log is available.
572 *
573 * @param name the name of the object to load.
574 *
575 *
576 */
577 public void preLoad(final Object name) {
578 if (!isValid()) {
579 return;
580 }
581 preLoad(name, null);
582 }
583
584 /**
585 * See {@link #preLoad(Object)}.
586 *
587 * @param name the name of the object to load.
588 * @param arguments these arguments will be passed to the load method of the
589 * loader object.
590
591 */
592 public void preLoad(final Object name, final Object arguments) {
593 if (!isValid()) {
594 return;
595 }
596 preLoad(name, null, arguments);
597 }
598
599 /**
600 * See {@link #preLoad(Object)}.
601 *
602 * @param name the name of the object to load.
603 * @param group the group the new object will be associated with.
604 * @param arguments these arguments will be passed to the load method of the
605 * loader object.
606 *
607 *
608 */
609 public void preLoad(final Object name, final String group, final Object arguments) {
610 if (!isValid()) {
611 return;
612 }
613 if (name == null) {
614 //log this, and silently return.
615 return;
616 }
617 final CacheLogger logger = CacheImpl.getCache().getAttributes().getLogger();
618 try {
619 final CacheObject obj = getCacheObject(name, group);
620 final CacheLoader loader = obj.getAttributes().getLoader();
621 if (loader == null) {
622 throw new ObjectNotFoundException("The object has no CacheLoader associated with it.");
623 }
624 Runnable runnable = new Runnable() {
625 public void run() {
626 try {
627 loader.load(obj, arguments);
628 } catch (CacheException e) {
629 if (logger != null) {
630 logger.log("The object was not found in the cache.", e);
631 }
632 }
633 }
634 };
635 CacheImpl.getCache().getExecPool().execute(runnable);
636 } catch (ObjectNotFoundException e) {
637 if (logger != null) {
638 logger.log("The object was not found in the cache.", e);
639 }
640 } catch (InterruptedException e) {
641 if (logger != null) {
642 logger.log("Some strange concurrency issue have occured.", e);
643 }
644 }
645 }
646
647 /**
648 * See {@link #put(Object, Object)}
649 *
650 * @param name the name associated with the object.
651 * @param attributes the attributes to associate with the object put into
652 * the cache,
653 * @param object the object wich is put in the cache.
654 *
655 *
656 *
657 * @see #put(Object,Object)
658 */
659 public void put(final Object name, final Attributes attributes, final Object object) {
660 if (!isValid()) {
661 return;
662 }
663 putImpl(name, null, attributes, object);
664 }
665
666 /**
667 * See {@link #put(Object, Object)}
668 *
669 * @param name the name associated with the object.
670 * @param group The group associated with the object.
671 * @param attributes the attributes to associate with the object put into
672 * the cache,
673 * @param object the object wich is put in the cache.
674 *
675 *
676 * @see #put(Object,Object)
677 */
678 public void put(final Object name, final String group, final Attributes attributes, final Object object) {
679 putImpl(name, group, attributes, object);
680 }
681
682 /**Gets the current number of objects in the cache.
683 * @return The current number of objects in the cache.
684 */
685 private int getCurrentObjectCount() {
686 int count = 0;
687 count += CacheImpl.getCache().getRegion().getObjectCount();
688 Iterator regions = CacheImpl.getCache().userRegionNames();
689 while (regions.hasNext()) {
690 count += CacheImpl.getCache().getRegion(regions.next()).getObjectCount();
691 }
692 return count;
693 }
694
695 /**
696 * Will return the last exception which occured.
697 * If no exception has occured, this will return null.
698 *
699 * @param cached if <code>true</code>, a cached exception is returned. The stacktrace of this exception
700 * will not be correct. Otherwise a new CacheException will be created. if you use <code>false</code> as the cache
701 * parameter, be adviced that this will be detrimental for performance.
702 * @return the last CacheException which occured.
703 */
704 public CacheException getException(boolean cached) {
705 if (lastException == null) {
706 return null;
707 }
708 try {
709 CacheException ex = (CacheException) lastException.newInstance();
710 ex.setMessage(lastMessage);
711 this.lastException = null;
712 this.lastMessage = null;
713 return ex;
714 } catch (InstantiationException e) {
715 throw new IllegalStateException(e.getMessage() + ":" + lastMessage);
716 } catch (IllegalAccessException e) {
717 throw new IllegalStateException(e.getMessage() + ":" + lastMessage);
718 }
719 }
720
721 /**
722 * puts an object into the cache without distribution.
723 * @param name the name of the object
724 * @param group the group to put the object into.
725 * @param attributes the attributoes belonging to the object
726 * @param object the actual object to put into the cache,.
727 * @return returns a boolean indicating wether the return was successfull or not. To get the errortype
728 * and errormessage you can call
729 */
730 private boolean putImpl(final Object name, final String group, final Attributes attributes, final Object object) {
731 CacheGroup objGr = region;
732 if (group != null) {
733 objGr = region.getGroup(group);
734 if (objGr == null) {
735 this.lastException = ObjectNotFoundException.class;
736 this.lastMessage = "The object " + group + " is not present in this cache.";
737 return false;
738 }
739 }
740 CacheObject o = new CacheObject(name, object, objGr, region, CacheImpl.getCache().getReferenceQueue());
741 o.setAttributes(attributes);
742 int maxObjects = CacheImpl.getCache().getAttributes().getMaxObjects();
743 int currentObjectCount = getCurrentObjectCount();
744 if (currentObjectCount >= maxObjects) {
745 DiskCache diskCache = CacheImpl.getCache().getDiskCache();
746 if (diskCache == null) {
747 //no disk, and memory is full.
748 this.lastException = CacheFullException.class;
749 this.lastMessage = "The maximum number of objects in the cache has been reached.";
750 return false;
751 }
752 boolean updated = diskCache.update(o);
753 if (!updated) {
754 this.lastException = CacheFullException.class;
755 this.lastMessage = "The maximum size for the diskCache has been reached.";
756 }
757 return updated;
758 }
759 if ((attributes != null) && (attributes.getSize() != 0)) {
760 if ((region.getCurrentSize() + attributes.getSize()) > (CacheImpl.getCache().getAttributes().getMemoryCacheSize() * 1024 * 1024)) {
761 DiskCache diskCache = CacheImpl.getCache().getDiskCache();
762 if (diskCache == null) {
763 //no disk, and memory is full.
764 this.lastException = CacheFullException.class;
765 this.lastMessage = "The maximum size for the memory cache has been reached.";
766 return false;
767 }
768 boolean updated = diskCache.update(o);
769 if (!updated) {
770 this.lastException = CacheFullException.class;
771 this.lastMessage = "The maximum size for the diskCache has been reached.";
772 }
773 return updated;
774 }
775 }
776 objGr.put(name, o, object);
777 return true;
778 }
779
780 /**
781 * inserts the specified object into the cache, and associates it with the
782 * specified name. Names are scoped to a region, so they must be unique
783 * within the region they are placed. This method is intended for very
784 * simple caching situations. In general it is better to create a
785 * CacheLoader object and allow the cache to manage the creation and loading
786 * of objects. Default attributes are assumed.
787 *
788 * @param name the name associated with the object.
789 * @param object the object wich is put in the cache.
790 *
791 *
792 */
793 public boolean put(final Object name, final Object object) {
794 if (!isValid()) {
795 return false;
796 }
797 return putImpl(name, null, null, object);
798 }
799
800 /**
801 * See {@link #put(Object, Object)}
802 *
803 * @param name the name associated with the object.
804 * @param group The group associated with the object.
805 * @param object the object wich is put in the cache.
806 *
807 *
808 *
809 * @see #put(Object, Object)
810 */
811 public void put(Object name, String group, Object object) {
812 if (!isValid()) {
813 return;
814 }
815 putImpl(name, group, null, object);
816 }
817
818 /**
819 * Is called to explicitly give up ownership for an object. Ownership is
820 * only relevant for synchronized objects. If ownership is not held,
821 * releaseOwnership is ignored.
822 *
823 *
824 */
825 public void releaseOwnership() {
826 if (!isValid()) {
827 return;
828 }
829 }
830
831 /**
832 * Will create a new version of the object indentified by the name,
833 * replacing the current version with the object specified. If the object
834 * doesn't exist in the cache, replace is equivalent to a put. The
835 * attributes will be inherited from the existing object or if no object
836 * exists, from the group or region the object associated with. Names are in
837 * the scope of a region so they must be unique within the region they are
838 * placed. This method is not valid on a disk, StreamAccess or Group Object.
839 *
840 * @param name the name of the object to replace.
841 * @param object The new object to be put in the cache.
842 *
843 * @return a reference to the newly replaced object.
844 *
845 */
846 public Object replace(Object name, Object object) {
847 if (!isValid()) {
848 return null;
849 }
850 if (name == null)
851 return null;
852 if (object == null)
853 return null;
854 Object replacedObject = replaceWithoutDistribution(name, object);
855 if (CacheImpl.getCache().isDistributed()) {
856 CacheImpl.getCache().getDistributionEngine().cacheObjectUpdated(getRegionName(), null, (Serializable) name, (Serializable) object);
857 }
858 return replacedObject;
859 }
860
861 /**
862 * @todo refactor me to another place. I really do not belong here, and I do not want to be public!
863 *
864 */
865 public Object replaceWithoutDistribution(Object name, Object object) {
866 if (!isValid()) {
867 return null;
868 }
869 return region.replace(name, new CacheObject(name, object, region, region, CacheImpl.getCache().getReferenceQueue()));
870 }
871
872 /**
873 * See replace(Object, Object)
874 *
875 * @param name the name of the object to replace.
876 * @param group the group the object is associated with.
877 * @param object The new object to be put in the cache.
878 *
879 * @return a reference to the newly replaced object.
880 *
881 */
882 public Object replace(Object name, String group, Object object) {
883 if (!isValid()) {
884 return null;
885 }
886 if (name == null)
887 return null;
888 if (object == null)
889 return null;
890 if (group == null)
891 return null;
892 Object replacedObject = replaceWithoutDistribution(name, group, object);
893 if (CacheImpl.getCache().isDistributed()) {
894 CacheImpl.getCache().getDistributionEngine().cacheObjectUpdated(getRegionName(), group, (Serializable) name, (Serializable) object);
895 }
896 return replacedObject;
897 }
898
899 /**
900 * @todo refactor me to another place. I really do not belong here, and I do not want to be public!
901 *
902 */
903 public Object replaceWithoutDistribution(Object name, String group, Object object) {
904 if (!isValid()) {
905 return null;
906 }
907 CacheGroup cachegroup = (CacheGroup) region.get(group);
908 if (cachegroup == null)
909 return null;
910 return cachegroup.replace(name, new CacheObject(name, object, region, region, CacheImpl.getCache().getReferenceQueue()));
911 }
912
913 /**
914 * allows for some attributes of a region to be reset. The attributes are
915 * expiration time attributes, time to live, default time to live, idle time
916 * and event handlers. The cacheloader and attributes explicitly set can't
917 * be reset with this method. To do this the object must be destroyed and
918 * redefined change those parameters. Changing the default settings on
919 * groups and regions will not affect existing objects. Only objects loaded
920 * after the reset will use the new defaults.
921 *
922 * @param attributes The new attributes to append to the region.
923 *
924 */
925 public void resetAttributes(Attributes attributes) {
926 if (!isValid()) {
927 return;
928 }
929 Attributes att = region.getAttributes();
930 att.reset();
931 att.applyAttributes(attributes);
932 }
933
934 /**
935 * See {@link #resetAttributes(Attributes)}.
936 *
937 * @param name the name of the region to reset the attributes for.
938 * @param attributes the new attributes for the named region.
939 *
940 */
941 public void resetAttributes(Object name, Attributes attributes) {
942 if (!isValid()) {
943 return;
944 }
945 Attributes att = CacheImpl.getCache(true).getRegion(name).getAttributes();
946 att.reset();
947 att.applyAttributes(attributes);
948 }
949
950 /**
951 * Will cause all objects within the region of this CacheAccess to be saved
952 * to the disk cache. All exceptions encountered will be logged if logging
953 * is on. Local objects will be saved in the process specific cache,
954 * distributed objects will be saved in the machine global disk cache.
955 *
956 *
957 */
958 public void save() {
959 if (!isValid()) {
960 return;
961 }
962 saveImpl(region);
963 }
964
965 /**
966 * Implements the stuff mentioned in save().
967 * This method does not throws any exceptions, cause all exceptions should be logged instead.
968 * @see CacheAccessImpl2#save()
969 * @todo Implement me.
970 * @param region the region to save.
971 */
972 private void saveImpl(CacheRegion region) {
973 }
974
975 /**
976 * See {@link #save()}. If the name refers to a specific object and that
977 * object does not implement the {@link java.io.Serializable}interface, a
978 * {@link CacheException}will be logged. If the name referenced a group or
979 * a region, all objects not implementing {@link java.io.Serializable}is
980 * ignored.
981 *
982 * @param name the name of the object to save.
983 *
984 */
985 public void save(Object name) {
986 if (!isValid()) {
987 return;
988 }
989 saveImpl(CacheImpl.getCache().getRegion(name));
990 }
991
992 /**
993 * May be used to wait for replies returned from invalidates or updates when
994 * a reply is requested. This method will block the calling thread until all
995 * the responses associated with the CacheAccess object have been retrieved
996 * or the time indicated in the timeout variable has expired. If this method
997 * times out and the caller does not intend to call waitForResponse again on
998 * this object, cancelResponse should be called. If the object is local or a
999 * reply has not been requested, this call return immediately.
1000 *
1001 * @param timeout the maximum number of milliseconds to wait for remote
1002 * caches to reply.
1003 *
1004 */
1005 public void waitForResponse(int timeout) {
1006 if (!isValid()) {
1007 return;
1008 }
1009 }
1010
1011 /**
1012 * Gets the region this access applies to.
1013 *
1014 * @return the region this access applies to.
1015 */
1016 public CacheRegion getRegion() {
1017 return region;
1018 }
1019
1020 private String getRegionName() {
1021 return region.getName() == null ? null : region.getName().toString();
1022 }
1023 }