KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > ojb > broker > metadata > fieldaccess > AbstractPersistentField


1 package org.apache.ojb.broker.metadata.fieldaccess;
2
3 /* Copyright 2003-2004 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.lang.reflect.Field JavaDoc;
19
20 import org.apache.commons.lang.SystemUtils;
21 import org.apache.ojb.broker.core.proxy.ProxyHelper;
22 import org.apache.ojb.broker.metadata.MetadataException;
23 import org.apache.ojb.broker.util.logging.Logger;
24 import org.apache.ojb.broker.util.logging.LoggerFactory;
25
26 /**
27  * Abstract {@link PersistentField} base implementation.
28  *
29  * @author <a HREF="mailto:armin@codeAuLait.de">Armin Waibel</a>
30  * @version $Id: AbstractPersistentField.java,v 1.22 2004/06/26 23:51:37 arminw Exp $
31  */

32 public abstract class AbstractPersistentField implements PersistentField
33 {
34     public static final String JavaDoc PATH_TOKEN = "::";
35     public static final Class JavaDoc PERSISTENT_FIELD_IMPL_FOR_NESTED = PersistentFieldDirectAccessImpl.class;
36
37     private static final int UNKNOWN_FIELD = 0;
38     private static final int NORMAL_FIELD = 1;
39     private static final int NESTED_FIELD = 2;
40
41     protected transient Field JavaDoc field;
42     protected String JavaDoc fieldName;
43     protected Class JavaDoc rootObjectType;
44     /**
45      * 0 - not initialized
46      * 1 - normal field
47      * 2 - nested field
48      */

49     private int isNestedField = UNKNOWN_FIELD;
50
51     /**
52      * For internal use only!!
53      * TODO: Default constructor only needed to support
54      * PersistentFieldFactory#usesAccessorsAndMutators()
55      * method - find a better solution. Make 'public' to
56      * allow helper class to instantiate class.
57      */

58     public AbstractPersistentField()
59     {
60     }
61
62     public AbstractPersistentField(Class JavaDoc clazz, String JavaDoc fieldname)
63     {
64         this.rootObjectType = clazz;
65         this.fieldName = fieldname;
66     }
67
68     /**
69      * Set value for target object.
70      */

71     public abstract void doSet(Object JavaDoc targetObject, Object JavaDoc value);
72
73     /**
74      * Get value for field extracted from given target object.
75      */

76     public abstract Object JavaDoc doGet(Object JavaDoc targetObject);
77
78     /**
79      * A value of true indicates that this field should
80      * suppress Java language access checking when it is used.
81      */

82     public abstract boolean makeAccessible();
83
84     /**
85      * do not override this method, have a look at {@link #doSet}
86      */

87     public void set(Object JavaDoc targetObject, Object JavaDoc value) throws MetadataException
88     {
89         if(targetObject == null) return;
90         if (isNestedField())
91         {
92             if (value != null || !getField().getType().isPrimitive())
93             {
94                 setNestedObject(targetObject, fieldName, value);
95             }
96         }
97         else
98         {
99             doSet(targetObject, value);
100         }
101     }
102
103     /**
104      * do not override this method, have a look at {@link #doGet}
105      */

106     public Object JavaDoc get(Object JavaDoc targetObject) throws MetadataException
107     {
108         if(targetObject == null) return null;
109         if (isNestedField())
110         {
111             return getNestedObject(targetObject, fieldName);
112         }
113         else
114         {
115             return doGet(targetObject);
116         }
117     }
118
119     protected Logger getLog()
120     {
121         return LoggerFactory.getLogger("PersistentField");
122     }
123
124     /**
125      * Returns the underlying field object.
126      * If parameter <tt>setAccessible</tt> is true the
127      * field access checking was suppressed.
128      */

129     protected Field JavaDoc getField()
130     {
131         if (field == null)
132         {
133             field = computeField(rootObjectType, fieldName, isNestedField(), makeAccessible());
134         }
135         return field;
136     }
137
138     /**
139      * Tries to compute a {@link java.lang.reflect.Field} object
140      * based on given <code>Class</code> and field name - The field
141      * name may a nested name string (e.g. stock::stockdetail::name)
142      *
143      * @throws MetadataException if there is an error computing the field
144      * ( No Field was found into the class hierarchy)
145      */

146     protected static Field JavaDoc computeField(Class JavaDoc c, String JavaDoc fieldname, boolean isNested, boolean makeAccessible)
147     {
148         try
149         {
150             Field JavaDoc f;
151             if (isNested)
152             {
153                 f = getNestedRecursiveField(c, fieldname);
154             }
155             else
156             {
157                 f = getFieldRecursive(c, fieldname);
158             }
159
160             if (makeAccessible)
161             {
162                 f.setAccessible(true);
163             }
164             return f;
165         }
166         catch (NoSuchFieldException JavaDoc e)
167         {
168             throw new MetadataException("Can't find member '" + fieldname + "' in " + c.getName(), e);
169         }
170     }
171
172     /**
173      * try to find a field in class c, recurse through class hierarchy if necessary
174      * @throws NoSuchFieldException if no Field was found into the class hierarchy
175      */

176     private static Field JavaDoc getFieldRecursive(Class JavaDoc c, String JavaDoc name) throws NoSuchFieldException JavaDoc
177     {
178         try
179         {
180             Field JavaDoc f = c.getDeclaredField(name);
181             return f;
182         }
183         catch (NoSuchFieldException JavaDoc e)
184         {
185             // if field could not be found in the inheritance hierarchy, signal error
186
if ((c == Object JavaDoc.class) || (c.getSuperclass() == null) || c.isInterface())
187             {
188                 throw e;
189             }
190             // if field could not be found in class c try in superclass
191
else
192             {
193                 return getFieldRecursive(c.getSuperclass(), name);
194             }
195         }
196     }
197
198     /**
199      * Return field of the given field name path expression
200      */

201     private static Field JavaDoc getNestedRecursiveField(Class JavaDoc c, String JavaDoc aFieldName) throws NoSuchFieldException JavaDoc
202     {
203         Field JavaDoc result = null;
204         int index = aFieldName.indexOf(PATH_TOKEN);
205         if (index >= 0)
206         {
207             String JavaDoc pathName = aFieldName.substring(0, index);
208             Field JavaDoc path = getFieldRecursive(c, pathName); // assert(path != null);
209
result = getNestedRecursiveField(path.getType(), aFieldName.substring(index + PATH_TOKEN.length()));
210         }
211         else
212         {
213             result = getFieldRecursive(c, aFieldName);
214         }
215         return result;
216     }
217
218     protected boolean isNestedField()
219     {
220         if (isNestedField == UNKNOWN_FIELD) // not initialized
221
{
222             if (fieldName == null)
223             {
224                 throw new MetadataException(
225                         "Unexpected behaviour: fieldName is null, can not calculate field rootObjectType");
226             }
227             if (fieldName.indexOf(PATH_TOKEN) >= 0)
228             {
229                 isNestedField = NESTED_FIELD;
230             }
231             else
232             {
233                 isNestedField = NORMAL_FIELD;
234             }
235         }
236         return isNestedField == NESTED_FIELD;
237     }
238
239     /**
240      * Get nested attribute with given field name.
241      * @param obj object from which the represented field's value is to be extracted
242      * @param aFieldName nested attribute name
243      * @return Object the value of the represented field in object obj
244      */

245     protected Object JavaDoc getNestedObject(Object JavaDoc obj, String JavaDoc aFieldName)
246     {
247         Object JavaDoc result = null;
248         int index = aFieldName.indexOf(PATH_TOKEN);
249         // make sure not to use a proxy object
250
Object JavaDoc realObj = ProxyHelper.getRealObject(obj);
251         Class JavaDoc realClass = ProxyHelper.getRealClass(obj);
252         if (index >= 0)
253         {
254             String JavaDoc name = aFieldName.substring(0, index);
255             PersistentField pField = createInternPersistentField(realClass, name);
256             Object JavaDoc attrib = pField.get(realObj);
257
258             if (attrib != null)
259             {
260                 String JavaDoc nestedName = aFieldName.substring(index + PATH_TOKEN.length());
261                 result = getNestedObject(attrib, nestedName);
262             }
263         }
264         else
265         {
266             PersistentField pField = createInternPersistentField(realClass, aFieldName);
267             result = pField.get(realObj);
268         }
269         return result;
270     }
271
272     /**
273      * Set nested attribute with given value.
274      * @param obj the object whose field should be modified
275      * @param fieldName nested attribute name
276      * @param value the new value for the field of obj being modified
277      */

278     protected void setNestedObject(Object JavaDoc obj, String JavaDoc fieldName, Object JavaDoc value)
279     {
280         int index = fieldName.indexOf(PATH_TOKEN);
281         Class JavaDoc realClass = ProxyHelper.getRealClass(obj);
282         Object JavaDoc realObj = ProxyHelper.getRealObject(obj);
283         if (index >= 0)
284         {
285             String JavaDoc name = fieldName.substring(0, index);
286             PersistentField pField = createInternPersistentField(realClass, name);
287             Object JavaDoc attrib = pField.get(realObj);
288
289             if (attrib != null || value != null)
290             {
291                 if (attrib == null)
292                 {
293                     try
294                     {
295                         attrib = createNestedFieldValue(pField);
296                     }
297                     catch (InstantiationException JavaDoc e)
298                     {
299                         throw new MetadataException("Error instantiate field: "
300                                 + name + " in object:" + realClass.getName(), e);
301                     }
302                     catch (IllegalAccessException JavaDoc e)
303                     {
304                         throw new MetadataException("Error getting field:"
305                                 + name + " in object:" + realClass.getName(), e);
306                     }
307
308                     /*
309                     TODO: here we need cast to AbstractPersistentField to execute the doSet-method.
310                     Find better solution without cast?
311                     */

312                     if (pField instanceof AbstractPersistentField)
313                     {
314                         ((AbstractPersistentField) pField).doSet(realObj, attrib);
315                     }
316                     else
317                     {
318                         pField.set(realObj, attrib);
319                     }
320                 }
321                 String JavaDoc nestedName = fieldName.substring(index + PATH_TOKEN.length());
322                 setNestedObject(attrib, nestedName, value);
323             }
324         }
325         else
326         {
327             PersistentField pField = createInternPersistentField(realClass, fieldName);
328             pField.set(realObj, value);
329         }
330
331     }
332
333     protected Object JavaDoc createNestedFieldValue(PersistentField nestedField) throws InstantiationException JavaDoc, IllegalAccessException JavaDoc
334     {
335         return nestedField.getType().newInstance();
336     }
337
338     private PersistentField createInternPersistentField(Class JavaDoc fieldType, String JavaDoc aFieldName)
339     {
340         try
341         {
342             return PersistentFieldFactory.createPersistentField(fieldType, aFieldName);
343         }
344         catch (Exception JavaDoc e)
345         {
346             throw new MetadataException("Cannot create PersistentField for field '" + aFieldName + "' of class " +
347                     fieldType.getName(), e);
348         }
349     }
350
351     public String JavaDoc toString()
352     {
353         StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
354         buf.append("fieldName=");
355         buf.append(fieldName);
356         buf.append(", field [");
357         buf.append(field);
358         buf.append("]");
359         return buf.toString();
360     }
361
362     public String JavaDoc getName()
363     {
364         return fieldName;
365     }
366
367     public Class JavaDoc getType()
368     {
369         return getField().getType();
370     }
371
372     public Class JavaDoc getDeclaringClass()
373     {
374         return getField().getDeclaringClass();
375     }
376
377     /**
378      * Build a String representation of given arguments.
379      */

380     public String JavaDoc buildMessageString(Object JavaDoc obj, Object JavaDoc value, Field JavaDoc aField)
381     {
382         String JavaDoc eol = SystemUtils.LINE_SEPARATOR;
383         StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
384         buf
385             .append(eol + "[try to set 'object value' in 'target object'")
386             .append(eol + "target obj class: " + (obj != null ? obj.getClass().getName() : null))
387             .append(eol + "target field name: " + (aField != null ? aField.getName() : null))
388             .append(eol + "target field type: " + (aField != null ? aField.getType() : null))
389             .append(eol + "object value class: " + (value != null ? value.getClass().getName() : null))
390             .append(eol + "object value: " + (value != null ? value : null))
391             .append(eol + "]");
392         return buf.toString();
393     }
394 }
395
Popular Tags