Coverage Report - org.apache.ojb.broker.metadata.fieldaccess.AnonymousPersistentField
 
Classes in this File Line Coverage Branch Coverage Complexity
AnonymousPersistentField
N/A
N/A
1.556
 
 1  
 package org.apache.ojb.broker.metadata.fieldaccess;
 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.Map;
 19  
 
 20  
 import org.apache.commons.collections.map.ReferenceIdentityMap;
 21  
 import org.apache.ojb.broker.metadata.MetadataException;
 22  
 
 23  
 /**
 24  
  * This class handle an anonymous persistent fiels for 1-1 association,
 25  
  * and ojbConcreteClass
 26  
  * @author Houar TINE
 27  
  * @version $Id: AnonymousPersistentField.java,v 1.1 2007-08-24 22:17:35 ewestfal Exp $
 28  
  */
 29  
 public class AnonymousPersistentField implements PersistentField
 30  
 {
 31  
     private static final long serialVersionUID = 3989863424358352941L;
 32  
 
 33  
     private transient Map fkCache;
 34  
     private String fieldname;
 35  
 
 36  
     public AnonymousPersistentField(String fieldname)
 37  
     {
 38  
         this.fieldname = fieldname;
 39  
     }
 40  
 
 41  
     public synchronized void set(Object obj, Object value) throws MetadataException
 42  
     {
 43  
         putToFieldCache(obj, value);
 44  
     }
 45  
 
 46  
     public synchronized Object get(Object anObject) throws MetadataException
 47  
     {
 48  
         return getFromFieldCache(anObject);
 49  
     }
 50  
 
 51  
 /*
 52  
     Use ReferenceIdentityMap (with weak key and hard value setting) instead of
 53  
     WeakHashMap to hold anonymous field values. Here is an snip of the mail from Andy Malakov:
 54  
     <snip>
 55  
         I found that usage of database identity in Java produces quite interesting problem in OJB:
 56  
         In my application all persistent Java objects use database identity instead of Java reference identity
 57  
         (i.e. Persistable.equals() is redefined so that two persistent objects are the same if they have the same
 58  
         primary key and top-level class).
 59  
 
 60  
         In OJB, for each field declared in repository there is dedicated instance of AnonymousPersistentField that stores
 61  
         object-to-field-value mapping in WeakHashMap (in fkCache attribute). Despite usage of cache
 62  
         (ObjectCachePerBrokerImpl in my case) it is possible that identical DB objects will end up as different
 63  
         Java objects during retrieval of complex objects.
 64  
 
 65  
         Now imagine what happens when two identical instances are retrieved:
 66  
         1)
 67  
         When first instance is retrieved it stores its foreign keys in AnonymousPersistentField.fkCache under instance's
 68  
         identity. (happens in RowReaderDefaultImpl.buildWithReflection())
 69  
         2)
 70  
         When second object is retrieved and stored in fkCache, first instance is probably still cached
 71  
         [WeakHashMap entries are cleaned up only during GC]. Since keys are identical WeakHashMap only updates entry
 72  
         value and DOES NOT update entry key.
 73  
         3)
 74  
         If Full GC happens after that moment it will dispose fcCache entry if the FIRST reference becomes
 75  
         soft-referenced only.
 76  
     </snip>
 77  
 */
 78  
     protected void putToFieldCache(Object key, Object value)
 79  
     {
 80  
         if (key != null)
 81  
         {
 82  
             if (fkCache == null)
 83  
             {
 84  
                 fkCache = new ReferenceIdentityMap (ReferenceIdentityMap.WEAK, ReferenceIdentityMap.HARD, true);
 85  
             }
 86  
             if (value != null)
 87  
                  fkCache.put(key, value);
 88  
              else
 89  
                  fkCache.remove (key);
 90  
         }
 91  
     }
 92  
 
 93  
     protected Object getFromFieldCache(Object key)
 94  
     {
 95  
         return (key != null && fkCache != null) ? fkCache.get(key) : null;
 96  
     }
 97  
 
 98  
     /**
 99  
      * Always returns <tt>null</tt>.
 100  
      * @see PersistentField#getDeclaringClass()
 101  
      */
 102  
     public Class getDeclaringClass()
 103  
     {
 104  
         return null;
 105  
     }
 106  
 
 107  
     /**
 108  
      * @see PersistentField#getName()
 109  
      */
 110  
     public String getName()
 111  
     {
 112  
         return fieldname;
 113  
     }
 114  
 
 115  
     /**
 116  
      * Always returns <tt>null</tt>.
 117  
      * @see PersistentField#getType()
 118  
      */
 119  
     public Class getType()
 120  
     {
 121  
         return null;
 122  
     }
 123  
 
 124  
     /**
 125  
      * Returns <tt>false</tt>.
 126  
      * @see PersistentField#usesAccessorsAndMutators()
 127  
      */
 128  
     public boolean usesAccessorsAndMutators()
 129  
     {
 130  
         return false;
 131  
     }
 132  
 }