KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > ojb > broker > cache > CacheDistributor


1 package org.apache.ojb.broker.cache;
2
3 /* Copyright 2003-2005 The Apache Software Foundation
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */

17
18 import java.util.ArrayList JavaDoc;
19 import java.util.HashMap JavaDoc;
20 import java.util.Iterator JavaDoc;
21 import java.util.List JavaDoc;
22 import java.util.Map JavaDoc;
23 import java.util.Properties JavaDoc;
24 import java.util.StringTokenizer JavaDoc;
25
26 import org.apache.commons.lang.SystemUtils;
27 import org.apache.commons.lang.builder.ToStringBuilder;
28 import org.apache.commons.lang.builder.ToStringStyle;
29 import org.apache.ojb.broker.Identity;
30 import org.apache.ojb.broker.OJBRuntimeException;
31 import org.apache.ojb.broker.PersistenceBroker;
32 import org.apache.ojb.broker.metadata.ObjectCacheDescriptor;
33 import org.apache.ojb.broker.util.ClassHelper;
34 import org.apache.ojb.broker.util.configuration.impl.OjbConfigurator;
35 import org.apache.ojb.broker.util.logging.Logger;
36 import org.apache.ojb.broker.util.logging.LoggerFactory;
37
38 /**
39  * A intern used {@link AbstractMetaCache} implementation acting
40  * as distributor of <code>ObjectCache</code> implementations declared
41  * in configuration metadata.
42  * <p/>
43  * Reads the name of the used ObjectCache implementation
44  * <br/>
45  * a) from class-descriptor, or if not found
46  * <br/>
47  * b) from jdbc-connection-descriptor, or if not found
48  * <br/>
49  * use a given standard ObjectCache implementation (given by
50  * constructor argument).
51  * </p>
52  *
53  * @author Matthew Baird (mattbaird@yahoo.com)
54  * @author <a HREF="mailto:armin@codeAuLait.de">Armin Waibel</a>
55  * @version $Id: CacheDistributor.java,v 1.7.2.4 2005/12/21 22:24:15 tomdz Exp $
56  */

