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.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 }