KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > torque > manager > AbstractBaseManager


1 package org.apache.torque.manager;
2
3 /*
4  * Licensed to the Apache Software Foundation (ASF) under one
5  * or more contributor license agreements. See the NOTICE file
6  * distributed with this work for additional information
7  * regarding copyright ownership. The ASF licenses this file
8  * to you under the Apache License, Version 2.0 (the
9  * "License"); you may not use this file except in compliance
10  * with the License. You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing,
15  * software distributed under the License is distributed on an
16  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17  * KIND, either express or implied. See the License for the
18  * specific language governing permissions and limitations
19  * under the License.
20  */

21
22 import java.lang.ref.WeakReference JavaDoc;
23 import java.util.Arrays JavaDoc;
24 import java.util.List JavaDoc;
25 import java.util.ArrayList JavaDoc;
26 import java.util.Map JavaDoc;
27 import java.util.HashMap JavaDoc;
28 import java.util.Iterator JavaDoc;
29 import java.io.Serializable JavaDoc;
30 import java.io.IOException JavaDoc;
31 import java.io.ObjectInputStream JavaDoc;
32
33 import org.apache.commons.collections.FastArrayList;
34 import org.apache.jcs.JCS;
35 import org.apache.jcs.access.GroupCacheAccess;
36 import org.apache.jcs.access.exception.CacheException;
37
38 import org.apache.torque.Torque;
39 import org.apache.torque.TorqueException;
40 import org.apache.torque.om.ObjectKey;
41 import org.apache.torque.om.Persistent;
42
43 import org.apache.commons.logging.Log;
44 import org.apache.commons.logging.LogFactory;
45
46 /**
47  * This class contains common functionality of a Manager for
48  * instantiating OM's.
49  *
50  * @author <a HREF="mailto:jmcnally@collab.net">John McNally</a>
51  * @version $Id: AbstractBaseManager.java 473821 2006-11-11 22:37:25Z tv $
52  */

