Coverage report

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

 1  
 package org.apache.torque.manager;
 2  
 
 3  
 /*
 4  
  * Copyright 2001-2005 The Apache Software Foundation.
 5  
  *
 6  
  * Licensed under the Apache License, Version 2.0 (the "License")
 7  
  * you may not use this file except in compliance with the License.
 8  
  * You may obtain a copy of the License at
 9  
  *
 10  
  *     http://www.apache.org/licenses/LICENSE-2.0
 11  
  *
 12  
  * Unless required by applicable law or agreed to in writing, software
 13  
  * distributed under the License is distributed on an "AS IS" BASIS,
 14  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 15  
  * See the License for the specific language governing permissions and
 16  
  * limitations under the License.
 17  
  */
 18  
 
 19  
 import java.lang.ref.WeakReference;
 20  
 import java.util.Arrays;
 21  
 import java.util.List;
 22  
 import java.util.ArrayList;
 23  
 import java.util.Map;
 24  
 import java.util.HashMap;
 25  
 import java.util.Iterator;
 26  
 import java.io.Serializable;
 27  
 import java.io.IOException;
 28  
 import java.io.ObjectInputStream;
 29  
 
 30  
 import org.apache.commons.collections.FastArrayList;
 31  
 import org.apache.jcs.JCS;
 32  
 import org.apache.jcs.access.GroupCacheAccess;
 33  
 import org.apache.jcs.access.exception.CacheException;
 34  
 
 35  
 import org.apache.torque.Torque;
 36  
 import org.apache.torque.TorqueException;
 37  
 import org.apache.torque.om.ObjectKey;
 38  
 import org.apache.torque.om.Persistent;
 39  
 
 40  
 import org.apache.commons.logging.Log;
 41  
 import org.apache.commons.logging.LogFactory;
 42  
 
 43  
 /**
 44  
  * This class contains common functionality of a Manager for
 45  
  * instantiating OM's.
 46  
  *
 47  
  * @author <a href="mailto:jmcnally@collab.net">John McNally</a>
 48  
  * @version $Id: AbstractBaseManager.java 239636 2005-08-24 12:38:09Z henning $
 49  
  */
 50  0
 public abstract class AbstractBaseManager
 51  
     implements Serializable
 52  
 {
 53  
     /** the log */
 54  0
     protected static Log log = LogFactory.getLog(AbstractBaseManager.class);
 55  
 
 56  
     /** used to cache the om objects. cache is set by the region property */
 57  
     protected transient GroupCacheAccess cache;
 58  
 
 59  
     /** method results cache */
 60  
     protected MethodResultCache mrCache;
 61  
 
 62  
     /** the class that the service will instantiate */
 63  
     private Class omClass;
 64  
 
 65  
     private String className;
 66  
 
 67  
     private String region;
 68  
 
 69  0
     private boolean isNew = true;
 70  
 
 71  
     protected Map validFields;
 72  0
     protected Map listenersMap = new HashMap();
 73  
 
 74  
     /**
 75  
      * Get the Class instance
 76  
      *
 77  
      * @return the om class
 78  
      */
 79  
     protected Class getOMClass()
 80  
     {
 81  0
         return omClass;
 82  
     }
 83  
 
 84  
     /**
 85  
      * Set the Class that will be instantiated by this manager
 86  
      *
 87  
      * @param omClass the om class
 88  
      */
 89  
     protected void setOMClass(Class omClass)
 90  
     {
 91  0
         this.omClass = omClass;
 92  0
     }
 93  
 
 94  
     /**
 95  
      * Get a fresh instance of an om
 96  
      *
 97  
      * @return an instance of the om class
 98  
      * @throws InstantiationException
 99  
      * @throws IllegalAccessException
 100  
      */
 101  
     protected Persistent getOMInstance()
 102  
         throws InstantiationException, IllegalAccessException
 103  
     {
 104  0
         return (Persistent) omClass.newInstance();
 105  
     }
 106  
 
 107  
     /**
 108  
      * Get the classname to instantiate for getInstance()
 109  
      * @return value of className.
 110  
      */
 111  
     public String getClassName()
 112  
     {
 113  0
         return className;
 114  
     }
 115  
 
 116  
     /**
 117  
      * Set the classname to instantiate for getInstance()
 118  
      * @param v  Value to assign to className.
 119  
      * @throws TorqueException Any exceptions caught during processing will be
 120  
      *         rethrown wrapped into a TorqueException.
 121  
      */
 122  
     public void setClassName(String  v)
 123  
         throws TorqueException
 124  
     {
 125  0
         this.className = v;
 126  
 
 127  
         try
 128  
         {
 129  0
             setOMClass(Class.forName(getClassName()));
 130  
         }
 131  0
         catch (ClassNotFoundException cnfe)
 132  
         {
 133  0
             throw new TorqueException("Could not load " + getClassName());
 134  0
         }
 135  0
     }
 136  
 
 137  
 
 138  
     /**
 139  
      * Return an instance of an om based on the id
 140  
      *
 141  
      * @param id
 142  
      * @throws TorqueException Any exceptions caught during processing will be
 143  
      *         rethrown wrapped into a TorqueException.
 144  
      */
 145  
     protected Persistent getOMInstance(ObjectKey id)
 146  
         throws TorqueException
 147  
     {
 148  0
         return getOMInstance(id, true);
 149  
     }
 150  
 
 151  
     /**
 152  
      * Return an instance of an om based on the id
 153  
      *
 154  
      * @throws TorqueException Any exceptions caught during processing will be
 155  
      *         rethrown wrapped into a TorqueException.
 156  
      */
 157  
     protected Persistent getOMInstance(ObjectKey key, boolean fromCache)
 158  
         throws TorqueException
 159  
     {
 160  0
         Persistent om = null;
 161  0
         if (fromCache)
 162  
         {
 163  0
             om = cacheGet(key);
 164  
         }
 165  
 
 166  0
         if (om == null)
 167  
         {
 168  0
             om = retrieveStoredOM(key);
 169  0
             if (fromCache)
 170  
             {
 171  0
                 putInstanceImpl(om);
 172  
             }
 173  
         }
 174  
 
 175  0
         return om;
 176  
     }
 177  
 
 178  
     protected Persistent cacheGet(Serializable key)
 179  
     {
 180  0
         Persistent om = null;
 181  0
         if (cache != null)
 182  
         {
 183  0
             synchronized (this)
 184  
             {
 185  0
                 om = (Persistent) cache.get(key);
 186  0
             }
 187  
         }
 188  0
         return om;
 189  
     }
 190  
 
 191  
     /**
 192  
      *
 193  
      * @throws TorqueException Any exceptions caught during processing will be
 194  
      *         rethrown wrapped into a TorqueException.
 195  
      */
 196  
     protected void clearImpl()
 197  
         throws TorqueException
 198  
     {
 199  0
         if (cache != null)
 200  
         {
 201  
             try
 202  
             {
 203  0
                 cache.remove();
 204  
             }
 205  0
             catch (CacheException ce)
 206  
             {
 207  0
                 throw new TorqueException(
 208  
                         "Could not clear cache due to internal JCS error.", ce);
 209  0
             }
 210  
         }
 211  0
     }
 212  
 
 213  
     /**
 214  
      *
 215  
      * @param key
 216  
      * @return
 217  
      * @throws TorqueException Any exceptions caught during processing will be
 218  
      *         rethrown wrapped into a TorqueException.
 219  
      */
 220  
     protected Persistent removeInstanceImpl(Serializable key)
 221  
         throws TorqueException
 222  
     {
 223  0
         Persistent oldOm = null;
 224  0
         if (cache != null)
 225  
         {
 226  
             try
 227  
             {
 228  0
                 synchronized (this)
 229  
                 {
 230  0
                     oldOm = (Persistent) cache.get(key);
 231  0
                     cache.remove(key);
 232  0
                 }
 233  
             }
 234  0
             catch (CacheException ce)
 235  
             {
 236  0
                 throw new TorqueException
 237  
                     ("Could not remove from cache due to internal JCS error",
 238  
                      ce);
 239  0
             }
 240  
         }
 241  0
         return oldOm;
 242  
     }
 243  
 
 244  
     /**
 245  
      *
 246  
      * @param om
 247  
      * @return
 248  
      * @throws TorqueException Any exceptions caught during processing will be
 249  
      *         rethrown wrapped into a TorqueException.
 250  
      */
 251  
     protected Persistent putInstanceImpl(Persistent om)
 252  
         throws TorqueException
 253  
     {
 254  0
         ObjectKey key = om.getPrimaryKey();
 255  0
         return putInstanceImpl(key, om);
 256  
     }
 257  
 
 258  
     /**
 259  
      *
 260  
      * @param key
 261  
      * @param om
 262  
      * @return
 263  
      * @throws TorqueException Any exceptions caught during processing will be
 264  
      *         rethrown wrapped into a TorqueException.
 265  
      */
 266  
     protected Persistent putInstanceImpl(Serializable key, Persistent om)
 267  
         throws TorqueException
 268  
     {
 269  0
         if (getOMClass() != null && !getOMClass().isInstance(om))
 270  
         {
 271  0
             throw new TorqueException(om + "; class=" + om.getClass().getName()
 272  
                 + "; id=" + om.getPrimaryKey() + " cannot be cached with "
 273  
                 + getOMClass().getName() + " objects");
 274  
         }
 275  
 
 276  0
         Persistent oldOm = null;
 277  0
         if (cache != null)
 278  
         {
 279  
             try
 280  
             {
 281  0
                 synchronized (this)
 282  
                 {
 283  0
                     oldOm = (Persistent) cache.get(key);
 284  0
                     cache.put(key, om);
 285  0
                 }
 286  
             }
 287  0
             catch (CacheException ce)
 288  
             {
 289  0
                 throw new TorqueException
 290  
                     ("Could not cache due to internal JCS error", ce);
 291  0
             }
 292  
         }
 293  0
         return oldOm;
 294  
     }
 295  
 
 296  
     /**
 297  
      *
 298  
      * @param id
 299  
      * @return
 300  
      * @throws TorqueException Any exceptions caught during processing will be
 301  
      *         rethrown wrapped into a TorqueException.
 302  
      */
 303  
     protected abstract Persistent retrieveStoredOM(ObjectKey id)
 304  
         throws TorqueException;
 305  
 
 306  
     /**
 307  
      * Gets a list of om's based on id's.
 308  
      *
 309  
      * @param ids a <code>ObjectKey[]</code> value
 310  
      * @return a <code>List</code> value
 311  
      * @throws TorqueException Any exceptions caught during processing will be
 312  
      *         rethrown wrapped into a TorqueException.
 313  
      */
 314  
     protected List getOMs(ObjectKey[] ids)
 315  
         throws TorqueException
 316  
     {
 317  0
         return getOMs(Arrays.asList(ids));
 318  
     }
 319  
 
 320  
     /**
 321  
      * Gets a list of om's based on id's.
 322  
      *
 323  
      * @param ids a <code>List</code> of <code>ObjectKey</code>'s
 324  
      * @return a <code>List</code> value
 325  
      * @throws TorqueException Any exceptions caught during processing will be
 326  
      *         rethrown wrapped into a TorqueException.
 327  
      */
 328  
     protected List getOMs(List ids)
 329  
         throws TorqueException
 330  
     {
 331  0
         return getOMs(ids, true);
 332  
     }
 333  
 
 334  
     /**
 335  
      * Gets a list of om's based on id's.
 336  
      *
 337  
      * @param ids a <code>List</code> of <code>ObjectKey</code>'s
 338  
      * @return a <code>List</code> value
 339  
      * @throws TorqueException Any exceptions caught during processing will be
 340  
      *         rethrown wrapped into a TorqueException.
 341  
      */
 342  
     protected List getOMs(List ids, boolean fromCache)
 343  
         throws TorqueException
 344  
     {
 345  0
         List oms = null;
 346  0
         if (ids != null && ids.size() > 0)
 347  
         {
 348  
             // start a new list where we will replace the id's with om's
 349  0
             oms = new ArrayList(ids);
 350  0
             List newIds = new ArrayList(ids.size());
 351  0
             for (int i = 0; i < ids.size(); i++)
 352  
             {
 353  0
                 ObjectKey key = (ObjectKey) ids.get(i);
 354  0
                 Persistent om = null;
 355  0
                 if (fromCache)
 356  
                 {
 357  0
                     om = cacheGet(key);
 358  
                 }
 359  0
                 if (om == null)
 360  
                 {
 361  0
                     newIds.add(key);
 362  
                 }
 363  
                 else
 364  
                 {
 365  0
                     oms.set(i, om);
 366  
                 }
 367  
             }
 368  
 
 369  0
             if (newIds.size() > 0)
 370  
             {
 371  0
                 List newOms = retrieveStoredOMs(newIds);
 372  0
                 for (int i = 0; i < oms.size(); i++)
 373  
                 {
 374  0
                     if (oms.get(i) instanceof ObjectKey)
 375  
                     {
 376  0
                         for (int j = newOms.size() - 1; j >= 0; j--)
 377  
                         {
 378  0
                             Persistent om = (Persistent) newOms.get(j);
 379  0
                             if (om.getPrimaryKey().equals(oms.get(i)))
 380  
                             {
 381  
                                 // replace the id with the om and add the om
 382  
                                 // to the cache
 383  0
                                 oms.set(i, om);
 384  0
                                 newOms.remove(j);
 385  0
                                 if (fromCache)
 386  
                                 {
 387  0
                                     putInstanceImpl(om);
 388  
                                 }
 389  
                                 break;
 390  
                             }
 391  
                         }
 392  
                     }
 393  
                 }
 394  
             }
 395  
         }
 396  0
         return oms;
 397  
     }
 398  
 
 399  
     /**
 400  
      *
 401  
      * @param ids
 402  
      * @return
 403  
      * @throws TorqueException Any exceptions caught during processing will be
 404  
      *         rethrown wrapped into a TorqueException.
 405  
      */
 406  
     protected abstract List retrieveStoredOMs(List ids)
 407  
         throws TorqueException;
 408  
 
 409  
     /**
 410  
      * Get the value of region.
 411  
      *
 412  
      * @return value of region.
 413  
      */
 414  
     public String getRegion()
 415  
     {
 416  0
         return region;
 417  
     }
 418  
 
 419  
     /**
 420  
      * Set the value of region.
 421  
      *
 422  
      * @param v  Value to assign to region.
 423  
      * @throws TorqueException Any exceptions caught during processing will be
 424  
      *         rethrown wrapped into a TorqueException.
 425  
      */
 426  
     public void setRegion(String v)
 427  
         throws TorqueException
 428  
     {
 429  0
         this.region = v;
 430  
         try
 431  
         {
 432  0
             if (Torque.getConfiguration().getBoolean(Torque.CACHE_KEY, false))
 433  
             {
 434  0
                 cache = JCS.getInstance(getRegion());
 435  0
                 mrCache = new MethodResultCache(cache);
 436  
             }
 437  
             else
 438  
             {
 439  0
                 mrCache = new NoOpMethodResultCache(cache);
 440  
             }
 441  
         }
 442  0
         catch (Exception e)
 443  
         {
 444  0
             throw new TorqueException("Cache could not be initialized", e);
 445  0
         }
 446  0
         if (cache == null)
 447  
         {
 448  0
             log.info("Cache could not be initialized for region: " + v);
 449  
         }
 450  0
     }
 451  
 
 452  
     /**
 453  
      * @return The cache instance.
 454  
      */
 455  
     public MethodResultCache getMethodResultCache()
 456  
     {
 457  0
         if (isNew)
 458  
         {
 459  0
             synchronized (this)
 460  
             {
 461  0
                 if (isNew)
 462  
                 {
 463  0
                     registerAsListener();
 464  0
                     isNew = false;
 465  
                 }
 466  0
             }
 467  
         }
 468  0
         return mrCache;
 469  
     }
 470  
 
 471  
     /**
 472  
      * NoOp version.  Managers should override this method to notify other
 473  
      * managers that they are interested in CacheEvents.
 474  
      */
 475  
     protected void registerAsListener()
 476  
     {
 477  0
     }
 478  
 
 479  
     /**
 480  
      *
 481  
      * @param listener A new listener for cache events.
 482  
      */
 483  
     public void addCacheListenerImpl(CacheListener listener)
 484  
     {
 485  0
         List keys = listener.getInterestedFields();
 486  0
         Iterator i = keys.iterator();
 487  0
         while (i.hasNext())
 488  
         {
 489  0
             String key = (String) i.next();
 490  
             // Peer.column names are the fields
 491  0
             if (validFields != null && validFields.containsKey(key))
 492  
             {
 493  0
                 List listeners = (List) listenersMap.get(key);
 494  0
                 if (listeners == null)
 495  
                 {
 496  0
                     listeners = createSubsetList(key);
 497  
                 }
 498  
 
 499  0
                 boolean isNew = true;
 500  0
                 Iterator j = listeners.iterator();
 501  0
                 while (j.hasNext())
 502  
                 {
 503  0
                     Object listener2 =
 504  
                         ((WeakReference) j.next()).get();
 505  0
                     if (listener2 == null)
 506  0
                     {
 507  
                         // do a little cleanup while checking for dupes
 508  
                         // not thread-safe, not likely to be many nulls
 509  
                         // but should revisit
 510  
                         //j.remove();
 511  
                     }
 512  0
                     else if (listener2 == listener)
 513  
                     {
 514  0
                         isNew = false;
 515  0
                         break;
 516  
                     }
 517  
                 }
 518  0
                 if (isNew)
 519  
                 {
 520  0
                     listeners.add(new WeakReference(listener));
 521  
                 }
 522  
             }
 523  
         }
 524  0
     }
 525  
 
 526  
     /**
 527  
      *
 528  
      * @param key
 529  
      * @return A subset of the list identified by <code>key</code>.
 530  
      */
 531  
     private synchronized List createSubsetList(String key)
 532  
     {
 533  0
         FastArrayList list = null;
 534  0
         if (listenersMap.containsKey(key))
 535  
         {
 536  0
             list = (FastArrayList) listenersMap.get(key);
 537  
         }
 538  
         else
 539  
         {
 540  0
             list = new FastArrayList();
 541  0
             list.setFast(true);
 542  0
             listenersMap.put(key, list);
 543  
         }
 544  0
         return list;
 545  
     }
 546  
 
 547  
     /**
 548  
      *
 549  
      * @param listeners
 550  
      * @param oldOm
 551  
      * @param om
 552  
      */
 553  
     protected void notifyListeners(List listeners,
 554  
                                    Persistent oldOm, Persistent om)
 555  
     {
 556  0
         if (listeners != null)
 557  
         {
 558  0
             synchronized (listeners)
 559  
             {
 560  0
                 Iterator i = listeners.iterator();
 561  0
                 while (i.hasNext())
 562  
                 {
 563  0
                     CacheListener listener = (CacheListener)
 564  
                         ((WeakReference) i.next()).get();
 565  0
                     if (listener == null)
 566  
                     {
 567  
                         // remove reference as its object was cleared
 568  0
                         i.remove();
 569  
                     }
 570  
                     else
 571  
                     {
 572  0
                         if (oldOm == null)
 573  
                         {
 574  
                             // object was added
 575  0
                             listener.addedObject(om);
 576  
                         }
 577  
                         else
 578  
                         {
 579  
                             // object was refreshed
 580  0
                             listener.refreshedObject(om);
 581  
                         }
 582  
                     }
 583  
                 }
 584  0
             }
 585  
         }
 586  0
     }
 587  
 
 588  
 
 589  
     /**
 590  
      * helper methods for the Serializable interface
 591  
      *
 592  
      * @param out
 593  
      * @throws IOException
 594  
      */
 595  
     private void writeObject(java.io.ObjectOutputStream out)
 596  
         throws IOException
 597  
     {
 598  0
         out.defaultWriteObject();
 599  0
     }
 600  
 
 601  
     /**
 602  
      * Helper methods for the <code>Serializable</code> interface.
 603  
      *
 604  
      * @param in The stream to read a <code>Serializable</code> from.
 605  
      * @throws IOException
 606  
      * @throws ClassNotFoundException
 607  
      */
 608  
     private void readObject(ObjectInputStream in)
 609  
         throws IOException, ClassNotFoundException
 610  
     {
 611  0
         in.defaultReadObject();
 612  
         // initialize the cache
 613  
         try
 614  
         {
 615  0
             if (region != null)
 616  
             {
 617  0
                 setRegion(region);
 618  
             }
 619  
         }
 620  0
         catch (Exception e)
 621  
         {
 622  0
             log.error("Cache could not be initialized for region '"
 623  
                       + region + "' after deserialization");
 624  0
         }
 625  0
     }
 626  
 }

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