KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > ojb > broker > core > IdentityFactoryImpl


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 JavaDoc;
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.2.2.5 2005/12/21 22:25:01 tomdz 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 JavaDoc 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 JavaDoc objOrProxy)
67     {
68         if(objOrProxy == null) throw new OJBRuntimeException("Can't create Identity for 'null'-object");
69         Identity result = null;
70         Class JavaDoc topLevelClass = null;
71         Class JavaDoc realClass = null;
72         Object JavaDoc[] 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 JavaDoc[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 JavaDoc 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 JavaDoc 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 JavaDoc 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 JavaDoc 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 JavaDoc realClass, Class JavaDoc topLevelClass, String JavaDoc[] pkFieldNames, Object JavaDoc[] pkValues)
153     {
154         Object JavaDoc[] orderedPKValues = pkValues;
155         if(pkValues == null)
156         {
157             throw new NullPointerException JavaDoc("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 JavaDoc[] reorderFieldValues(FieldDescriptor[] flds, String JavaDoc[] fieldNames, Object JavaDoc[] fieldValues)
188     {
189         String JavaDoc fieldName;
190         Object JavaDoc[] orderedValues = new Object JavaDoc[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 JavaDoc[] fieldNames, String JavaDoc 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 JavaDoc[] 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 JavaDoc realClass, String JavaDoc[] pkFieldNames, Object JavaDoc[] 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 JavaDoc realClass, Class JavaDoc topLevelClass, Object JavaDoc[] 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 JavaDoc realClass, Object JavaDoc pkValue)
248     {
249         return buildIdentity(realClass, (String JavaDoc[]) null, new Object JavaDoc[]{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 JavaDoc ex, String JavaDoc message, final Object JavaDoc objectToIdentify, Class JavaDoc topLevelClass, Class JavaDoc realClass, Object JavaDoc[] pks)
264     {
265         final String JavaDoc eol = SystemUtils.LINE_SEPARATOR;
266         StringBuffer JavaDoc msg = new StringBuffer JavaDoc();
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 JavaDoc rootCause = ExceptionUtils.getRootCause(ex);
283             if(rootCause != null)
284             {
285                 msg.append(eol).append("The root stack trace is --> ");
286                 String JavaDoc 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 }
333
Popular Tags