Coverage Report - org.apache.ojb.broker.metadata.fieldaccess.PersistentFieldIntrospectorImpl
 
Classes in this File Line Coverage Branch Coverage Complexity
PersistentFieldIntrospectorImpl
N/A
N/A
3.643
 
 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.beans.BeanInfo;
 19  
 import java.beans.IntrospectionException;
 20  
 import java.beans.Introspector;
 21  
 import java.beans.PropertyDescriptor;
 22  
 import java.lang.reflect.Method;
 23  
 import java.util.ArrayList;
 24  
 import java.util.List;
 25  
 
 26  
 import org.apache.commons.lang.StringUtils;
 27  
 import org.apache.ojb.broker.core.proxy.ProxyHelper;
 28  
 import org.apache.ojb.broker.metadata.MetadataException;
 29  
 import org.apache.ojb.broker.util.ClassHelper;
 30  
 import org.apache.ojb.broker.util.logging.Logger;
 31  
 
 32  
 /**
 33  
  * A {@link PersistentField} implementation using
 34  
  * JavaBeans compliant calls only to access persistent attributes.
 35  
  * No Reflection is needed. But for each attribute xxx there must be
 36  
  * public getXxx() and setXxx() methods. In metadata the field name must be
 37  
  * the bean compliant 'xxx'.
 38  
  *
 39  
  * @version $Id: PersistentFieldIntrospectorImpl.java,v 1.1 2007-08-24 22:17:35 ewestfal Exp $
 40  
  */
 41  
 public class PersistentFieldIntrospectorImpl extends PersistentFieldBase
 42  
 {
 43  
     private static final long serialVersionUID = 8805309492150404444L;
 44  
     private Class type;
 45  
     private transient List propertyGraph;
 46  
 
 47  
     public PersistentFieldIntrospectorImpl()
 48  
     {
 49  
         super();
 50  
     }
 51  
 
 52  
     public PersistentFieldIntrospectorImpl(Class aClass, String aPropertyName)
 53  
     {
 54  
         super(aClass, aPropertyName);
 55  
     }
 56  
 
 57  
     public Class getType()
 58  
     {
 59  
         if (type == null)
 60  
         {
 61  
             type = getPropertyDescriptor().getPropertyType();
 62  
         }
 63  
         return type;
 64  
     }
 65  
 
 66  
     public void set(Object target, Object value) throws MetadataException
 67  
     {
 68  
         if(target == null) return;
 69  
         List propertyDescriptors = getPropertyGraph();
 70  
         int size = propertyDescriptors.size() - 1;
 71  
         PropertyDescriptor pd;
 72  
         for (int i = 0; i < size; i++)
 73  
         {
 74  
             Object attribute;
 75  
             pd = (PropertyDescriptor) propertyDescriptors.get(i);
 76  
             attribute = getValueFrom(pd, target);
 77  
             if (attribute != null || value != null)
 78  
             {
 79  
                 if (attribute == null)
 80  
                 {
 81  
                     try
 82  
                     {
 83  
                         attribute = ClassHelper.newInstance(pd.getPropertyType());
 84  
                     }
 85  
                     catch (Exception e)
 86  
                     {
 87  
                         throw new MetadataException("Can't instantiate nested object of type '"
 88  
                                 + pd.getPropertyType() + "' for field '"
 89  
                                 + pd.getName() + "'", e);
 90  
                     }
 91  
                 }
 92  
                 setValueFor(pd, target, attribute);
 93  
             }
 94  
             else
 95  
             {
 96  
                 return;
 97  
             }
 98  
             target = attribute;
 99  
         }
 100  
         pd = (PropertyDescriptor) propertyDescriptors.get(size);
 101  
         setValueFor(pd, target, value);
 102  
     }
 103  
 
 104  
     public Object get(Object target) throws MetadataException
 105  
     {
 106  
         List propertyDescriptors = getPropertyGraph();
 107  
         for (int i = 0; i < propertyDescriptors.size(); i++)
 108  
         {
 109  
             PropertyDescriptor pd = (PropertyDescriptor) propertyDescriptors.get(i);
 110  
             target = getValueFrom(pd, target);
 111  
             if (target == null) break;
 112  
         }
 113  
         return target;
 114  
     }
 115  
 
 116  
     private Object getValueFrom(PropertyDescriptor pd, Object target)
 117  
     {
 118  
         if (target == null) return null;
 119  
         Method m = pd.getReadMethod();
 120  
         if (m != null)
 121  
         {
 122  
             try
 123  
             {
 124  
                 return m.invoke(ProxyHelper.getRealObject(target), null);
 125  
             }
 126  
             catch (Throwable e)
 127  
             {
 128  
                 logProblem(pd, target, null, "Can't read value from given object");
 129  
                 throw new MetadataException("Error invoking method:" + m.getName() + " in object " + target.getClass().getName(), e);
 130  
             }
 131  
         }
 132  
         else
 133  
         {
 134  
             throw new MetadataException("Can't get ReadMethod for property:" + pd.getName() + " in object " + target.getClass().getName());
 135  
         }
 136  
     }
 137  
 
 138  
     private void setValueFor(PropertyDescriptor pd, Object target, Object value)
 139  
     {
 140  
         Method m = pd.getWriteMethod();
 141  
         Object[] args = {value};
 142  
         if (m != null)
 143  
         {
 144  
             try
 145  
             {
 146  
                 /**
 147  
                  * MBAIRD: it is safe to call getParameterTypes()[0] because this is
 148  
                  * the "set" method and it needs to take one parameter only.
 149  
                  * we need to be able to set values to null. We can only set something to null if
 150  
                  * the type is not a primitive (assignable from Object).
 151  
                  */
 152  
                 if ((value != null) || !m.getParameterTypes()[0].isPrimitive())
 153  
                 {
 154  
                     m.invoke(ProxyHelper.getRealObject(target), args);
 155  
                 }
 156  
             }
 157  
             catch (Throwable e)
 158  
             {
 159  
                 logProblem(pd, target, value, "Can't set value on given object.");
 160  
                 throw new MetadataException("Error invoking method:" + m.getName() + " in object:" + target.getClass().getName(), e);
 161  
             }
 162  
         }
 163  
         else
 164  
         {
 165  
             throw new MetadataException("Can't get WriteMethod for property:" + pd.getName() + " in object:" + target.getClass().getName());
 166  
         }
 167  
     }
 168  
 
 169  
     private List getPropertyGraph()
 170  
     {
 171  
         if (propertyGraph == null)
 172  
         {
 173  
             propertyGraph = buildPropertyGraph();
 174  
         }
 175  
         return propertyGraph;
 176  
     }
 177  
 
 178  
     private List buildPropertyGraph()
 179  
     {
 180  
         List result = new ArrayList();
 181  
         String[] fields = StringUtils.split(getName(), PATH_TOKEN);
 182  
         PropertyDescriptor pd = null;
 183  
         for (int i = 0; i < fields.length; i++)
 184  
         {
 185  
             String fieldName = fields[i];
 186  
             if (pd == null)
 187  
             {
 188  
                 pd = findPropertyDescriptor(getDeclaringClass(), fieldName);
 189  
             }
 190  
             else
 191  
             {
 192  
                 pd = findPropertyDescriptor(pd.getPropertyType(), fieldName);
 193  
             }
 194  
             result.add(pd);
 195  
         }
 196  
         return result;
 197  
     }
 198  
 
 199  
     /**
 200  
      * Get the PropertyDescriptor for aClass and aPropertyName
 201  
      */
 202  
     protected static PropertyDescriptor findPropertyDescriptor(Class aClass, String aPropertyName)
 203  
     {
 204  
         BeanInfo info;
 205  
         PropertyDescriptor[] pd;
 206  
         PropertyDescriptor descriptor = null;
 207  
 
 208  
         try
 209  
         {
 210  
             info = Introspector.getBeanInfo(aClass);
 211  
             pd = info.getPropertyDescriptors();
 212  
             for (int i = 0; i < pd.length; i++)
 213  
             {
 214  
                 if (pd[i].getName().equals(aPropertyName))
 215  
                 {
 216  
                     descriptor = pd[i];
 217  
                     break;
 218  
                 }
 219  
             }
 220  
             if (descriptor == null)
 221  
             {
 222  
                 /*
 223  
                                  * Daren Drummond:         Throw here so we are consistent
 224  
                                  *                                         with PersistentFieldDefaultImpl.
 225  
                                  */
 226  
                 throw new MetadataException("Can't find property " + aPropertyName + " in " + aClass.getName());
 227  
             }
 228  
             return descriptor;
 229  
         }
 230  
         catch (IntrospectionException ex)
 231  
         {
 232  
             /*
 233  
                          * Daren Drummond:         Throw here so we are consistent
 234  
                          *                                         with PersistentFieldDefaultImpl.
 235  
                          */
 236  
             throw new MetadataException("Can't find property " + aPropertyName + " in " + aClass.getName(), ex);
 237  
         }
 238  
     }
 239  
 
 240  
     /**
 241  
      * Returns the PropertyDescriptor.
 242  
      *
 243  
      * @return java.beans.PropertyDescriptor
 244  
      */
 245  
     protected PropertyDescriptor getPropertyDescriptor()
 246  
     {
 247  
         return (PropertyDescriptor) getPropertyGraph().get(getPropertyGraph().size() - 1);
 248  
     }
 249  
 
 250  
     /**
 251  
      * This implementation returns always 'false'.
 252  
      */
 253  
     public boolean makeAccessible()
 254  
     {
 255  
         return false;
 256  
     }
 257  
 
 258  
     /**
 259  
      * Always returns 'false'.
 260  
      *
 261  
      * @see PersistentField#usesAccessorsAndMutators
 262  
      */
 263  
     public boolean usesAccessorsAndMutators()
 264  
     {
 265  
         return true;
 266  
     }
 267  
 
 268  
     /**
 269  
      * Let's give the user some hints as to what could be wrong.
 270  
      */
 271  
     protected void logProblem(PropertyDescriptor pd, Object anObject, Object aValue, String msg)
 272  
     {
 273  
         Logger logger = getLog();
 274  
         logger.error("Error in [PersistentFieldPropertyImpl], " + msg);
 275  
         logger.error("Declaring class [" + getDeclaringClass().getName() + "]");
 276  
         logger.error("Property Name [" + getName() + "]");
 277  
         logger.error("Property Type [" + pd.getPropertyType().getName() + "]");
 278  
 
 279  
         if (anObject != null)
 280  
         {
 281  
             logger.error("anObject was class [" + anObject.getClass().getName() + "]");
 282  
         }
 283  
         else
 284  
         {
 285  
             logger.error("anObject was null");
 286  
         }
 287  
         if (aValue != null)
 288  
         {
 289  
             logger.error("aValue was class [" + aValue.getClass().getName() + "]");
 290  
         }
 291  
         else
 292  
         {
 293  
             logger.error("aValue was null");
 294  
         }
 295  
     }
 296  
 }