KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > oracle > toplink > essentials > internal > weaving > TransformerFactory


1 /*
2  * The contents of this file are subject to the terms
3  * of the Common Development and Distribution License
4  * (the "License"). You may not use this file except
5  * in compliance with the License.
6  *
7  * You can obtain a copy of the license at
8  * glassfish/bootstrap/legal/CDDLv1.0.txt or
9  * https://glassfish.dev.java.net/public/CDDLv1.0.html.
10  * See the License for the specific language governing
11  * permissions and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL
14  * HEADER in each file and include the License file at
15  * glassfish/bootstrap/legal/CDDLv1.0.txt. If applicable,
16  * add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your
18  * own identifying information: Portions Copyright [yyyy]
19  * [name of copyright owner]
20  */

21 // Copyright (c) 2005, 2006, Oracle. All rights reserved.
22
package oracle.toplink.essentials.internal.weaving;
23
24 // J2SE imports
25
import java.lang.reflect.*;
26 import java.security.AccessController JavaDoc;
27 import java.security.PrivilegedActionException JavaDoc;
28 import java.util.*;
29
30 // ASM imports
31
import oracle.toplink.libraries.asm.Type;
32
33 // TopLink imports
34
import oracle.toplink.essentials.indirection.ValueHolderInterface;
35 import oracle.toplink.essentials.logging.SessionLog;
36 import oracle.toplink.essentials.mappings.*;
37 import oracle.toplink.essentials.descriptors.ClassDescriptor;
38 import oracle.toplink.essentials.sessions.Session;
39 import oracle.toplink.essentials.sessions.Project;
40 import oracle.toplink.essentials.internal.security.PrivilegedAccessHelper;
41 import oracle.toplink.essentials.internal.security.PrivilegedGetDeclaredField;
42 import oracle.toplink.essentials.internal.security.PrivilegedGetDeclaredMethod;
43 import oracle.toplink.essentials.internal.security.PrivilegedGetMethod;
44 import oracle.toplink.essentials.internal.security.PrivilegedGetField;
45
46 import javax.persistence.spi.ClassTransformer;
47
48 /**
49  * INTERNAL:
50  * This class creates a ClassFileTransformer that is used for dynamic bytecode
51  * weaving. It is called by {@link oracle.toplink.essentials.internal.ejb.cmp3.EntityManagerSetupImpl#predeploy}
52  * <p>
53  * <i>Note:</i> The Session's Project is is scanned to ensure that weaving is
54  * supported and is <b>modified</b> to suit (set the {@link ObjectChangePolicy}
55  * for the Descriptor).
56  * <p>
57  *
58  */

