Coverage Report - org.apache.ojb.broker.cache.CacheDistributor
 
Classes in this File Line Coverage Branch Coverage Complexity
CacheDistributor
N/A
N/A
2.208
CacheDistributor$ObjectCacheInternalWrapper
N/A
N/A
2.208
 
 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;
 19  
 import java.util.HashMap;
 20  
 import java.util.Iterator;
 21  
 import java.util.List;
 22  
 import java.util.Map;
 23  
 import java.util.Properties;
 24  
 import java.util.StringTokenizer;
 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.1 2007-08-24 22:17:29 ewestfal Exp $
 56  
  */
 57  
 class CacheDistributor implements ObjectCacheInternal
 58  
 {
 59  
     private static Logger log = LoggerFactory.getLogger(CacheDistributor.class);
 60  
     private static final String DESCRIPTOR_BASED_CACHES = "descriptorBasedCaches";
 61  
     public static final String CACHE_EXCLUDES_STRING = "cacheExcludes";
 62  
     private static final String 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 caches = new HashMap();
 70  
     private List 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 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 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 obj)
 110  
     {
 111  
         return getCache(oid.getObjectsTopLevelClass()).cacheIfNew(oid, obj);
 112  
     }
 113  
 
 114  
     public Object 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 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 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 obj, int type)
 146  
     {
 147  
         getCache(oid.getObjectsTopLevelClass()).doInternalCache(oid, obj, type);
 148  
     }
 149  
 
 150  
     public ObjectCacheInternal getCache(Class 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 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 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 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 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 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[]{PersistenceBroker.class, Properties.class},
 274  
                         new Object[]{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 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 key)
 297  
     {
 298  
         return (ObjectCacheInternal) caches.get(key);
 299  
     }
 300  
 
 301  
     private List createExcludedPackagesList(String theList)
 302  
     {
 303  
         StringTokenizer tok = new StringTokenizer(theList, DELIMITER_FOR_EXCLUDE);
 304  
         String token = null;
 305  
         ArrayList result = new ArrayList();
 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 targetClass)
 315  
     {
 316  
         if(excludedPackages != null)
 317  
         {
 318  
             String name = targetClass.getName();
 319  
             for(int i = 0; i < excludedPackages.size(); i++)
 320  
             {
 321  
                 String exclude = (String) 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 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 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 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 obj)
 395  
         {
 396  
             cache.cache(oid, obj);
 397  
         }
 398  
 
 399  
         public boolean cacheIfNew(Identity oid, Object obj)
 400  
         {
 401  
             cache.cache(oid, obj);
 402  
             return true;
 403  
         }
 404  
 
 405  
         public Object 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  
 }