57 class CacheDistributor implements ObjectCacheInternal
58 {
59     private static Logger log = LoggerFactory.getLogger(CacheDistributor.class);
60     private static final String JavaDoc DESCRIPTOR_BASED_CACHES = "descriptorBasedCaches";
61     public static final String JavaDoc CACHE_EXCLUDES_STRING = "cacheExcludes";
62     private static final String JavaDoc DELIMITER_FOR_EXCLUDE = ",";
63     private static final ObjectCacheInternal DUMMY_CACHE =
64             new ObjectCacheInternalWrapper(new ObjectCacheEmptyImpl(null, null));
65
66     /**
67      * map, represents used cache implementations
68      */

69     private Map JavaDoc caches = new HashMap JavaDoc();
70     private List JavaDoc excludedPackages;
71
72     private final PersistenceBroker broker;
73     /**
74      * If <code>true</code> the class name of the object is used
75      * to find a per class {@link ObjectCache} implementation.
76      * If set <code>false</code> the {@link ObjectCacheDescriptor}
77      * instance is used as key to find a per class ObjectCache.
78      */

79     private boolean descriptorBasedCaches;
80
81     /**
82      * public Default Constructor
83      */

84     public CacheDistributor(final PersistenceBroker broker)
85     {
86         this.broker = broker;
87         this.descriptorBasedCaches = OjbConfigurator.getInstance().getConfigurationFor(null)
88                 .getBoolean(DESCRIPTOR_BASED_CACHES, false);
89         String JavaDoc exclude = broker.serviceConnectionManager().getConnectionDescriptor().getAttribute(CACHE_EXCLUDES_STRING);
90         if(exclude != null)
91         {
92             exclude = exclude.trim();
93             if(exclude.length() > 0)
94             {
95                 excludedPackages = createExcludedPackagesList(exclude);
96                 log.info("Packages to exclude from caching: " + excludedPackages);
97             }
98         }
99     }
100
101     public void cache(Identity oid, Object JavaDoc obj)
102     {
103         getCache(oid.getObjectsTopLevelClass()).cache(oid, obj);
104     }
105
106     /**
107      * @see ObjectCacheInternal#cacheIfNew(org.apache.ojb.broker.Identity, Object)
108      */

109     public boolean cacheIfNew(Identity oid, Object JavaDoc obj)
110     {
111         return getCache(oid.getObjectsTopLevelClass()).cacheIfNew(oid, obj);
112     }
113
114     public Object JavaDoc lookup(Identity oid)
115     {
116         return getCache(oid.getObjectsTopLevelClass()).lookup(oid);
117     }
118
119     public void remove(Identity oid)
120     {
121         getCache(oid.getObjectsTopLevelClass()).remove(oid);
122     }
123
124     public void clear()
125     {
126         synchronized(caches)
127         {
128             Iterator JavaDoc it = caches.values().iterator();
129             ObjectCache oc = null;
130             while(it.hasNext())
131             {
132                 oc = (ObjectCache) it.next();
133                 try
134                 {
135                     oc.clear();
136                 }
137                 catch(Exception JavaDoc e)
138                 {
139                     log.error("Error while call method 'clear()' on '" + oc + "'", e);
140                 }
141             }
142         }
143     }
144
145     public void doInternalCache(Identity oid, Object JavaDoc obj, int type)
146     {
147         getCache(oid.getObjectsTopLevelClass()).doInternalCache(oid, obj, type);
148     }
149
150     public ObjectCacheInternal getCache(Class JavaDoc targetClass)
151     {
152         /*
153         the priorities to find an ObjectCache for a specific object are:
154         1. try to find a cache defined per class
155         2. try to find a cache defined per jdbc-connection-descriptor
156         */

157         boolean useConnectionLevelCache = false;
158         ObjectCacheInternal retval = null;
159         /*
160         first search in class-descriptor, then in jdbc-connection-descriptor
161         for ObjectCacheDescriptor.
162         */

163         ObjectCacheDescriptor ocd = searchInClassDescriptor(targetClass);
164         if(ocd == null)
165         {
166             ocd = searchInJdbcConnectionDescriptor();
167             useConnectionLevelCache = true;
168         }
169         if(ocd == null)
170         {
171             throw new OJBRuntimeException("No object cache descriptor found for " + targetClass + ", using PBKey " + broker.getPBKey()
172                     + ". Please set a cache descriptor in jdbc-connection-descriptor or in class-descriptor");
173         }
174         else
175         {
176             // use a class-descriptor level cache
177
if(!useConnectionLevelCache)
178             {
179                 if(!descriptorBasedCaches)
180                 {
181                     synchronized(caches)
182                     {
183                         retval = lookupCache(targetClass);
184
185                         if(retval == null)
186                         {
187                             if(log.isEnabledFor(Logger.INFO))
188                             {
189                                 String JavaDoc eol = SystemUtils.LINE_SEPARATOR;
190                                 log.info(eol + "<====" + eol + "Setup new object cache instance on CLASS LEVEL for" + eol
191                                         + "PersistenceBroker: " + broker + eol
192                                         + "descriptorBasedCache: " + descriptorBasedCaches + eol
193                                         + "Class: " + targetClass + eol
194                                         + "ObjectCache: " + ocd + eol + "====>");
195                             }
196                             retval = prepareAndAddCache(targetClass, ocd);
197                         }
198                     }
199                 }
200                 else
201                 {
202                     synchronized(caches)
203                     {
204                         retval = lookupCache(ocd);
205
206                         if(retval == null)
207                         {
208                             if(log.isEnabledFor(Logger.INFO))
209                             {
210                                 String JavaDoc eol = SystemUtils.LINE_SEPARATOR;
211                                 log.info(eol + "<====" + eol + "Setup new object cache instance on CLASS LEVEL for" + eol
212                                         + "PersistenceBroker: " + broker + eol
213                                         + "descriptorBasedCache: " + descriptorBasedCaches + eol
214                                         + "class: " + targetClass + eol
215                                         + "ObjectCache: " + ocd + eol + "====>");
216                             }
217                             retval = prepareAndAddCache(ocd, ocd);
218                         }
219                     }
220                 }
221             }
222             // use a jdbc-connection-descriptor level cache
223
else
224             {
225                 if(isExcluded(targetClass))
226                 {
227                     if(log.isDebugEnabled()) log.debug("Class '" + targetClass.getName() + "' is excluded from being cached");
228                     retval = DUMMY_CACHE;
229                 }
230                 else
231                 {
232                     String JavaDoc jcdAlias = broker.serviceConnectionManager().getConnectionDescriptor().getJcdAlias();
233                     synchronized(caches)
234                     {
235                         retval = lookupCache(jcdAlias);
236
237                         if(retval == null)
238                         {
239                             if(log.isEnabledFor(Logger.INFO))
240                             {
241                                 String JavaDoc eol = SystemUtils.LINE_SEPARATOR;
242                                 log.info(eol + "<====" + eol + "Setup new object cache instance on CONNECTION LEVEL for" + eol
243                                         + "PersistenceBroker: " + broker + eol
244                                         + "descriptorBasedCache: " + descriptorBasedCaches + eol
245                                         + "Connection jcdAlias: " + jcdAlias + eol
246                                         + "Calling class: " + targetClass
247                                         + "ObjectCache: " + ocd + eol + "====>");
248                             }
249                             retval = prepareAndAddCache(jcdAlias, ocd);
250                         }
251                     }
252                 }
253             }
254         }
255         return retval;
256     }
257
258     private ObjectCacheInternal prepareAndAddCache(Object JavaDoc key, ObjectCacheDescriptor ocd)
259     {
260         ObjectCacheInternal cache;
261         // before the synchronize method lock this,
262
// another thread maybe added same key
263
if((cache = lookupCache(key)) != null)
264         {
265             log.info("Key '" + key + "' was already in use no need to create the ObjectCache instance again");
266         }
267         else
268         {
269             if(log.isDebugEnabled()) log.debug("Create new ObjectCache implementation for " + key);
270             try
271             {
272                 ObjectCache temp = (ObjectCache) ClassHelper.newInstance(ocd.getObjectCache(),
273                         new Class JavaDoc[]{PersistenceBroker.class, Properties JavaDoc.class},
274                         new Object JavaDoc[]{broker, ocd.getConfigurationProperties()});
275                 if(temp instanceof ObjectCacheInternal)
276                 {
277                     cache = (ObjectCacheInternal) temp;
278                 }
279                 else
280                 {
281                     log.info("Specified cache " + ocd.getObjectCache() + " does not implement "
282                             + ObjectCacheInternal.class + " and will be wrapped by a helper class");
283                     cache = new ObjectCacheInternalWrapper(temp);
284                 }
285             }
286             catch(Exception JavaDoc e)
287             {
288                 log.error("Can not create ObjectCache instance using class " + ocd.getObjectCache(), e);
289                 throw new OJBRuntimeException(e);
290             }
291             caches.put(key, cache);
292         }
293         return cache;
294     }
295
296     private ObjectCacheInternal lookupCache(Object JavaDoc key)
297     {
298         return (ObjectCacheInternal) caches.get(key);
299     }
300
301     private List JavaDoc createExcludedPackagesList(String JavaDoc theList)
302     {
303         StringTokenizer JavaDoc tok = new StringTokenizer JavaDoc(theList, DELIMITER_FOR_EXCLUDE);
304         String JavaDoc token = null;
305         ArrayList JavaDoc result = new ArrayList JavaDoc();
306         while(tok.hasMoreTokens())
307         {
308             token = tok.nextToken().trim();
309             if(token.length() > 0) result.add(token);
310         }
311         return result;
312     }
313
314     private boolean isExcluded(Class JavaDoc targetClass)
315     {
316         if(excludedPackages != null)
317         {
318             String JavaDoc name = targetClass.getName();
319             for(int i = 0; i < excludedPackages.size(); i++)
320             {
321                 String JavaDoc exclude = (String JavaDoc) excludedPackages.get(i);
322                 if(name.startsWith(exclude))
323                 {
324                     return true;
325                 }
326             }
327         }
328         return false;
329     }
330
331     /**
332      * Try to lookup {@link ObjectCacheDescriptor} in
333      * {@link org.apache.ojb.broker.metadata.ClassDescriptor}.
334      *
335      * @param targetClass
336      * @return Returns the found {@link ObjectCacheDescriptor} or <code>null</code>
337      * if none was found.
338      */

339     protected ObjectCacheDescriptor searchInClassDescriptor(Class JavaDoc targetClass)
340     {
341         return targetClass != null ? broker.getClassDescriptor(targetClass).getObjectCacheDescriptor() : null;
342     }
343
344     /**
345      * Lookup {@link ObjectCacheDescriptor} in
346      * {@link org.apache.ojb.broker.metadata.JdbcConnectionDescriptor}.
347      *
348      * @return Returns the found {@link ObjectCacheDescriptor} or <code>null</code>
349      * if none was found.
350      */

351     protected ObjectCacheDescriptor searchInJdbcConnectionDescriptor()
352     {
353         return broker.serviceConnectionManager().getConnectionDescriptor().getObjectCacheDescriptor();
354     }
355
356     public String JavaDoc toString()
357     {
358         ToStringBuilder buf = new ToStringBuilder(this, ToStringStyle.DEFAULT_STYLE);
359         return buf.append("Associated PB", broker)
360                 .append("Mapped caches", caches).toString();
361     }
362
363     //=================================================
364
// inner class
365
//=================================================
366
/**
367      * Wrapper class used to make existing {@link ObjectCache} implementations work
368      * with {@link ObjectCacheInternal}.
369      */

370     static final class ObjectCacheInternalWrapper implements ObjectCacheInternal
371     {
372         ObjectCache cache = null;
373
374         public ObjectCacheInternalWrapper(ObjectCache cache)
375         {
376             this.cache = cache;
377         }
378
379         public void doInternalCache(Identity oid, Object JavaDoc obj, int type)
380         {
381             cache(oid, obj);
382         }
383
384         public void doInternalClear()
385         {
386             // noop
387
}
388
389         public boolean contains(Identity oid)
390         {
391             return cache.lookup(oid) != null;
392         }
393
394         public void cache(Identity oid, Object JavaDoc obj)
395         {
396             cache.cache(oid, obj);
397         }
398
399         public boolean cacheIfNew(Identity oid, Object JavaDoc obj)
400         {
401             cache.cache(oid, obj);
402             return true;
403         }
404
405         public Object JavaDoc lookup(Identity oid)
406         {
407             return cache.lookup(oid);
408         }
409
410         public void remove(Identity oid)
411         {
412             cache.remove(oid);
413         }
414
415         public void clear()
416         {
417             cache.clear();
418         }
419     }
420
421 }
422
Popular Tags