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 473821 2006-11-11 22:37:25Z 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.remove();
 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  
      * 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 key)
 236  
         throws TorqueException
 237  
     {
 238  0
         Persistent oldOm = null;
 239  0
         if (cache != null)
 240  
         {
 241  
             try
 242  
             {
 243  0
                 synchronized (this)
 244  
                 {
 245  0
                     oldOm = (Persistent) cache.get(key);
 246  0
                     cache.remove(key);
 247  0
                 }
 248  
             }
 249  0
             catch (CacheException ce)
 250  
             {
 251  0
                 throw new TorqueException
 252  
                     ("Could not remove from cache due to internal JCS error",
 253  
                      ce);
 254  0
             }
 255  
         }
 256  0
         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  0
         ObjectKey key = om.getPrimaryKey();
 272  0
         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 key, Persistent om)
 286  
         throws TorqueException
 287  
     {
 288  0
         if (getOMClass() != null && !getOMClass().isInstance(om))
 289  
         {
 290  0
             throw new TorqueException(om + "; class=" + om.getClass().getName()
 291  
                 + "; id=" + om.getPrimaryKey() + " cannot be cached with "
 292  
                 + getOMClass().getName() + " objects");
 293  
         }
 294  
 
 295  0
         Persistent oldOm = null;
 296  0
         if (cache != null)
 297  
         {
 298  
             try
 299  
             {
 300  0
                 synchronized (this)
 301  
                 {
 302  0
                     oldOm = (Persistent) cache.get(key);
 303  0
                     cache.put(key, om);
 304  0
                 }
 305  
             }
 306  0
             catch (CacheException ce)
 307  
             {
 308  0
                 throw new TorqueException
 309  
                     ("Could not cache due to internal JCS error", ce);
 310  0
             }
 311  
         }
 312  0
         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 getOMs(ObjectKey[] ids)
 335  
         throws TorqueException
 336  
     {
 337  0
         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 getOMs(List ids)
 349  
         throws TorqueException
 350  
     {
 351  0
         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 getOMs(List ids, boolean fromCache)
 363  
         throws TorqueException
 364  
     {
 365  0
         List oms = null;
 366  0
         if (ids != null && ids.size() > 0)
 367  
         {
 368  
             // start a new list where we will replace the id's with om's
 369  0
             oms = new ArrayList(ids);
 370  0
             List newIds = new ArrayList(ids.size());
 371  0
             for (int i = 0; i < ids.size(); i++)
 372  
             {
 373  0
                 ObjectKey key = (ObjectKey) ids.get(i);
 374  0
                 Persistent om = null;
 375  0
                 if (fromCache)
 376  
                 {
 377  0
                     om = cacheGet(key);
 378  
                 }
 379  0
                 if (om == null)
 380  
                 {
 381  0
                     newIds.add(key);
 382  0
                 }
 383  
                 else
 384  
                 {
 385  0
                     oms.set(i, om);
 386  
                 }
 387  
             }
 388  
 
 389  0
             if (newIds.size() > 0)
 390  
             {
 391  0
                 List newOms = retrieveStoredOMs(newIds);
 392  0
                 for (int i = 0; i < oms.size(); i++)
 393  
                 {
 394  0
                     if (oms.get(i) instanceof ObjectKey)
 395  
                     {
 396  0
                         for (int j = newOms.size() - 1; j >= 0; j--)
 397  
                         {
 398  0
                             Persistent om = (Persistent) newOms.get(j);
 399  0
                             if (om.getPrimaryKey().equals(oms.get(i)))
 400  
                             {
 401  
                                 // replace the id with the om and add the om
 402  
                                 // to the cache
 403  0
                                 oms.set(i, om);
 404  0
                                 newOms.remove(j);
 405  0
                                 if (fromCache)
 406  
                                 {
 407  0
                                     putInstanceImpl(om);
 408  0
                                 }
 409  
                                 break;
 410  
                             }
 411  
                         }
 412  
                     }
 413  
                 }
 414  
             }
 415  
         }
 416  0
         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 retrieveStoredOMs(List ids)
 429  
         throws TorqueException;
 430  
 
 431  
     /**
 432  
      * Get the value of region.
 433  
      *
 434  
      * @return value of region.
 435  
      */
 436  
     public String getRegion()
 437  
     {
 438  0
         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 v)
 449  
         throws TorqueException
 450  
     {
 451  0
         this.region = v;
 452  
         try
 453  
         {
 454  0
             if (Torque.getConfiguration().getBoolean(Torque.CACHE_KEY, false))
 455  
             {
 456  0
                 cache = JCS.getInstance(getRegion());
 457  0
                 mrCache = new MethodResultCache(cache);
 458  0
             }
 459  
             else
 460  
             {
 461  0
                 mrCache = new NoOpMethodResultCache(cache);
 462  
             }
 463  
         }
 464  0
         catch (CacheException e)
 465  
         {
 466  0
             throw new TorqueException("Cache could not be initialized", e);
 467  0
         }
 468  
 
 469  0
         if (cache == null)
 470  
         {
 471  0
             log.info("Cache could not be initialized for region: " + v);
 472  
         }
 473  0
     }
 474  
 
 475  
     /**
 476  
      * @return The cache instance.
 477  
      */
 478  
     public MethodResultCache getMethodResultCache()
 479  
     {
 480  0
         if (isNew)
 481  
         {
 482  0
             synchronized (this)
 483  
             {
 484  0
                 if (isNew)
 485  
                 {
 486  0
                     registerAsListener();
 487  0
                     isNew = false;
 488  
                 }
 489  0
             }
 490  
         }
 491  0
         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  0
     }
 501  
 
 502  
     /**
 503  
      *
 504  
      * @param listener A new listener for cache events.
 505  
      */
 506  
     public void addCacheListenerImpl(CacheListener listener)
 507  
     {
 508  0
         List keys = listener.getInterestedFields();
 509  0
         Iterator i = keys.iterator();
 510  0
         while (i.hasNext())
 511  
         {
 512  0
             String key = (String) i.next();
 513  
             // Peer.column names are the fields
 514  0
             if (validFields != null && validFields.containsKey(key))
 515  
             {
 516  0
                 List listeners = (List) listenersMap.get(key);
 517  0
                 if (listeners == null)
 518  
                 {
 519  0
                     listeners = createSubsetList(key);
 520  
                 }
 521  
 
 522  0
                 boolean isNew = true;
 523  0
                 Iterator j = listeners.iterator();
 524  0
                 while (j.hasNext())
 525  
                 {
 526  0
                     Object listener2 =
 527  
                         ((WeakReference) j.next()).get();
 528  0
                     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  0
                     }
 535  0
                     else if (listener2 == listener)
 536  
                     {
 537  0
                         isNew = false;
 538  0
                         break;
 539  
                     }
 540  0
                 }
 541  0
                 if (isNew)
 542  
                 {
 543  0
                     listeners.add(new WeakReference(listener));
 544  
                 }
 545  
             }
 546  0
         }
 547  0
     }
 548  
 
 549  
     /**
 550  
      *
 551  
      * @param key
 552  
      * @return A subset of the list identified by <code>key</code>.
 553  
      */
 554  
     private synchronized List createSubsetList(String key)
 555  
     {
 556  0
         FastArrayList list = null;
 557  0
         if (listenersMap.containsKey(key))
 558  
         {
 559  0
             list = (FastArrayList) listenersMap.get(key);
 560  0
         }
 561  
         else
 562  
         {
 563  0
             list = new FastArrayList();
 564  0
             list.setFast(true);
 565  0
             listenersMap.put(key, list);
 566  
         }
 567  0
         return list;
 568  
     }
 569  
 
 570  
     /**
 571  
      *
 572  
      * @param listeners
 573  
      * @param oldOm
 574  
      * @param om
 575  
      */
 576  
     protected void notifyListeners(List listeners,
 577  
                                    Persistent oldOm, Persistent om)
 578  
     {
 579  0
         if (listeners != null)
 580  
         {
 581  0
             synchronized (listeners)
 582  
             {
 583  0
                 Iterator i = listeners.iterator();
 584  0
                 while (i.hasNext())
 585  
                 {
 586  0
                     CacheListener listener = (CacheListener)
 587  
                         ((WeakReference) i.next()).get();
 588  0
                     if (listener == null)
 589  
                     {
 590  
                         // remove reference as its object was cleared
 591  0
                         i.remove();
 592  0
                     }
 593  
                     else
 594  
                     {
 595  0
                         if (oldOm == null)
 596  
                         {
 597  
                             // object was added
 598  0
                             listener.addedObject(om);
 599  0
                         }
 600  
                         else
 601  
                         {
 602  
                             // object was refreshed
 603  0
                             listener.refreshedObject(om);
 604  
                         }
 605  
                     }
 606  0
                 }
 607  0
             }
 608  
         }
 609  0
     }
 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 out)
 619  
         throws IOException
 620  
     {
 621  0
         out.defaultWriteObject();
 622  0
     }
 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 in)
 632  
         throws IOException, ClassNotFoundException
 633  
     {
 634  0
         in.defaultReadObject();
 635  
         // initialize the cache
 636  
         try
 637  
         {
 638  0
             if (region != null)
 639  
             {
 640  0
                 setRegion(region);
 641  
             }
 642  
         }
 643  0
         catch (Exception e)
 644  
         {
 645  0
             log.error("Cache could not be initialized for region '"
 646  
                       + region + "' after deserialization");
 647  0
         }
 648  0
     }
 649  
 }

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