Coverage report

  %line %branch
org.apache.torque.manager.AbstractBaseManager
0% 
0% 

 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;
 23  
 import java.util.Arrays;
 24  
 import java.util.List;
 25  
 import java.util.ArrayList;
 26  
 import java.util.Map;
 27  
 import java.util.HashMap;
 28  
 import java.util.Iterator;
 29  
 import java.io.Serializable;
 30  
 import java.io.IOException;
 31  
 import java.io.ObjectInputStream;
 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 571790 2007-09-01 12:40:44Z tv $
 52  
  */
 53  0
 public abstract class AbstractBaseManager
 54  
     implements Serializable
 55  
 {
 56  
     /** the log */
 57  0
     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 omClass;
 67  
 
 68  
     private String className;
 69  
 
 70  
     private String region;
 71  
 
 72  0
     private boolean isNew = true;
 73  
 
 74  
     protected Map validFields;
 75  0
     protected Map listenersMap = new HashMap();
 76  
 
 77  
     /**
 78  
      * Get the Class instance
 79  
      *
 80  
      * @return the om class
 81  
      */
 82  
     protected Class getOMClass()
 83  
     {
 84  0
         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 omClass)
 93  
     {
 94  0
         this.omClass = omClass;
 95  0
     }
 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, IllegalAccessException
 106  
     {
 107  0
         return (Persistent) omClass.newInstance();
 108  
     }
 109  
 
 110  
     /**
 111  
      * Get the classname to instantiate for getInstance()
 112  
      * @return value of className.
 113  
      */
 114  
     public String getClassName()
 115  
     {
 116  0
         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  v)
 126  
         throws TorqueException
 127  
     {
 128  0
         this.className = v;
 129  
 
 130  
         try
 131  
         {
 132  0
             setOMClass(Class.forName(getClassName()));
 133  
         }
 134  0
         catch (ClassNotFoundException cnfe)
 135  
         {
 136  0
             throw new TorqueException("Could not load " + getClassName());
 137  0
         }
 138  0
     }
 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  0
         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  0
         Persistent om = null;
 168  0
         if (fromCache)
 169  
         {
 170  0
             om = cacheGet(key);
 171  
         }
 172  
 
 173  0
         if (om == null)
 174  
         {
 175  0
             om = retrieveStoredOM(key);
 176  0
             if (fromCache)
 177  
             {
 178  0
                 putInstanceImpl(om);
 179  
             }
 180  
         }
 181  
 
 182  0
         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 key)
 192  
     {
 193  0
         Persistent om = null;
 194  0
         if (cache != null)
 195  
         {
 196  0
             synchronized (this)
 197  
             {
 198  0
                 om = (Persistent) cache.get(key);
 199  0
             }
 200  
         }
 201  0
         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  0
         if (cache != null)
 214  
         {
 215  
             try
 216  
             {
 217  0
                 cache.clear();
 218  
             }
 219  0
             catch (CacheException ce)
 220  
             {
 221  0
                 throw new TorqueException(
 222  
                         "Could not clear cache due to internal JCS error.", ce);
 223  0
             }
 224  
         }
 225  0
     }
 226  
 
 227  
     /**
 228  
      * Disposes of the cache. This triggers a shutdown of the connected cache
 229  
      * instances. This method should only be used during shutdown of Torque. The
 230  
      * manager instance will not cache anymore after this call.
 231  
      */
 232  
     public void dispose()
 233  
     {
 234  0
         if (cache != null)
 235  
         {
 236  0
             cache.dispose();
 237  0
             cache = null;
 238  
         }
 239  0
     }
 240  
 
 241  
     /**
 242  
      * Remove an object from the cache
 243  
      *
 244  
      * @param key the cache key for the object
 245  
      * @return the object one last time
 246  
      * @throws TorqueException Any exceptions caught during processing will be
 247  
      *         rethrown wrapped into a TorqueException.
 248  
      */
 249  
     protected Persistent removeInstanceImpl(Serializable key)
 250  
         throws TorqueException
 251  
     {
 252  0
         Persistent oldOm = null;
 253  0
         if (cache != null)
 254  
         {
 255  
             try
 256  
             {
 257  0
                 synchronized (this)
 258  
                 {
 259  0
                     oldOm = (Persistent) cache.get(key);
 260  0
                     cache.remove(key);
 261  0
                 }
 262  
             }
 263  0
             catch (CacheException ce)
 264  
             {
 265  0
                 throw new TorqueException
 266  
                     ("Could not remove from cache due to internal JCS error",
 267  
                      ce);
 268  0
             }
 269  
         }
 270  0
         return oldOm;
 271  
     }
 272  
 
 273  
     /**
 274  
      * Put an object into the cache
 275  
      *
 276  
      * @param om the object
 277  
      * @return if an object with the same key already is in the cache
 278  
      *         this object will be returned, else null
 279  
      * @throws TorqueException Any exceptions caught during processing will be
 280  
      *         rethrown wrapped into a TorqueException.
 281  
      */
 282  
     protected Persistent putInstanceImpl(Persistent om)
 283  
         throws TorqueException
 284  
     {
 285  0
         ObjectKey key = om.getPrimaryKey();
 286  0
         return putInstanceImpl(key, om);
 287  
     }
 288  
 
 289  
     /**
 290  
      * Put an object into the cache
 291  
      *
 292  
      * @param key the cache key for the object
 293  
      * @param om the object
 294  
      * @return if an object with this key already is in the cache
 295  
      *         this object will be returned, else null
 296  
      * @throws TorqueException Any exceptions caught during processing will be
 297  
      *         rethrown wrapped into a TorqueException.
 298  
      */
 299  
     protected Persistent putInstanceImpl(Serializable key, Persistent om)
 300  
         throws TorqueException
 301  
     {
 302  0
         if (getOMClass() != null && !getOMClass().isInstance(om))
 303  
         {
 304  0
             throw new TorqueException(om + "; class=" + om.getClass().getName()
 305  
                 + "; id=" + om.getPrimaryKey() + " cannot be cached with "
 306  
                 + getOMClass().getName() + " objects");
 307  
         }
 308  
 
 309  0
         Persistent oldOm = null;
 310  0
         if (cache != null)
 311  
         {
 312  
             try
 313  
             {
 314  0
                 synchronized (this)
 315  
                 {
 316  0
                     oldOm = (Persistent) cache.get(key);
 317  0
                     cache.put(key, om);
 318  0
                 }
 319  
             }
 320  0
             catch (CacheException ce)
 321  
             {
 322  0
                 throw new TorqueException
 323  
                     ("Could not cache due to internal JCS error", ce);
 324  0
             }
 325  
         }
 326  0
         return oldOm;
 327  
     }
 328  
 
 329  
     /**
 330  
      * Retrieve an object from persistent storage
 331  
      *
 332  
      * @param id the primary key of the object
 333  
      * @return the object
 334  
      * @throws TorqueException Any exceptions caught during processing will be
 335  
      *         rethrown wrapped into a TorqueException.
 336  
      */
 337  
     protected abstract Persistent retrieveStoredOM(ObjectKey id)
 338  
         throws TorqueException;
 339  
 
 340  
     /**
 341  
      * Gets a list of om's based on id's.
 342  
      *
 343  
      * @param ids a <code>ObjectKey[]</code> value
 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 getOMs(ObjectKey[] ids)
 349  
         throws TorqueException
 350  
     {
 351  0
         return getOMs(Arrays.asList(ids));
 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 getOMs(List ids)
 363  
         throws TorqueException
 364  
     {
 365  0
         return getOMs(ids, true);
 366  
     }
 367  
 
 368  
     /**
 369  
      * Gets a list of om's based on id's.
 370  
      *
 371  
      * @param ids a <code>List</code> of <code>ObjectKey</code>'s
 372  
      * @return a <code>List</code> value
 373  
      * @throws TorqueException Any exceptions caught during processing will be
 374  
      *         rethrown wrapped into a TorqueException.
 375  
      */
 376  
     protected List getOMs(List ids, boolean fromCache)
 377  
         throws TorqueException
 378  
     {
 379  0
         List oms = null;
 380  0
         if (ids != null && ids.size() > 0)
 381  
         {
 382  
             // start a new list where we will replace the id's with om's
 383  0
             oms = new ArrayList(ids);
 384  0
             List newIds = new ArrayList(ids.size());
 385  0
             for (int i = 0; i < ids.size(); i++)
 386  
             {
 387  0
                 ObjectKey key = (ObjectKey) ids.get(i);
 388  0
                 Persistent om = null;
 389  0
                 if (fromCache)
 390  
                 {
 391  0
                     om = cacheGet(key);
 392  
                 }
 393  0
                 if (om == null)
 394  
                 {
 395  0
                     newIds.add(key);
 396  
                 }
 397  
                 else
 398  
                 {
 399  0
                     oms.set(i, om);
 400  
                 }
 401  
             }
 402  
 
 403  0
             if (newIds.size() > 0)
 404  
             {
 405  0
                 List newOms = retrieveStoredOMs(newIds);
 406  0
                 for (int i = 0; i < oms.size(); i++)
 407  
                 {
 408  0
                     if (oms.get(i) instanceof ObjectKey)
 409  
                     {
 410  0
                         for (int j = newOms.size() - 1; j >= 0; j--)
 411  
                         {
 412  0
                             Persistent om = (Persistent) newOms.get(j);
 413  0
                             if (om.getPrimaryKey().equals(oms.get(i)))
 414  
                             {
 415  
                                 // replace the id with the om and add the om
 416  
                                 // to the cache
 417  0
                                 oms.set(i, om);
 418  0
                                 newOms.remove(j);
 419  0
                                 if (fromCache)
 420  
                                 {
 421  0
                                     putInstanceImpl(om);
 422  
                                 }
 423  
                                 break;
 424  
                             }
 425  
                         }
 426  
                     }
 427  
                 }
 428  
             }
 429  
         }
 430  0
         return oms;
 431  
     }
 432  
 
 433  
     /**
 434  
      * Gets a list of om's based on id's.
 435  
      * This method must be implemented in the drived class
 436  
      *
 437  
      * @param ids a <code>List</code> of <code>ObjectKey</code>'s
 438  
      * @return a <code>List</code> value
 439  
      * @throws TorqueException Any exceptions caught during processing will be
 440  
      *         rethrown wrapped into a TorqueException.
 441  
      */
 442  
     protected abstract List retrieveStoredOMs(List ids)
 443  
         throws TorqueException;
 444  
 
 445  
     /**
 446  
      * Get the value of region.
 447  
      *
 448  
      * @return value of region.
 449  
      */
 450  
     public String getRegion()
 451  
     {
 452  0
         return region;
 453  
     }
 454  
 
 455  
     /**
 456  
      * Set the value of region.
 457  
      *
 458  
      * @param v  Value to assign to region.
 459  
      * @throws TorqueException Any exceptions caught during processing will be
 460  
      *         rethrown wrapped into a TorqueException.
 461  
      */
 462  
     public void setRegion(String v)
 463  
         throws TorqueException
 464  
     {
 465  0
         this.region = v;
 466  
         try
 467  
         {
 468  0
             if (Torque.getConfiguration().getBoolean(Torque.CACHE_KEY, false))
 469  
             {
 470  0
                 cache = JCS.getInstance(getRegion());
 471  0
                 mrCache = new MethodResultCache(cache);
 472  
             }
 473  
             else
 474  
             {
 475  0
                 mrCache = new NoOpMethodResultCache(cache);
 476  
             }
 477  
         }
 478  0
         catch (CacheException e)
 479  
         {
 480  0
             throw new TorqueException("Cache could not be initialized", e);
 481  0
         }
 482  
 
 483  0
         if (cache == null)
 484  
         {
 485  0
             log.info("Cache could not be initialized for region: " + v);
 486  
         }
 487  0
     }
 488  
 
 489  
     /**
 490  
      * @return The cache instance.
 491  
      */
 492  
     public MethodResultCache getMethodResultCache()
 493  
     {
 494  0
         if (isNew)
 495  
         {
 496  0
             synchronized (this)
 497  
             {
 498  0
                 if (isNew)
 499  
                 {
 500  0
                     registerAsListener();
 501  0
                     isNew = false;
 502  
                 }
 503  0
             }
 504  
         }
 505  0
         return mrCache;
 506  
     }
 507  
 
 508  
     /**
 509  
      * NoOp version.  Managers should override this method to notify other
 510  
      * managers that they are interested in CacheEvents.
 511  
      */
 512  
     protected void registerAsListener()
 513  
     {
 514  0
     }
 515  
 
 516  
     /**
 517  
      *
 518  
      * @param listener A new listener for cache events.
 519  
      */
 520  
     public void addCacheListenerImpl(CacheListener listener)
 521  
     {
 522  0
         List keys = listener.getInterestedFields();
 523  0
         Iterator i = keys.iterator();
 524  0
         while (i.hasNext())
 525  
         {
 526  0
             String key = (String) i.next();
 527  
             // Peer.column names are the fields
 528  0
             if (validFields != null && validFields.containsKey(key))
 529  
             {
 530  0
                 List listeners = (List) listenersMap.get(key);
 531  0
                 if (listeners == null)
 532  
                 {
 533  0
                     listeners = createSubsetList(key);
 534  
                 }
 535  
 
 536  0
                 boolean isNew = true;
 537  0
                 Iterator j = listeners.iterator();
 538  0
                 while (j.hasNext())
 539  
                 {
 540  0
                     Object listener2 =
 541  
                         ((WeakReference) j.next()).get();
 542  0
                     if (listener2 == null)
 543  0
                     {
 544  
                         // do a little cleanup while checking for dupes
 545  
                         // not thread-safe, not likely to be many nulls
 546  
                         // but should revisit
 547  
                         //j.remove();
 548  
                     }
 549  0
                     else if (listener2 == listener)
 550  
                     {
 551  0
                         isNew = false;
 552  0
                         break;
 553  
                     }
 554  
                 }
 555  0
                 if (isNew)
 556  
                 {
 557  0
                     listeners.add(new WeakReference(listener));
 558  
                 }
 559  
             }
 560  
         }
 561  0
     }
 562  
 
 563  
     /**
 564  
      *
 565  
      * @param key
 566  
      * @return A subset of the list identified by <code>key</code>.
 567  
      */
 568  
     private synchronized List createSubsetList(String key)
 569  
     {
 570  0
         FastArrayList list = null;
 571  0
         if (listenersMap.containsKey(key))
 572  
         {
 573  0
             list = (FastArrayList) listenersMap.get(key);
 574  
         }
 575  
         else
 576  
         {
 577  0
             list = new FastArrayList();
 578  0
             list.setFast(true);
 579  0
             listenersMap.put(key, list);
 580  
         }
 581  0
         return list;
 582  
     }
 583  
 
 584  
     /**
 585  
      *
 586  
      * @param listeners
 587  
      * @param oldOm
 588  
      * @param om
 589  
      */
 590  
     protected void notifyListeners(List listeners,
 591  
                                    Persistent oldOm, Persistent om)
 592  
     {
 593  0
         if (listeners != null)
 594  
         {
 595  0
             synchronized (listeners)
 596  
             {
 597  0
                 Iterator i = listeners.iterator();
 598  0
                 while (i.hasNext())
 599  
                 {
 600  0
                     CacheListener listener = (CacheListener)
 601  
                         ((WeakReference) i.next()).get();
 602  0
                     if (listener == null)
 603  
                     {
 604  
                         // remove reference as its object was cleared
 605  0
                         i.remove();
 606  
                     }
 607  
                     else
 608  
                     {
 609  0
                         if (oldOm == null)
 610  
                         {
 611  
                             // object was added
 612  0
                             listener.addedObject(om);
 613  
                         }
 614  
                         else
 615  
                         {
 616  
                             // object was refreshed
 617  0
                             listener.refreshedObject(om);
 618  
                         }
 619  
                     }
 620  
                 }
 621  0
             }
 622  
         }
 623  0
     }
 624  
 
 625  
 
 626  
     /**
 627  
      * helper methods for the Serializable interface
 628  
      *
 629  
      * @param out
 630  
      * @throws IOException
 631  
      */
 632  
     private void writeObject(java.io.ObjectOutputStream out)
 633  
         throws IOException
 634  
     {
 635  0
         out.defaultWriteObject();
 636  0
     }
 637  
 
 638  
     /**
 639  
      * Helper methods for the <code>Serializable</code> interface.
 640  
      *
 641  
      * @param in The stream to read a <code>Serializable</code> from.
 642  
      * @throws IOException
 643  
      * @throws ClassNotFoundException
 644  
      */
 645  
     private void readObject(ObjectInputStream in)
 646  
         throws IOException, ClassNotFoundException
 647  
     {
 648  0
         in.defaultReadObject();
 649  
         // initialize the cache
 650  
         try
 651  
         {
 652  0
             if (region != null)
 653  
             {
 654  0
                 setRegion(region);
 655  
             }
 656  
         }
 657  0
         catch (Exception e)
 658  
         {
 659  0
             log.error("Cache could not be initialized for region '"
 660  
                       + region + "' after deserialization");
 661  0
         }
 662  0
     }
 663  
 }

This report is generated by jcoverage, Maven and Maven JCoverage Plugin.