53 public abstract class AbstractBaseManager
54     implements Serializable JavaDoc
55 {
56     /** the log */
57     protected static final Log log = LogFactory.getLog(AbstractBaseManager.class);
58
59     /** used to cache the om objects. cache is set by the region property */
60     protected transient GroupCacheAccess cache;
61
62     /** method results cache */
63     protected MethodResultCache mrCache;
64
65     /** the class that the service will instantiate */
66     private Class JavaDoc omClass;
67
68     private String JavaDoc className;
69
70     private String JavaDoc region;
71
72     private boolean isNew = true;
73
74     protected Map JavaDoc validFields;
75     protected Map JavaDoc listenersMap = new HashMap JavaDoc();
76
77     /**
78      * Get the Class instance
79      *
80      * @return the om class
81      */

82     protected Class JavaDoc getOMClass()
83     {
84         return omClass;
85     }
86
87     /**
88      * Set the Class that will be instantiated by this manager
89      *
90      * @param omClass the om class
91      */

92     protected void setOMClass(Class JavaDoc omClass)
93     {
94         this.omClass = omClass;
95     }
96
97     /**
98      * Get a fresh instance of an om
99      *
100      * @return an instance of the om class
101      * @throws InstantiationException
102      * @throws IllegalAccessException
103      */

104     protected Persistent getOMInstance()
105         throws InstantiationException JavaDoc, IllegalAccessException JavaDoc
106     {
107         return (Persistent) omClass.newInstance();
108     }
109
110     /**
111      * Get the classname to instantiate for getInstance()
112      * @return value of className.
113      */

114     public String JavaDoc getClassName()
115     {
116         return className;
117     }
118
119     /**
120      * Set the classname to instantiate for getInstance()
121      * @param v Value to assign to className.
122      * @throws TorqueException Any exceptions caught during processing will be
123      * rethrown wrapped into a TorqueException.
124      */

125     public void setClassName(String JavaDoc v)
126         throws TorqueException
127     {
128         this.className = v;
129
130         try
131         {
132             setOMClass(Class.forName(getClassName()));
133         }
134         catch (ClassNotFoundException JavaDoc cnfe)
135         {
136             throw new TorqueException("Could not load " + getClassName());
137         }
138     }
139
140
141     /**
142      * Return an instance of an om based on the id
143      *
144      * @param id the primary key of the object
145      * @return the object from persistent storage or from cache
146      * @throws TorqueException Any exceptions caught during processing will be
147      * rethrown wrapped into a TorqueException.
148      */

149     protected Persistent getOMInstance(ObjectKey id)
150         throws TorqueException
151     {
152         return getOMInstance(id, true);
153     }
154
155     /**
156      * Return an instance of an om based on the id
157      *
158      * @param key the primary key of the object
159      * @param fromCache true if the object should be retrieved from cache
160      * @return the object from persistent storage or from cache
161      * @throws TorqueException Any exceptions caught during processing will be
162      * rethrown wrapped into a TorqueException.
163      */

164     protected Persistent getOMInstance(ObjectKey key, boolean fromCache)
165         throws TorqueException
166     {
167         Persistent om = null;
168         if (fromCache)
169         {
170             om = cacheGet(key);
171         }
172
173         if (om == null)
174         {
175             om = retrieveStoredOM(key);
176             if (fromCache)
177             {
178                 putInstanceImpl(om);
179             }
180         }
181
182         return om;
183     }
184
185     /**
186      * Get an object from cache
187      *
188      * @param key the primary key of the object
189      * @return the object from cache
190      */

191     protected Persistent cacheGet(Serializable JavaDoc key)
192     {
193         Persistent om = null;
194         if (cache != null)
195         {
196             synchronized (this)
197             {
198                 om = (Persistent) cache.get(key);
199             }
200         }
201         return om;
202     }
203
204     /**
205      * Clears the cache
206      *
207      * @throws TorqueException Any exceptions caught during processing will be
208      * rethrown wrapped into a TorqueException.
209      */

210     protected void clearImpl()
211         throws TorqueException
212     {
213         if (cache != null)
214         {
215             try
216             {
217                 cache.remove();
218             }
219             catch (CacheException ce)
220             {
221                 throw new TorqueException(
222                         "Could not clear cache due to internal JCS error.", ce);
223             }
224         }
225     }
226
227     /**
228      * Remove an object from the cache
229      *
230      * @param key the cache key for the object
231      * @return the object one last time
232      * @throws TorqueException Any exceptions caught during processing will be
233      * rethrown wrapped into a TorqueException.
234      */

235     protected Persistent removeInstanceImpl(Serializable JavaDoc key)
236         throws TorqueException
237     {
238         Persistent oldOm = null;
239         if (cache != null)
240         {
241             try
242             {
243                 synchronized (this)
244                 {
245                     oldOm = (Persistent) cache.get(key);
246                     cache.remove(key);
247                 }
248             }
249             catch (CacheException ce)
250             {
251                 throw new TorqueException
252                     ("Could not remove from cache due to internal JCS error",
253                      ce);
254             }
255         }
256         return oldOm;
257     }
258
259     /**
260      * Put an object into the cache
261      *
262      * @param om the object
263      * @return if an object with the same key already is in the cache
264      * this object will be returned, else null
265      * @throws TorqueException Any exceptions caught during processing will be
266      * rethrown wrapped into a TorqueException.
267      */

268     protected Persistent putInstanceImpl(Persistent om)
269         throws TorqueException
270     {
271         ObjectKey key = om.getPrimaryKey();
272         return putInstanceImpl(key, om);
273     }
274
275     /**
276      * Put an object into the cache
277      *
278      * @param key the cache key for the object
279      * @param om the object
280      * @return if an object with this key already is in the cache
281      * this object will be returned, else null
282      * @throws TorqueException Any exceptions caught during processing will be
283      * rethrown wrapped into a TorqueException.
284      */

285     protected Persistent putInstanceImpl(Serializable JavaDoc key, Persistent om)
286         throws TorqueException
287     {
288         if (getOMClass() != null && !getOMClass().isInstance(om))
289         {
290             throw new TorqueException(om + "; class=" + om.getClass().getName()
291                 + "; id=" + om.getPrimaryKey() + " cannot be cached with "
292                 + getOMClass().getName() + " objects");
293         }
294
295         Persistent oldOm = null;
296         if (cache != null)
297         {
298             try
299             {
300                 synchronized (this)
301                 {
302                     oldOm = (Persistent) cache.get(key);
303                     cache.put(key, om);
304                 }
305             }
306             catch (CacheException ce)
307             {
308                 throw new TorqueException
309                     ("Could not cache due to internal JCS error", ce);
310             }
311         }
312         return oldOm;
313     }
314
315     /**
316      * Retrieve an object from persistent storage
317      *
318      * @param id the primary key of the object
319      * @return the object
320      * @throws TorqueException Any exceptions caught during processing will be
321      * rethrown wrapped into a TorqueException.
322      */

323     protected abstract Persistent retrieveStoredOM(ObjectKey id)
324         throws TorqueException;
325
326     /**
327      * Gets a list of om's based on id's.
328      *
329      * @param ids a <code>ObjectKey[]</code> value
330      * @return a <code>List</code> value
331      * @throws TorqueException Any exceptions caught during processing will be
332      * rethrown wrapped into a TorqueException.
333      */

334     protected List JavaDoc getOMs(ObjectKey[] ids)
335         throws TorqueException
336     {
337         return getOMs(Arrays.asList(ids));
338     }
339
340     /**
341      * Gets a list of om's based on id's.
342      *
343      * @param ids a <code>List</code> of <code>ObjectKey</code>'s
344      * @return a <code>List</code> value
345      * @throws TorqueException Any exceptions caught during processing will be
346      * rethrown wrapped into a TorqueException.
347      */

348     protected List JavaDoc getOMs(List JavaDoc ids)
349         throws TorqueException
350     {
351         return getOMs(ids, true);
352     }
353
354     /**
355      * Gets a list of om's based on id's.
356      *
357      * @param ids a <code>List</code> of <code>ObjectKey</code>'s
358      * @return a <code>List</code> value
359      * @throws TorqueException Any exceptions caught during processing will be
360      * rethrown wrapped into a TorqueException.
361      */

362     protected List JavaDoc getOMs(List JavaDoc ids, boolean fromCache)
363         throws TorqueException
364     {
365         List JavaDoc oms = null;
366         if (ids != null && ids.size() > 0)
367         {
368             // start a new list where we will replace the id's with om's
369
oms = new ArrayList JavaDoc(ids);
370             List JavaDoc newIds = new ArrayList JavaDoc(ids.size());
371             for (int i = 0; i < ids.size(); i++)
372             {
373                 ObjectKey key = (ObjectKey) ids.get(i);
374                 Persistent om = null;
375                 if (fromCache)
376                 {
377                     om = cacheGet(key);
378                 }
379                 if (om == null)
380                 {
381                     newIds.add(key);
382                 }
383                 else
384                 {
385                     oms.set(i, om);
386                 }
387             }
388
389             if (newIds.size() > 0)
390             {
391                 List JavaDoc newOms = retrieveStoredOMs(newIds);
392                 for (int i = 0; i < oms.size(); i++)
393                 {
394                     if (oms.get(i) instanceof ObjectKey)
395                     {
396                         for (int j = newOms.size() - 1; j >= 0; j--)
397                         {
398                             Persistent om = (Persistent) newOms.get(j);
399                             if (om.getPrimaryKey().equals(oms.get(i)))
400                             {
401                                 // replace the id with the om and add the om
402
// to the cache
403
oms.set(i, om);
404                                 newOms.remove(j);
405                                 if (fromCache)
406                                 {
407                                     putInstanceImpl(om);
408                                 }
409                                 break;
410                             }
411                         }
412                     }
413                 }
414             }
415         }
416         return oms;
417     }
418
419     /**
420      * Gets a list of om's based on id's.
421      * This method must be implemented in the drived class
422      *
423      * @param ids a <code>List</code> of <code>ObjectKey</code>'s
424      * @return a <code>List</code> value
425      * @throws TorqueException Any exceptions caught during processing will be
426      * rethrown wrapped into a TorqueException.
427      */

428     protected abstract List JavaDoc retrieveStoredOMs(List JavaDoc ids)
429         throws TorqueException;
430
431     /**
432      * Get the value of region.
433      *
434      * @return value of region.
435      */

436     public String JavaDoc getRegion()
437     {
438         return region;
439     }
440
441     /**
442      * Set the value of region.
443      *
444      * @param v Value to assign to region.
445      * @throws TorqueException Any exceptions caught during processing will be
446      * rethrown wrapped into a TorqueException.
447      */

448     public void setRegion(String JavaDoc v)
449         throws TorqueException
450     {
451         this.region = v;
452         try
453         {
454             if (Torque.getConfiguration().getBoolean(Torque.CACHE_KEY, false))
455             {
456                 cache = JCS.getInstance(getRegion());
457                 mrCache = new MethodResultCache(cache);
458             }
459             else
460             {
461                 mrCache = new NoOpMethodResultCache(cache);
462             }
463         }
464         catch (CacheException e)
465         {
466             throw new TorqueException("Cache could not be initialized", e);
467         }
468
469         if (cache == null)
470         {
471             log.info("Cache could not be initialized for region: " + v);
472         }
473     }
474
475     /**
476      * @return The cache instance.
477      */

478     public MethodResultCache getMethodResultCache()
479     {
480         if (isNew)
481         {
482             synchronized (this)
483             {
484                 if (isNew)
485                 {
486                     registerAsListener();
487                     isNew = false;
488                 }
489             }
490         }
491         return mrCache;
492     }
493
494     /**
495      * NoOp version. Managers should override this method to notify other
496      * managers that they are interested in CacheEvents.
497      */

498     protected void registerAsListener()
499     {
500     }
501
502     /**
503      *
504      * @param listener A new listener for cache events.
505      */

506     public void addCacheListenerImpl(CacheListener listener)
507     {
508         List JavaDoc keys = listener.getInterestedFields();
509         Iterator JavaDoc i = keys.iterator();
510         while (i.hasNext())
511         {
512             String JavaDoc key = (String JavaDoc) i.next();
513             // Peer.column names are the fields
514
if (validFields != null && validFields.containsKey(key))
515             {
516                 List JavaDoc listeners = (List JavaDoc) listenersMap.get(key);
517                 if (listeners == null)
518                 {
519                     listeners = createSubsetList(key);
520                 }
521
522                 boolean isNew = true;
523                 Iterator JavaDoc j = listeners.iterator();
524                 while (j.hasNext())
525                 {
526                     Object JavaDoc listener2 =
527                         ((WeakReference JavaDoc) j.next()).get();
528                     if (listener2 == null)
529                     {
530                         // do a little cleanup while checking for dupes
531
// not thread-safe, not likely to be many nulls
532
// but should revisit
533
//j.remove();
534
}
535                     else if (listener2 == listener)
536                     {
537                         isNew = false;
538                         break;
539                     }
540                 }
541                 if (isNew)
542                 {
543                     listeners.add(new WeakReference JavaDoc(listener));
544                 }
545             }
546         }
547     }
548
549     /**
550      *
551      * @param key
552      * @return A subset of the list identified by <code>key</code>.
553      */

554     private synchronized List JavaDoc createSubsetList(String JavaDoc key)
555     {
556         FastArrayList list = null;
557         if (listenersMap.containsKey(key))
558         {
559             list = (FastArrayList) listenersMap.get(key);
560         }
561         else
562         {
563             list = new FastArrayList();
564             list.setFast(true);
565             listenersMap.put(key, list);
566         }
567         return list;
568     }
569
570     /**
571      *
572      * @param listeners
573      * @param oldOm
574      * @param om
575      */

576     protected void notifyListeners(List JavaDoc listeners,
577                                    Persistent oldOm, Persistent om)
578     {
579         if (listeners != null)
580         {
581             synchronized (listeners)
582             {
583                 Iterator JavaDoc i = listeners.iterator();
584                 while (i.hasNext())
585                 {
586                     CacheListener listener = (CacheListener)
587                         ((WeakReference JavaDoc) i.next()).get();
588                     if (listener == null)
589                     {
590                         // remove reference as its object was cleared
591
i.remove();
592                     }
593                     else
594                     {
595                         if (oldOm == null)
596                         {
597                             // object was added
598
listener.addedObject(om);
599                         }
600                         else
601                         {
602                             // object was refreshed
603
listener.refreshedObject(om);
604                         }
605                     }
606                 }
607             }
608         }
609     }
610
611
612     /**
613      * helper methods for the Serializable interface
614      *
615      * @param out
616      * @throws IOException
617      */

618     private void writeObject(java.io.ObjectOutputStream JavaDoc out)
619         throws IOException JavaDoc
620     {
621         out.defaultWriteObject();
622     }
623
624     /**
625      * Helper methods for the <code>Serializable</code> interface.
626      *
627      * @param in The stream to read a <code>Serializable</code> from.
628      * @throws IOException
629      * @throws ClassNotFoundException
630      */

631     private void readObject(ObjectInputStream JavaDoc in)
632         throws IOException JavaDoc, ClassNotFoundException JavaDoc
633     {
634         in.defaultReadObject();
635         // initialize the cache
636
try
637         {
638             if (region != null)
639             {
640                 setRegion(region);
641             }
642         }
643         catch (Exception JavaDoc e)
644         {
645             log.error("Cache could not be initialized for region '"
646                       + region + "' after deserialization");
647         }
648     }
649 }
650
Popular Tags