KickJava   Java API By Example, From Geeks To Geeks.

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


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.util.*;
26
27 //ASM imports
28
import oracle.toplink.libraries.asm.*;
29 import oracle.toplink.libraries.asm.attrs.RuntimeVisibleAnnotations;
30 import oracle.toplink.libraries.asm.attrs.Annotation;
31
32 /**
33  * INTERNAL:
34  * Weaves classes to allow them to support TopLink indirection.
35  * Classes are weaved to add a variable of type ValueHolderInterface for each attribute
36  * that uses indirection. In addition, access methods are added for the new variable.
37  * Also, triggers the process of weaving the methods of the class.
38  * @see oracle.toplink.essentials.internal.weaving.TopLinkMethodWeaver
39  */

40
41 public class TopLinkClassWeaver extends ClassAdapter implements Constants {
42
43     public static final String JavaDoc VHI_CLASSNAME =
44         "oracle.toplink.essentials.indirection.ValueHolderInterface";
45     public static final String JavaDoc VH_SHORT_SIGNATURE =
46         "oracle/toplink/essentials/indirection/ValueHolder";
47     public static final String JavaDoc VHI_SHORT_SIGNATURE =
48         "oracle/toplink/essentials/indirection/ValueHolderInterface";
49     public static final String JavaDoc VHI_SIGNATURE =
50         "L" + VHI_SHORT_SIGNATURE +";";
51     public static final String JavaDoc TW_SHORT_SIGNATURE =
52         "oracle/toplink/essentials/internal/weaving/TopLinkWeaved";
53     
54     protected ClassDetails classDetails;
55     public boolean alreadyWeaved = false;
56     public boolean weavedVH = false;
57
58     public TopLinkClassWeaver(ClassWriter classWriter, ClassDetails classDetails) {
59         super(classWriter);
60         this.classDetails = classDetails;
61     }
62
63     /**
64     * INTERNAL:
65     * Add a variable of type ValueHolderInterface to the class. When this method has been run, the
66     * class will contain a variable declaration similar to the following:
67     *
68     * private ValueHolderInterface _toplink_variableName_vh;
69     */

70     public void addValueHolder(AttributeDetails attributeDetails){
71         String JavaDoc attribute = attributeDetails.getAttributeName();
72         RuntimeVisibleAnnotations annotations = null;
73         if (attributeDetails.getMapping().getGetMethodName() == null || attributeDetails.getMapping().getGetMethodName().equals("")){
74             annotations = getTransientAnnotation();
75         }
76         weavedVH = true;
77         cv.visitField(ACC_PRIVATE, "_toplink_" + attribute + "_vh", "Loracle/toplink/essentials/indirection/ValueHolderInterface;", null, annotations);
78     }
79
80     /**
81      * INTERNAL:
82      * Add a get method for the newly added valueholder. Adds a method of the followign form:
83      *
84      * public ValueHolderInterface _toplink_getvariableName_vh(){
85      * return _toplink_variableName_vh;
86      * }
87      */

88     public void addGetterMethodForValueHolder(ClassDetails classDetails, AttributeDetails attributeDetails){
89         String JavaDoc attribute = attributeDetails.getAttributeName();
90         String JavaDoc className = classDetails.getClassName();
91         // Create a getter method for the new valueholder
92
CodeVisitor cv_get_VH = cv.visitMethod(ACC_PUBLIC, "_toplink_get" + attribute + "_vh", "()" + VHI_SIGNATURE, null, null);
93         cv_get_VH.visitVarInsn(ALOAD, 0);
94         cv_get_VH.visitFieldInsn(GETFIELD, className, "_toplink_" + attribute + "_vh", "Loracle/toplink/essentials/indirection/ValueHolderInterface;");
95         cv_get_VH.visitInsn(ARETURN);
96         cv_get_VH.visitMaxs(0, 0);
97     }
98     
99     /**
100      * INTERNAL:
101      * Add a set method for the newly added ValueHolder. Adds a method of this form:
102      *
103      * public void _toplink_setvariableName_vh(ValueHolderInterface valueholderinterface)
104      * _toplink_variableName_vh = valueholderinterface;
105      * }
106      */

107     public void addSetterMethodForValueHolder(ClassDetails classDetails, AttributeDetails attributeDetails){
108         String JavaDoc attribute = attributeDetails.getAttributeName();
109         String JavaDoc className = classDetails.getClassName();
110         // create a setter method for the new valueholder
111
CodeVisitor cv_set_value = cv.visitMethod(ACC_PUBLIC, "_toplink_set" + attribute + "_vh", "(Loracle/toplink/essentials/indirection/ValueHolderInterface;)V", null, null);
112         cv_set_value.visitVarInsn(ALOAD, 0);
113         cv_set_value.visitVarInsn(ALOAD, 1);
114         cv_set_value.visitFieldInsn(PUTFIELD, className, "_toplink_" + attribute + "_vh", "Loracle/toplink/essentials/indirection/ValueHolderInterface;");
115         cv_set_value.visitInsn(RETURN);
116         cv_set_value.visitMaxs(0, 0);
117     }
118     
119     /**
120      * INTERNAL:
121      * Adds a convenience method used to replace a PUTFIELD when field access is used. The method follows
122      * the following form:
123      *
124      * public void _toplink_setvariableName(<VariableClas> item) {
125      * _toplink_variableName_vh.setValue(item);
126      * this.item = item;
127      * }
128      *
129      */

130     public void addSetterMethodForFieldAccess(ClassDetails classDetails, AttributeDetails attributeDetails){
131         String JavaDoc attribute = attributeDetails.getAttributeName();
132         CodeVisitor cv_set = cv.visitMethod(ACC_PUBLIC, "_toplink_set" + attribute, "(L" + attributeDetails.getReferenceClass().replace('.','/') + ";)V", null, null);
133         cv_set.visitVarInsn(ALOAD, 0);
134         cv_set.visitFieldInsn(GETFIELD, classDetails.getClassName(), "_toplink_" + attribute + "_vh", TopLinkClassWeaver.VHI_SIGNATURE);
135         cv_set.visitVarInsn(ALOAD, 1);
136         cv_set.visitMethodInsn(INVOKEINTERFACE, TopLinkClassWeaver.VHI_SHORT_SIGNATURE, "setValue", "(Ljava/lang/Object;)V");
137         cv_set.visitVarInsn(ALOAD, 0);
138         cv_set.visitVarInsn(ALOAD, 1);
139         cv_set.visitFieldInsn(PUTFIELD, classDetails.getClassName(), attribute, "L" + attributeDetails.getReferenceClass().replace('.','/') + ";");
140         cv_set.visitInsn(RETURN);
141         cv_set.visitMaxs(0 ,0);
142     }
143
144     /**
145      * INTERNAL:
146      * Adds a convenience method used to replace a GETFIELD when field access is used. The method follows
147      * the following form:
148      *
149      * public <VariableClass> _toplink_getvariableName(){
150      * this.item = (<VariableClass>)_toplink_variableName_vh.getValue();
151      * return this.item;
152      * }
153      *
154      */

155     public void addGetterMethodForFieldAccess(ClassDetails classDetails, AttributeDetails attributeDetails){
156         String JavaDoc attribute = attributeDetails.getAttributeName();
157
158         CodeVisitor cv_get = cv.visitMethod(ACC_PUBLIC, "_toplink_get" + attribute, "()L" + attributeDetails.getReferenceClass().replace('.','/') + ";", null, null);
159         cv_get.visitVarInsn(ALOAD, 0);
160         cv_get.visitVarInsn(ALOAD, 0);
161         cv_get.visitFieldInsn(GETFIELD, classDetails.getClassName(), "_toplink_" + attribute + "_vh", TopLinkClassWeaver.VHI_SIGNATURE);
162         cv_get.visitMethodInsn(INVOKEINTERFACE, TopLinkClassWeaver.VHI_SHORT_SIGNATURE, "getValue", "()Ljava/lang/Object;");
163         cv_get.visitTypeInsn(CHECKCAST, attributeDetails.getReferenceClass().replace('.','/'));
164         cv_get.visitFieldInsn(PUTFIELD, classDetails.getClassName(), attribute, "L" + attributeDetails.getReferenceClass().replace('.','/') + ";");
165         cv_get.visitVarInsn(ALOAD, 0);
166         cv_get.visitFieldInsn(GETFIELD, classDetails.getClassName(), attribute, "L" + attributeDetails.getReferenceClass().replace('.','/') + ";");
167         cv_get.visitInsn(ARETURN);
168         cv_get.visitMaxs(0, 0);
169     }
170    
171     private RuntimeVisibleAnnotations getTransientAnnotation(){
172         RuntimeVisibleAnnotations attrs = new RuntimeVisibleAnnotations();
173         Annotation transientAnnotation = new Annotation("Ljavax/persistence/Transient;");
174         attrs.annotations.add(transientAnnotation);
175         return attrs;
176     }
177     
178     // add ChangeTracker, TopLinkWeaved interfaces
179
public void visit(int version, int access, String JavaDoc name, String JavaDoc superName,
180         String JavaDoc[] interfaces, String JavaDoc sourceFile) {
181
182         // prevent 'double' weaving: scan for TopLinkWeaved interface
183
for (int i = 0; i < interfaces.length; i++) {
184             String JavaDoc s = interfaces[i];
185             if (TW_SHORT_SIGNATURE.equals(s)) {
186                 alreadyWeaved = true;
187                 break;
188             }
189         }
190         
191         if (!alreadyWeaved) {
192             int len = 1 + interfaces.length;
193             String JavaDoc[] newInterfaces = new String JavaDoc[len];
194             System.arraycopy(interfaces, 0, newInterfaces, 0, interfaces.length);
195             // add 'marker' oracle.toplink.essentials.internal.weaving.TopLinkWeaved interface
196
newInterfaces[interfaces.length] = TW_SHORT_SIGNATURE;
197             super.visit(version, access, name, superName, newInterfaces,
198                 sourceFile);
199         } else {
200             super.visit(version, access, name, superName, interfaces, sourceFile);
201         }
202
203     }
204
205     /**
206      * INTERNAL:
207      * Construct a TopLinkMethodWeaver and allow it to process the method.
208      */

209     public CodeVisitor visitMethod(int access, String JavaDoc methodName, String JavaDoc desc,
210             String JavaDoc[] exceptions, Attribute attrs) {
211
212         if (!alreadyWeaved) {
213             return new TopLinkMethodWeaver(this, methodName, desc, cv.visitMethod(access, methodName, desc, exceptions, attrs));
214         } else {
215             return super.visitMethod(access, methodName, desc, exceptions, attrs);
216         }
217     }
218
219     public void visitAttribute(Attribute attr) {
220         if (!alreadyWeaved) {
221             cv.visitAttribute(attr);
222         } else {
223             super.visitAttribute(attr);
224         }
225     }
226
227     public void visitEnd() {
228         if (!alreadyWeaved) {
229             // add implementation of weavedValueHolders() method in the TopLinkWeaved interface
230
// this method will return true if we have weaved and false otherwise.
231
CodeVisitor cv_weavedValueHolders = cv.visitMethod(ACC_PUBLIC,
232                 "weavedValueHolders", "()Z", null, null);
233             if (classDetails.weavedValueHolders()) {
234                 cv_weavedValueHolders.visitInsn(ICONST_1);
235             } else {
236                 cv_weavedValueHolders.visitInsn(ICONST_0);
237             }
238             cv_weavedValueHolders.visitInsn(IRETURN);
239             cv_weavedValueHolders.visitMaxs(0, 0);
240         }
241         
242         // for each attribute we need to check what methods and variables to add
243
for (Iterator i = classDetails.getAttributesMap().values().iterator();i.hasNext();) {
244             AttributeDetails attributeDetails = (AttributeDetails)i.next();
245             if (attributeDetails.weaveValueHolders()) {
246                 
247                 // we will add valueholders and methods to classes that have not already been weaved
248
// and classes that actually contain the attribute we are processing
249
// an attribute could be in the classDetails but not actually in the class
250
// if it is owned by a MappedSuperClass
251
if (!alreadyWeaved && !attributeDetails.isAttributeOnSuperClass()){
252                     addValueHolder(attributeDetails);
253                     addGetterMethodForValueHolder(classDetails, attributeDetails);
254                     addSetterMethodForValueHolder(classDetails, attributeDetails);
255                     
256                     // We only add the following convenience method if we are using attribute access.
257
if (attributeDetails.getMapping().usesIndirection() && attributeDetails.isMappedWithAttributeAccess()){
258                         addSetterMethodForFieldAccess(classDetails, attributeDetails);
259                         addGetterMethodForFieldAccess(classDetails, attributeDetails);
260                     }
261                 }
262  
263             }
264         }
265         super.visitEnd();
266     }
267 }
268
Popular Tags