59 public class TransformerFactory {
60    
61     public static final String JavaDoc WEAVER_NULL_PROJECT =
62         "weaver_null_project";
63     public static final String JavaDoc WEAVER_DISABLE_BY_SYSPROP =
64         "weaver_disable_by_system_property";
65     public static final String JavaDoc WEAVER_ADDING_EMBEDDABLE =
66         "weaver_adding_embeddable_class";
67     public static final String JavaDoc WEAVER_FOUND_FIELD_LOCK =
68         "weaver_found_field_lock";
69     public static final String JavaDoc WEAVER_CLASS_NOT_IN_PROJECT =
70         "weaver_class_not_in_project";
71     public static final String JavaDoc WEAVER_PROCESSING_CLASS =
72         "weaver_processing_class";
73     
74     public static ClassTransformer createTransformerAndModifyProject(Session session,
75         Collection entityClasses, ClassLoader JavaDoc classLoader) {
76         if (session == null) {
77             throw new IllegalArgumentException JavaDoc("Weaver session cannot be null");
78         }
79         if (session.getProject() == null) {
80             ((oracle.toplink.essentials.internal.sessions.AbstractSession)session).log(
81                 SessionLog.SEVERE, SessionLog.WEAVER, WEAVER_NULL_PROJECT, null);
82             throw new IllegalArgumentException JavaDoc("Weaver session's project cannot be null");
83         }
84         TransformerFactory tf = new TransformerFactory(session, entityClasses, classLoader);
85         tf.buildClassDetailsAndModifyProject();
86         return tf.buildTopLinkWeaver();
87     }
88     
89     protected Session session;
90     protected Collection entityClasses;
91     protected List embeddableClasses;
92     protected Map classDetailsMap;
93     protected ClassLoader JavaDoc classLoader;
94     
95     public TransformerFactory(Session session, Collection entityClasses, ClassLoader JavaDoc classLoader) {
96         this.session = session;
97         this.entityClasses = entityClasses;
98         this.classLoader = classLoader;
99         embeddableClasses = new ArrayList();
100         classDetailsMap = new HashMap();
101     }
102     
103     /**
104      * INTERNAL:
105      * Look higher in the hierarchy for the mappings listed in the unMappedAttribute list.
106      *
107      * We assume that if a mapping exists, the attribute must either be mapped from the owninig
108      * class or from a superclass.
109      */

110     public void addClassDetailsForMappedSuperClasses(Class JavaDoc clz, ClassDescriptor initialDescriptor, ClassDetails classDetails, Map classDetailsMap, List unMappedAttributes){
111         // This class has inheritance to a mapped entity rather than a MappedSuperClass
112
if (initialDescriptor.getInheritancePolicyOrNull() != null && initialDescriptor.getInheritancePolicyOrNull().getParentClass() != null){
113             return;
114         }
115         if (unMappedAttributes.isEmpty()){
116             return;
117         }
118         Class JavaDoc superClz = clz.getSuperclass();
119         if (superClz == null || superClz == java.lang.Object JavaDoc.class){
120             return;
121         }
122         
123         boolean weaveValueHolders = canWeaveValueHolders(superClz, unMappedAttributes);
124         List stillUnMappedMappings = null;
125         ClassDetails superClassDetails = createClassDetails(superClz, weaveValueHolders);
126         superClassDetails.setIsMappedSuperClass(true);
127         if (!classDetailsMap.containsKey(superClassDetails.getClassName())){
128             stillUnMappedMappings = storeAttributeMappings(superClz, superClassDetails, unMappedAttributes, weaveValueHolders);
129             classDetailsMap.put(superClassDetails.getClassName() ,superClassDetails);
130         }
131        
132         if (stillUnMappedMappings != null && !stillUnMappedMappings.isEmpty()){
133             addClassDetailsForMappedSuperClasses(superClz, initialDescriptor, classDetails, classDetailsMap, stillUnMappedMappings);
134         }
135         
136         
137     }
138     
139     public ClassTransformer buildTopLinkWeaver() {
140         return new TopLinkWeaver(session, classDetailsMap);
141     }
142
143     /**
144      * Build a list ClassDetails instance that contains a ClassDetails for each class
145      * in our entities list.
146      */

147     public void buildClassDetailsAndModifyProject() {
148         if (entityClasses != null && entityClasses.size() > 0) {
149             
150             // scan thru list building details of persistent classes
151

152             // do @Entity's next
153
for (Iterator i = entityClasses.iterator(); i.hasNext();) {
154                 Class JavaDoc clz = (Class JavaDoc)i.next();
155                 
156                 // check to ensure that class is present in project
157
ClassDescriptor descriptor = findDescriptor(session.getProject(), clz.getName());
158                 if (descriptor == null) {
159
160                     log(SessionLog.FINER, WEAVER_CLASS_NOT_IN_PROJECT,
161                         new Object JavaDoc[]{clz.getName()});
162                 } else {
163                     log(SessionLog.FINER, WEAVER_PROCESSING_CLASS,
164                         new Object JavaDoc[]{clz.getName()});
165
166                     boolean weaveValueHolders = canWeaveValueHolders(clz, descriptor.getMappings());
167                     
168                     if (weaveValueHolders) {
169                         ClassDetails classDetails = createClassDetails(clz, weaveValueHolders);
170                         List unMappedAttributes = storeAttributeMappings(clz, classDetails, descriptor.getMappings(), weaveValueHolders);
171                         classDetailsMap.put(classDetails.getClassName() ,classDetails);
172
173                         if (!unMappedAttributes.isEmpty()){
174                             addClassDetailsForMappedSuperClasses(clz, descriptor, classDetails, classDetailsMap, unMappedAttributes);
175                         }
176                         if (classDetails.getLazyOneToOneMappings() != null){
177                             Iterator iterator = classDetails.getLazyOneToOneMappings().iterator();
178                             while(iterator.hasNext()){
179                                 OneToOneMapping mapping = (OneToOneMapping)iterator.next();
180                                 mapping.setGetMethodName("_toplink_get" + mapping.getAttributeName() + "_vh");
181                                 mapping.setSetMethodName("_toplink_set" + mapping.getAttributeName() + "_vh");
182                             }
183                         }
184                     }
185                 }
186             }
187             // hookup superClassDetails
188
for (Iterator i = classDetailsMap.values().iterator(); i.hasNext();) {
189                 ClassDetails classDetails = (ClassDetails)i.next();
190                 ClassDetails superClassDetails =
191                     (ClassDetails)classDetailsMap.get(
192                         classDetails.getSuperClassName());
193                 if (superClassDetails != null) {
194                     classDetails.setSuperClassDetails(superClassDetails);
195                 }
196             }
197         // combine lists: add entities to end of embeddables,
198
// then clear entities and re-populate from embeddables.
199
embeddableClasses.addAll(entityClasses);
200         entityClasses.clear();
201         entityClasses.addAll(embeddableClasses);
202         }
203     }
204        
205     protected boolean canWeaveValueHolders(Class JavaDoc clz, List mappings) {
206
207         // we intend to change to fetch=LAZY 1:1 attributes to ValueHolders
208
boolean weaveValueHolders = true;
209         boolean foundOTOM = false;
210         for (Iterator j = mappings.iterator(); j.hasNext();) {
211             DatabaseMapping dm = (DatabaseMapping)j.next();
212             String JavaDoc attributeName = dm.getAttributeName();
213             if (dm.isOneToOneMapping()) {
214                 OneToOneMapping otom = (OneToOneMapping)dm;
215                 Class JavaDoc typeClz = getAttributeTypeFromClass(clz, attributeName, dm, true);
216                 if (otom.getIndirectionPolicy().usesIndirection() &&
217                     typeClz != null && !typeClz.isAssignableFrom(
218                     ValueHolderInterface.class)) {
219                     foundOTOM = true;
220                     weaveValueHolders = true;
221                  }
222              }
223         }
224
225         // did we actually <b>find</b> any attributes to change?
226
return weaveValueHolders & foundOTOM;
227     }
228
229     private ClassDetails createClassDetails(Class JavaDoc clz, boolean weaveValueHolders){
230         // compose className in JVM 'slash' format
231
// instead of regular Java 'dotted' format
232
String JavaDoc className = clz.getName().replace('.','/');
233         String JavaDoc superClassName = clz.getSuperclass().getName().replace('.','/');
234         ClassDetails classDetails = new ClassDetails();
235         classDetails.setClassName(className);
236         classDetails.setSuperClassName(superClassName);
237         classDetails.weaveValueHolders(weaveValueHolders);
238         return classDetails;
239     }
240
241     /**
242      * INTERNAL:
243      * Store a set of attribute mappings on the given ClassDetails taht correspont to the given class.
244      * Return the list of mappings that is not specifically found on the given class. These attributes will
245      * be found on MappedSuperclasses
246      */

247     protected List storeAttributeMappings(Class JavaDoc clz, ClassDetails classDetails, List mappings, boolean weaveValueHolders) {
248         List unMappedAttributes = new Vector();
249         Map attributesMap = new HashMap();
250         Map settersMap = new HashMap();
251         Map gettersMap = new HashMap();
252         List lazyMappings = new Vector();
253         for (Iterator j = mappings.iterator(); j.hasNext();) {
254             DatabaseMapping dm = (DatabaseMapping)j.next();
255             String JavaDoc attribute = dm.getAttributeName();
256             AttributeDetails attributeDetails = new AttributeDetails(attribute);
257             Class JavaDoc typeClz = getAttributeTypeFromClass(clz, attribute, dm, false);
258             if (typeClz == null){
259                 attributeDetails.setAttributeOnSuperClass(true);
260                 if (dm.isOneToOneMapping()){
261                     unMappedAttributes.add(dm);
262                 }
263             }
264             if (dm.isCollectionMapping()) {
265                 attributeDetails.setCollectionMapping(true);
266             } else if (dm.isOneToOneMapping()) {
267                 OneToOneMapping otom = (OneToOneMapping)dm;
268                 attributeDetails.referenceClass = otom.getReferenceClassName();
269                 attributeDetails.weaveVH(weaveValueHolders, otom);
270                 if (otom.getGetMethodName() != null){
271                     gettersMap.put(otom.getGetMethodName(), attributeDetails);
272                     if (otom.getSetMethodName() != null){
273                         settersMap.put(otom.getSetMethodName(), attributeDetails);
274                     }
275                 } else {
276                     attributeDetails.setIsMappedWithAttributeAccess(true);
277                 }
278                 if (typeClz == null){
279                     typeClz = getAttributeTypeFromClass(clz, attribute, dm, true);
280                 }
281                 if (weaveValueHolders && otom.getIndirectionPolicy().usesIndirection() &&
282                     typeClz != null && !typeClz.isAssignableFrom(ValueHolderInterface.class)) {
283                     lazyMappings.add(otom);
284                 }
285
286             }
287             attributesMap.put(attribute, attributeDetails);
288          }
289         classDetails.setAttributesMap(attributesMap);
290         classDetails.setGetterMethodToAttributeDetails(gettersMap);
291         classDetails.setSetterMethodToAttributeDetails(settersMap);
292         classDetails.setLazyOneToOneMappings(lazyMappings);
293         return unMappedAttributes;
294     }
295     
296     /**
297      * Find a descriptor by name in the given project
298      * used to avoid referring to descriptors by class.
299      * This avoids having to construct a project by class facilitating weaving
300      */

301     protected ClassDescriptor findDescriptor(Project project, String JavaDoc className){
302         Iterator iterator = project.getOrderedDescriptors().iterator();
303         while (iterator.hasNext()){
304             ClassDescriptor descriptor = (ClassDescriptor)iterator.next();
305             if (descriptor.getJavaClassName().equals(className)){
306                 return descriptor;
307             }
308         }
309         return null;
310     }
311
312     /**
313      * Use the database mapping for an attribute to find it's type. The type returned will either be
314      * the field type of the field in the object or the type returned by the getter method.
315      */

316     private Class JavaDoc getAttributeTypeFromClass(Class JavaDoc clz, String JavaDoc attributeName, DatabaseMapping mapping, boolean checkSuperclass){
317         String JavaDoc getterMethod = mapping.getGetMethodName();
318         if (mapping != null && getterMethod != null){
319             try{
320                 Method method = null;
321                 if (checkSuperclass){
322                     if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()){
323                         try {
324                             method = (Method)AccessController.doPrivileged(new PrivilegedGetMethod(clz, getterMethod, null, false));
325                         } catch (PrivilegedActionException JavaDoc exception) {
326                         }
327                     } else {
328                         method = PrivilegedAccessHelper.getMethod(clz, getterMethod, null, false);
329                     }
330                 } else {
331                     method = null;
332                     if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()){
333                         try {
334                             method = (Method)AccessController.doPrivileged(new PrivilegedGetDeclaredMethod(clz, getterMethod, null));
335                         } catch (PrivilegedActionException JavaDoc exception) {
336                         }
337                     } else {
338                         method = PrivilegedAccessHelper.getDeclaredMethod(clz, getterMethod, null);
339                     }
340                 }
341                 if (method != null){
342                     return method.getReturnType();
343                 }
344             } catch (Exception JavaDoc e) { }
345         } else {
346             try {
347                 Class JavaDoc typeClz = null;
348                 if (checkSuperclass){
349                     Field field = null;
350                     if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()){
351                         try {
352                             field = (Field)AccessController.doPrivileged(new PrivilegedGetField(clz, attributeName, false));
353                         } catch (PrivilegedActionException JavaDoc exception) {
354                         }
355                     } else {
356                         field = PrivilegedAccessHelper.getField(clz, attributeName, false);
357                     }
358                     typeClz = field.getType();
359                 } else {
360                     Field field = null;
361                     if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()){
362                         try {
363                             field = (Field)AccessController.doPrivileged(new PrivilegedGetDeclaredField(clz, attributeName, false));
364                         } catch (PrivilegedActionException JavaDoc exception) {
365                         }
366                     } else {
367                         field = PrivilegedAccessHelper.getDeclaredField(clz, attributeName, false);
368                     }
369                     typeClz = field.getType();
370                 }
371                 if (typeClz != null){
372                     return typeClz;
373                 }
374             } catch (Exception JavaDoc e) { }
375         }
376
377         return null;
378     }
379
380     protected static boolean hasField(Class JavaDoc clz, String JavaDoc fieldName) {
381         
382         if ("java.lang.Object".equals(clz.getName())) {
383             return false;
384         }
385         else {
386             boolean hasField = false;
387             // check to see if the mapping's attribute exists as a field on the
388
// class; failing that, recurse up super-class(es).
389
try {
390                 Field f = null;
391                 if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()){
392                     try {
393                         f = (Field)AccessController.doPrivileged(new PrivilegedGetDeclaredField(clz, fieldName, false));
394                     } catch (PrivilegedActionException JavaDoc exception) {
395                     }
396                 } else {
397                     f = PrivilegedAccessHelper.getDeclaredField(clz, fieldName, false);
398                 }
399                 hasField = true;
400             }
401             catch (Exception JavaDoc e) { /* ignore */ }
402             return hasField ? hasField : hasField(clz.getSuperclass(), fieldName);
403         }
404     }
405     
406     protected void log(int level, String JavaDoc msg, Object JavaDoc[] params) {
407         ((oracle.toplink.essentials.internal.sessions.AbstractSession)session).log(level,
408             SessionLog.WEAVER, msg, params);
409     }
410 }
411
Popular Tags