Coverage Report - org.apache.ojb.broker.core.IdentityFactoryImpl
 
Classes in this File Line Coverage Branch Coverage Complexity
IdentityFactoryImpl
N/A
N/A
3.05
 
 1  
 package org.apache.ojb.broker.core;
 2  
 
 3  
 /* Copyright 2002-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.ojb.broker.Identity;
 21  
 import org.apache.ojb.broker.IdentityFactory;
 22  
 import org.apache.ojb.broker.OJBRuntimeException;
 23  
 import org.apache.ojb.broker.PersistenceBroker;
 24  
 import org.apache.ojb.broker.PersistenceBrokerException;
 25  
 import org.apache.ojb.broker.PBStateListener;
 26  
 import org.apache.ojb.broker.PBStateEvent;
 27  
 import org.apache.ojb.broker.core.proxy.IndirectionHandler;
 28  
 import org.apache.ojb.broker.core.proxy.ProxyHelper;
 29  
 import org.apache.ojb.broker.metadata.ClassDescriptor;
 30  
 import org.apache.ojb.broker.metadata.ClassNotPersistenceCapableException;
 31  
 import org.apache.ojb.broker.metadata.FieldDescriptor;
 32  
 import org.apache.ojb.broker.util.BrokerHelper;
 33  
 import org.apache.ojb.broker.util.sequence.SequenceManager;
 34  
 import org.apache.ojb.broker.util.sequence.SequenceManagerTransientImpl;
 35  
 import org.apache.commons.lang.SystemUtils;
 36  
 import org.apache.commons.lang.ArrayUtils;
 37  
 import org.apache.commons.lang.exception.ExceptionUtils;
 38  
 import org.apache.commons.collections.map.ReferenceIdentityMap;
 39  
 
 40  
 /**
 41  
  * @author <a href="mailto:armin@codeAuLait.de">Armin Waibel</a>
 42  
  * @version $Id: IdentityFactoryImpl.java,v 1.1 2007-08-24 22:17:35 ewestfal Exp $
 43  
  * @see org.apache.ojb.broker.IdentityFactory
 44  
  */
 45  
 public class IdentityFactoryImpl implements IdentityFactory, PBStateListener
 46  
 {
 47  
     private PersistenceBroker broker;
 48  
     //private boolean activeTx;
 49  
     private Map objectToIdentityMap;
 50  
     private SequenceManager transientSequenceManager;
 51  
 
 52  
     public IdentityFactoryImpl(PersistenceBroker broker)
 53  
     {
 54  
         this.broker = broker;
 55  
         this.objectToIdentityMap = new ReferenceIdentityMap(ReferenceIdentityMap.WEAK, ReferenceIdentityMap.HARD, true);
 56  
         this.transientSequenceManager = new SequenceManagerTransientImpl(broker);
 57  
         broker.addListener(this, true);
 58  
     }
 59  
 
 60  
     /**
 61  
      * This methods creates a new transient (if at least one PK field is 'null') or persistent
 62  
      * (if the PK fields are populated) {@link org.apache.ojb.broker.Identity} instance. If the specified object
 63  
      * is transient and former call for the same object returns already a transient Identity, the same transient
 64  
      * Identity object will be returned.
 65  
      */
 66  
     protected Identity createTransientOrRealIdentity(ClassDescriptor cld, Object objOrProxy)
 67  
     {
 68  
         if(objOrProxy == null) throw new OJBRuntimeException("Can't create Identity for 'null'-object");
 69  
         Identity result = null;
 70  
         Class topLevelClass = null;
 71  
         Class realClass = null;
 72  
         Object[] pks = null;
 73  
         try
 74  
         {
 75  
             final IndirectionHandler handler = ProxyHelper.getIndirectionHandler(objOrProxy);
 76  
 
 77  
             synchronized(objOrProxy)
 78  
             {
 79  
                 if(handler != null)
 80  
                 {
 81  
                     result = handler.getIdentity();
 82  
                 }
 83  
                 else
 84  
                 {
 85  
                     // now we are sure that the specified object is not a proxy
 86  
                     realClass = objOrProxy.getClass();
 87  
                     topLevelClass = broker.getTopLevelClass(objOrProxy.getClass());
 88  
                     if(cld == null)
 89  
                     {
 90  
                         cld = broker.getClassDescriptor(objOrProxy.getClass());
 91  
                     }
 92  
                     BrokerHelper helper = broker.serviceBrokerHelper();
 93  
 
 94  
                     FieldDescriptor[] fields = cld.getPkFields();
 95  
                     pks = new Object[fields.length];
 96  
                     FieldDescriptor fld;
 97  
                     for(int i = 0; i < fields.length; i++)
 98  
                     {
 99  
                         fld = fields[i];
 100  
                         /*
 101  
                         we check all PK fields for 'null'-values
 102  
                         */
 103  
                         Object value = fld.getPersistentField().get(objOrProxy);
 104  
                         if(helper.representsNull(fld, value))
 105  
                         {
 106  
                             result = (Identity) objectToIdentityMap.get(objOrProxy);
 107  
                             if(result == null)
 108  
                             {
 109  
                                 pks[i] = transientSequenceManager.getUniqueValue(fld);
 110  
                                 result = new Identity(realClass, topLevelClass, pks, true);
 111  
                                 //if(activeTx) objectToIdentityMap.put(objOrProxy, result);
 112  
                                 objectToIdentityMap.put(objOrProxy, result);
 113  
                             }
 114  
                             break;
 115  
                         }
 116  
                         else
 117  
                         {
 118  
                             pks[i] = value;
 119  
                         }
 120  
                     }
 121  
                     if(result == null)
 122  
                     {
 123  
                         result = new Identity(realClass, topLevelClass, pks, false);
 124  
                     }
 125  
                 }
 126  
             }
 127  
         }
 128  
         catch(ClassNotPersistenceCapableException e)
 129  
         {
 130  
             throw e;
 131  
         }
 132  
         catch(Exception e)
 133  
         {
 134  
             throw createException(e, "Can not init Identity for given object.", objOrProxy, topLevelClass, realClass, pks);
 135  
         }
 136  
         return result;
 137  
     }
 138  
 
 139  
     /** @see org.apache.ojb.broker.IdentityFactory#buildIdentity(Object) */
 140  
     public Identity buildIdentity(Object obj)
 141  
     {
 142  
         return createTransientOrRealIdentity(broker.getClassDescriptor(ProxyHelper.getRealClass(obj)), obj);
 143  
     }
 144  
 
 145  
     /** @see org.apache.ojb.broker.IdentityFactory#buildIdentity(Object) */
 146  
     public Identity buildIdentity(ClassDescriptor cld, Object obj)
 147  
     {
 148  
         return createTransientOrRealIdentity(cld, obj);
 149  
     }
 150  
 
 151  
     /** @see org.apache.ojb.broker.IdentityFactory#buildIdentity(Class, Class, String[], Object[]) */
 152  
     public Identity buildIdentity(Class realClass, Class topLevelClass, String[] pkFieldNames, Object[] pkValues)
 153  
     {
 154  
         Object[] orderedPKValues = pkValues;
 155  
         if(pkValues == null)
 156  
         {
 157  
             throw new NullPointerException("Given primary key value array can't be null");
 158  
         }
 159  
         if(pkValues.length == 1 && (pkFieldNames == null || pkFieldNames.length == 1))
 160  
         {
 161  
             /*
 162  
             we assume only a single PK field is defined and do no further checks,
 163  
             we have nothing to do
 164  
             */
 165  
         }
 166  
         else
 167  
         {
 168  
             // in other more complex cases we do several check
 169  
             FieldDescriptor[] flds = broker.getClassDescriptor(realClass).getPkFields();
 170  
             if(!isOrdered(flds, pkFieldNames))
 171  
             {
 172  
                 orderedPKValues = reorderFieldValues(flds, pkFieldNames, pkValues);
 173  
             }
 174  
         }
 175  
         return new Identity(realClass, topLevelClass, orderedPKValues);
 176  
     }
 177  
 
 178  
     /**
 179  
      * This method orders the specified field values based on the
 180  
      * specified {@link org.apache.ojb.broker.metadata.FieldDescriptor}.
 181  
      *
 182  
      * @param flds The {@link org.apache.ojb.broker.metadata.FieldDescriptor} array.
 183  
      * @param fieldNames The field names.
 184  
      * @param fieldValues The field values.
 185  
      * @return The ordered field values.
 186  
      */
 187  
     private Object[] reorderFieldValues(FieldDescriptor[] flds, String[] fieldNames, Object[] fieldValues)
 188  
     {
 189  
         String fieldName;
 190  
         Object[] orderedValues = new Object[flds.length];
 191  
         for(int i = 0; i < flds.length; i++)
 192  
         {
 193  
             fieldName = flds[i].getPersistentField().getName();
 194  
             int realPosition = findIndexForName(fieldNames, fieldName);
 195  
             orderedValues[i] = fieldValues[realPosition];
 196  
         }
 197  
         return orderedValues;
 198  
     }
 199  
 
 200  
     /**
 201  
      * Find the index of the specified name in field name array.
 202  
      */
 203  
     private int findIndexForName(String[] fieldNames, String searchName)
 204  
     {
 205  
         for(int i = 0; i < fieldNames.length; i++)
 206  
         {
 207  
             if(searchName.equals(fieldNames[i]))
 208  
             {
 209  
                 return i;
 210  
             }
 211  
         }
 212  
         throw new PersistenceBrokerException("Can't find field name '" + searchName +
 213  
                 "' in given array of field names");
 214  
     }
 215  
 
 216  
     /** Checks length and compare order of field names with declared PK fields in metadata. */
 217  
     private boolean isOrdered(FieldDescriptor[] flds, String[] pkFieldNames)
 218  
     {
 219  
         if((flds.length > 1 && pkFieldNames == null) || flds.length != pkFieldNames.length)
 220  
         {
 221  
             throw new PersistenceBrokerException("pkFieldName length does not match number of defined PK fields." +
 222  
                     " Expected number of PK fields is " + flds.length + ", given number was " +
 223  
                     (pkFieldNames != null ? pkFieldNames.length : 0));
 224  
         }
 225  
         boolean result = true;
 226  
         for(int i = 0; i < flds.length; i++)
 227  
         {
 228  
             FieldDescriptor fld = flds[i];
 229  
             result = result && fld.getPersistentField().getName().equals(pkFieldNames[i]);
 230  
         }
 231  
         return result;
 232  
     }
 233  
 
 234  
     /** @see org.apache.ojb.broker.IdentityFactory#buildIdentity(Class, String[], Object[]) */
 235  
     public Identity buildIdentity(Class realClass, String[] pkFieldNames, Object[] pkValues)
 236  
     {
 237  
         return buildIdentity(realClass, broker.getTopLevelClass(realClass), pkFieldNames, pkValues);
 238  
     }
 239  
 
 240  
     /** @see org.apache.ojb.broker.IdentityFactory#buildIdentity(Class, String[], Object[]) */
 241  
     public Identity buildIdentity(Class realClass, Class topLevelClass, Object[] pkValues)
 242  
     {
 243  
         return new Identity(realClass, topLevelClass, pkValues);
 244  
     }
 245  
 
 246  
     /** @see org.apache.ojb.broker.IdentityFactory#buildIdentity(Class, Object) */
 247  
     public Identity buildIdentity(Class realClass, Object pkValue)
 248  
     {
 249  
         return buildIdentity(realClass, (String[]) null, new Object[]{pkValue});
 250  
     }
 251  
 
 252  
     /**
 253  
      * Helper method which supports creation of proper error messages.
 254  
      *
 255  
      * @param ex An exception to include or <em>null</em>.
 256  
      * @param message The error message or <em>null</em>.
 257  
      * @param objectToIdentify The current used object or <em>null</em>.
 258  
      * @param topLevelClass The object top-level class or <em>null</em>.
 259  
      * @param realClass The object real class or <em>null</em>.
 260  
      * @param pks The associated PK values of the object or <em>null</em>.
 261  
      * @return The generated exception.
 262  
      */
 263  
     private PersistenceBrokerException createException(final Exception ex, String message, final Object objectToIdentify, Class topLevelClass, Class realClass, Object[] pks)
 264  
     {
 265  
         final String eol = SystemUtils.LINE_SEPARATOR;
 266  
         StringBuffer msg = new StringBuffer();
 267  
         if(message == null)
 268  
         {
 269  
             msg.append("Unexpected error: ");
 270  
         }
 271  
         else
 272  
         {
 273  
             msg.append(message).append(" :");
 274  
         }
 275  
         if(topLevelClass != null) msg.append(eol).append("objectTopLevelClass=").append(topLevelClass.getName());
 276  
         if(realClass != null) msg.append(eol).append("objectRealClass=").append(realClass.getName());
 277  
         if(pks != null) msg.append(eol).append("pkValues=").append(ArrayUtils.toString(pks));
 278  
         if(objectToIdentify != null) msg.append(eol).append("object to identify: ").append(objectToIdentify);
 279  
         if(ex != null)
 280  
         {
 281  
             // add causing stack trace
 282  
             Throwable rootCause = ExceptionUtils.getRootCause(ex);
 283  
             if(rootCause != null)
 284  
             {
 285  
                 msg.append(eol).append("The root stack trace is --> ");
 286  
                 String rootStack = ExceptionUtils.getStackTrace(rootCause);
 287  
                 msg.append(eol).append(rootStack);
 288  
             }
 289  
 
 290  
             return new PersistenceBrokerException(msg.toString(), ex);
 291  
         }
 292  
         else
 293  
         {
 294  
             return new PersistenceBrokerException(msg.toString());
 295  
         }
 296  
     }
 297  
 
 298  
     //===================================================================
 299  
     // PBStateListener interface
 300  
     //===================================================================
 301  
     public void afterBegin(PBStateEvent event)
 302  
     {
 303  
     }
 304  
 
 305  
     public void afterCommit(PBStateEvent event)
 306  
     {
 307  
         if(objectToIdentityMap.size() > 0) objectToIdentityMap.clear();
 308  
     }
 309  
 
 310  
     public void afterRollback(PBStateEvent event)
 311  
     {
 312  
         if(objectToIdentityMap.size() > 0) objectToIdentityMap.clear();
 313  
     }
 314  
 
 315  
     public void beforeClose(PBStateEvent event)
 316  
     {
 317  
         if(objectToIdentityMap.size() > 0) objectToIdentityMap.clear();
 318  
     }
 319  
 
 320  
     public void beforeRollback(PBStateEvent event)
 321  
     {
 322  
     }
 323  
     public void afterOpen(PBStateEvent event)
 324  
     {
 325  
     }
 326  
     public void beforeBegin(PBStateEvent event)
 327  
     {
 328  
     }
 329  
     public void beforeCommit(PBStateEvent event)
 330  
     {
 331  
     }
 332  
 }