Coverage Report - org.apache.ojb.broker.metadata.SuperReferenceDescriptor
 
Classes in this File Line Coverage Branch Coverage Complexity
SuperReferenceDescriptor
N/A
N/A
2.208
SuperReferenceDescriptor$SuperReferenceField
N/A
N/A
2.208
 
 1  
 package org.apache.ojb.broker.metadata;
 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.List;
 19  
 import java.util.Map;
 20  
 import java.util.HashMap;
 21  
 
 22  
 import org.apache.commons.lang.SystemUtils;
 23  
 import org.apache.ojb.broker.metadata.fieldaccess.AnonymousPersistentField;
 24  
 import org.apache.ojb.broker.metadata.fieldaccess.PersistentField;
 25  
 import org.apache.ojb.broker.metadata.fieldaccess.PersistentFieldFactory;
 26  
 import org.apache.ojb.broker.util.ClassHelper;
 27  
 import org.apache.ojb.broker.util.logging.Logger;
 28  
 import org.apache.ojb.broker.util.logging.LoggerFactory;
 29  
 
 30  
 /**
 31  
  * This class handle inheritance as 1-1 association based on a anonymous field
 32  
  * (no field in persistent object needed).
 33  
  *
 34  
  * @version $Id: SuperReferenceDescriptor.java,v 1.1 2007-08-24 22:17:29 ewestfal Exp $
 35  
  */
 36  
 public class SuperReferenceDescriptor extends ObjectReferenceDescriptor
 37  
 {
 38  
     private transient Logger log;
 39  
 
 40  
     public static final String SUPER_FIELD_INTERNAL_NAME = "ojbSuperFieldInternal";
 41  
     public static final String SUPER_FIELD_NAME = RepositoryElements.TAG_SUPER;
 42  
 
 43  
     private Boolean javaInheritance;
 44  
     private Map declaredInheritanceFields = new HashMap();
 45  
 
 46  
     public SuperReferenceDescriptor(ClassDescriptor descriptor)
 47  
     {
 48  
         super(descriptor);
 49  
         // most important call, create new specific field for inheritance
 50  
         super.setPersistentField(new SuperReferenceField(this));
 51  
         // needed immutable settings
 52  
         super.setLazy(false);
 53  
         super.setCascadeRetrieve(true);
 54  
         super.setCascadingStore(CASCADE_OBJECT);
 55  
         super.setCascadingDelete(CASCADE_OBJECT);
 56  
     }
 57  
 
 58  
     public boolean isSuperReferenceDescriptor()
 59  
     {
 60  
         return true;
 61  
     }
 62  
 
 63  
     public void setItemClass(Class c)
 64  
     {
 65  
         super.setItemClass(c);
 66  
         getClassDescriptor().setBaseClass(c.getName());
 67  
     }
 68  
 
 69  
     /**
 70  
      * Noop, a specific {@link org.apache.ojb.broker.metadata.fieldaccess.PersistentField} is
 71  
      * used internal - {@link org.apache.ojb.broker.metadata.SuperReferenceDescriptor.SuperReferenceField}.
 72  
      */
 73  
     public void setPersistentField(Class c, String fieldname)
 74  
     {
 75  
         // noop
 76  
     }
 77  
 
 78  
     /**
 79  
      * Noop, a specific {@link org.apache.ojb.broker.metadata.fieldaccess.PersistentField} is
 80  
      * used internal - {@link org.apache.ojb.broker.metadata.SuperReferenceDescriptor.SuperReferenceField}.
 81  
      */
 82  
     public void setPersistentField(PersistentField pf)
 83  
     {
 84  
         // noop
 85  
     }
 86  
 
 87  
     public void setLazy(boolean lazy)
 88  
     {
 89  
         getLog().info("Not allowed to change this property, will ignore setting");
 90  
     }
 91  
 
 92  
     public void setCascadeRetrieve(boolean b)
 93  
     {
 94  
         getLog().info("Not allowed to change this property, will ignore setting");
 95  
     }
 96  
 
 97  
     public void setCascadingStore(int cascade)
 98  
     {
 99  
         getLog().info("Not allowed to change this property, will ignore setting");
 100  
     }
 101  
 
 102  
     public void setCascadingStore(String value)
 103  
     {
 104  
         getLog().info("Not allowed to change this property, will ignore setting");
 105  
     }
 106  
 
 107  
     public void setCascadingDelete(int cascade)
 108  
     {
 109  
         getLog().info("Not allowed to change this property, will ignore setting");
 110  
     }
 111  
 
 112  
     public void setCascadingDelete(String value)
 113  
     {
 114  
         getLog().info("Not allowed to change this property, will ignore setting");
 115  
     }
 116  
 
 117  
     public void setCascadeStore(boolean cascade)
 118  
     {
 119  
         getLog().info("Not allowed to change this property, will ignore setting");
 120  
     }
 121  
 
 122  
     public void setCascadeDelete(boolean cascade)
 123  
     {
 124  
         getLog().info("Not allowed to change this property, will ignore setting");
 125  
     }
 126  
 
 127  
     public SuperReferenceField getInheritanceField()
 128  
     {
 129  
         return (SuperReferenceField) getPersistentField();
 130  
     }
 131  
 
 132  
     /**
 133  
      * If this method returns <em>true</em> the inheritance described by this object
 134  
      * is a <em>normal</em> JAVA inheritance. If <em>false</em> the inheritance is only declared
 135  
      * in the O/R mapping it's a <em>declarative inheritance</em>, the referenced "super class" in <strong>not</strong>
 136  
      * a JAVA super class of the main class.
 137  
      */
 138  
     public boolean isJavaInheritance()
 139  
     {
 140  
         if(javaInheritance == null)
 141  
         {
 142  
             javaInheritance = getClassDescriptor().getSuperClassDescriptor().getClassOfObject()
 143  
                     .isAssignableFrom(getClassDescriptor().getClassOfObject()) ? Boolean.TRUE : Boolean.FALSE;
 144  
         }
 145  
         return javaInheritance.booleanValue();
 146  
     }
 147  
 
 148  
     synchronized PersistentField getDeclaredInheritanceField(Class target, String name)
 149  
     {
 150  
         Map fields = (HashMap) declaredInheritanceFields.get(target);
 151  
         if(fields == null)
 152  
         {
 153  
             fields = new HashMap();
 154  
             declaredInheritanceFields.put(target, fields);
 155  
         }
 156  
         PersistentField pf = (PersistentField) fields.get(name);
 157  
         if(pf == null)
 158  
         {
 159  
             pf = PersistentFieldFactory.createPersistentField(target, name);
 160  
             // System.out.println("## tmp field: " + target + ", name: " + name + ", field: " + pf);
 161  
             fields.put(name, pf);
 162  
         }
 163  
         return pf;
 164  
     }
 165  
 
 166  
     private Logger getLog()
 167  
     {
 168  
         if(log == null)
 169  
         {
 170  
             log = LoggerFactory.getLogger(SuperReferenceField.class);
 171  
         }
 172  
         return log;
 173  
     }
 174  
 
 175  
 
 176  
     //====================================================
 177  
     // inner class
 178  
     //====================================================
 179  
 
 180  
     public static final class SuperReferenceField extends AnonymousPersistentField
 181  
     {
 182  
         private transient Logger log;
 183  
 
 184  
         private SuperReferenceDescriptor superRef;
 185  
 
 186  
         public SuperReferenceField(SuperReferenceDescriptor superRef)
 187  
         {
 188  
             super(SUPER_FIELD_INTERNAL_NAME);
 189  
             this.superRef = superRef;
 190  
         }
 191  
 
 192  
         private Logger getLog()
 193  
         {
 194  
             if(log == null)
 195  
             {
 196  
                 log = LoggerFactory.getLogger(SuperReferenceField.class);
 197  
             }
 198  
             return log;
 199  
         }
 200  
 
 201  
         /**
 202  
          * Field values of 'value' (base object) are copied to 'obj' (derived object)
 203  
          * then obj is saved in a map
 204  
          *
 205  
          * @param target - the base object instance
 206  
          * @param value  - the derived object instance
 207  
          * @throws MetadataException
 208  
          */
 209  
         public synchronized void set(Object target, Object value) throws MetadataException
 210  
         {
 211  
             // System.out.println("target: " + target + " value: " + value);
 212  
             ClassDescriptor superCld = superRef.getClassDescriptor().getSuperClassDescriptor();
 213  
             if(superRef.isJavaInheritance())
 214  
             {
 215  
                 copyFields(superCld, target, superCld, value, true, true);
 216  
             }
 217  
             else
 218  
             {
 219  
                 copyFields(superRef.getClassDescriptor(), target, superCld, value, false, false);
 220  
             }
 221  
         }
 222  
 
 223  
         /**
 224  
          * Field values of specified 'obj' (the derived object) are copied to
 225  
          * 'value' (base object) then value is returned as a referenced object.
 226  
          * If the base object is the super class of the specified 'obj', then
 227  
          * return the specified object.
 228  
          * Else a base class instance will be created at runtime and the field values
 229  
          * from the derived object are copied to the base class object.
 230  
          *
 231  
          * @param obj - the base object instance
 232  
          * @throws MetadataException
 233  
          */
 234  
         public synchronized Object get(Object obj) throws MetadataException
 235  
         {
 236  
             if(obj == null) return null;
 237  
             if(superRef.isJavaInheritance())
 238  
             {
 239  
                 return obj;
 240  
             }
 241  
             else
 242  
             {
 243  
                 return getObjectWithDeclaredSuperClass(obj);
 244  
             }
 245  
         }
 246  
 
 247  
         private Object getObjectWithDeclaredSuperClass(Object obj)
 248  
         {
 249  
             Object value = getFromFieldCache(obj);
 250  
             if(value == null)
 251  
             {
 252  
                 ClassDescriptor baseCld = null;
 253  
                 try
 254  
                 {
 255  
                     baseCld = superRef.getClassDescriptor().getSuperClassDescriptor();
 256  
                     value = ClassHelper.buildNewObjectInstance(baseCld);
 257  
                 }
 258  
                 catch(Exception e)
 259  
                 {
 260  
                     throw new MetadataException("Can't create new base class object for '"
 261  
                             + (baseCld != null ? baseCld.getClassNameOfObject() : null) + "'", e);
 262  
                 }
 263  
                 copyFields(baseCld, value, superRef.getClassDescriptor(), obj, true, false);
 264  
                 putToFieldCache(obj, value);
 265  
             }
 266  
             return value;
 267  
         }
 268  
 
 269  
         void copyFields(ClassDescriptor targetCld, Object target, ClassDescriptor sourceCld, Object source, boolean targetIsSuper, boolean javaInheritance)
 270  
         {
 271  
             if(getLog().isDebugEnabled())
 272  
             {
 273  
                 String msg = ("Copy fields from " + SystemUtils.LINE_SEPARATOR
 274  
                         + "source object '" + (source != null ? source.getClass().getName() : null) + "'" + SystemUtils.LINE_SEPARATOR
 275  
                         + "using source fields declared in '" + sourceCld.getClassNameOfObject() + "'" + SystemUtils.LINE_SEPARATOR
 276  
                         + "to target object '" + (target != null ? target.getClass().getName() : null) + "'" + SystemUtils.LINE_SEPARATOR
 277  
                         + "using target fields declared in '" + targetCld.getClassNameOfObject() + "'" + SystemUtils.LINE_SEPARATOR
 278  
                         + "the fields to copy are declared in '" + (targetIsSuper ? targetCld.getClassNameOfObject() : sourceCld.getClassNameOfObject()) + "' class" + SystemUtils.LINE_SEPARATOR
 279  
                         + "the used classes are associated by java inheritance: " + javaInheritance + SystemUtils.LINE_SEPARATOR);
 280  
                 getLog().debug(msg);
 281  
             }
 282  
             /*
 283  
             arminw:
 284  
             If the target object is a super object of the source object, iterate all target object fields.
 285  
             If the source object is a super object of the target object, iterate all source object fields
 286  
 
 287  
             If java inheritance is used (target is super class of source or vice versa) we can use the same
 288  
             FieldDescriptor to copy the fields.
 289  
             If only a "declarative inheritance" is used (no class inheritance, only identical field names of the super class)
 290  
             we have to use the associated FieldDescriptor of target and source ClassDescriptor
 291  
             */
 292  
             FieldDescriptor[] fields = targetIsSuper ? targetCld.getFieldDescriptions() : sourceCld.getFieldDescriptions();
 293  
             for(int i = 0; i < fields.length; i++)
 294  
             {
 295  
                 FieldDescriptor field = fields[i];
 296  
                 if(!field.isAnonymous())
 297  
                 {
 298  
                     performFieldCopy(target,  targetCld, source, sourceCld,
 299  
                                 field.getPersistentField(), targetIsSuper, javaInheritance);
 300  
                 }
 301  
             }
 302  
             List refs = targetIsSuper ? targetCld.getCollectionDescriptors() : sourceCld.getCollectionDescriptors();
 303  
             for(int i = 0; i < refs.size(); i++)
 304  
             {
 305  
                 CollectionDescriptor col = (CollectionDescriptor) refs.get(i);
 306  
                 PersistentField pf = col.getPersistentField();
 307  
                 performFieldCopy(target,  targetCld, source, sourceCld, pf, targetIsSuper, javaInheritance);
 308  
             }
 309  
 
 310  
             refs = targetIsSuper ? targetCld.getObjectReferenceDescriptors() : sourceCld.getObjectReferenceDescriptors();
 311  
             for(int i = 0; i < refs.size(); i++)
 312  
             {
 313  
                 ObjectReferenceDescriptor ord = (ObjectReferenceDescriptor) refs.get(i);
 314  
                 PersistentField pf = ord.getPersistentField();
 315  
                 performFieldCopy(target,  targetCld, source, sourceCld, pf, targetIsSuper, javaInheritance);
 316  
             }
 317  
         }
 318  
 
 319  
         private void performFieldCopy(Object target, ClassDescriptor targetCld, Object source,
 320  
                                  ClassDescriptor sourceCld, PersistentField pf, boolean targetIsSuper, boolean javaInheritance)
 321  
         {
 322  
             if(javaInheritance)
 323  
             {
 324  
                 pf.set(target, pf.get(source));
 325  
             }
 326  
             else
 327  
             {
 328  
                 if(targetIsSuper)
 329  
                 {
 330  
                     if(pf instanceof SuperReferenceField)
 331  
                     {
 332  
                         log.error("Declared inheritance doesn't support nested super references, target '"
 333  
                                 + targetCld.getClassNameOfObject() + "' has super reference");
 334  
                     }
 335  
                     else
 336  
                     {
 337  
                         PersistentField tmp = superRef.getDeclaredInheritanceField(sourceCld.getClassOfObject(), pf.getName());
 338  
                         pf.set(target, tmp.get(source));
 339  
                     }
 340  
                 }
 341  
                 else
 342  
                 {
 343  
                     PersistentField tmp = superRef.getDeclaredInheritanceField(targetCld.getClassOfObject(), pf.getName());
 344  
                     tmp.set(target, pf.get(source));
 345  
                 }
 346  
             }
 347  
         }
 348  
     }
 349  
 }
 350