KickJava   Java API By Example, From Geeks To Geeks.

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


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.instrument.*;
26 import java.io.FileOutputStream JavaDoc;
27 import java.security.ProtectionDomain JavaDoc;
28 import java.util.Map JavaDoc;
29 import java.util.StringTokenizer JavaDoc;
30 import java.io.File JavaDoc;
31 import javax.persistence.spi.ClassTransformer;
32
33 // ASM imports
34
import oracle.toplink.libraries.asm.*;
35 import oracle.toplink.libraries.asm.attrs.Attributes;
36
37 // TopLink imports
38
import oracle.toplink.essentials.logging.SessionLog;
39 import oracle.toplink.essentials.sessions.Session;
40
41
42 /**
43  * INTERNAL:
44  * This class performs dynamic bytecode weaving: for each attribute
45  * mapped with One To One mapping with Basic Indirection it substitutes the
46  * original attribute's type for ValueHolderInterface.
47  */

48 public class TopLinkWeaver implements ClassTransformer {
49     
50     public static final String JavaDoc WEAVING_OUTPUT_PATH = "toplink.weaving.output.path";
51     public static final String JavaDoc WEAVING_SHOULD_OVERWRITE = "toplink.weaving.overwrite.existing";
52     public static final String JavaDoc WEAVER_NOT_OVERWRITING = "weaver_not_overwriting";
53     public static final String JavaDoc WEAVER_COULD_NOT_WRITE = "weaver_could_not_write";
54     
55     protected Session session; // for logging
56
// Map<String, ClassDetails> where the key is className in JVM '/' format
57
protected Map JavaDoc classDetailsMap;
58     
59     public TopLinkWeaver(Session session, Map JavaDoc classDetailsMap) {
60         this.session = session;
61         this.classDetailsMap = classDetailsMap;
62     }
63     
64     public Map JavaDoc getClassDetailsMap() {
65         return classDetailsMap;
66     }
67
68     // @Override: well, not precisely. I wanted the code to be 1.4 compatible,
69
// so the method is written without any Generic type <T>'s in the signature
70
public byte[] transform(ClassLoader JavaDoc loader, String JavaDoc className,
71         Class JavaDoc classBeingRedefined, ProtectionDomain JavaDoc protectionDomain,
72         byte[] classfileBuffer) throws IllegalClassFormatException {
73         
74         /*
75          * The ClassFileTransformer callback - when called by the JVM's
76          * Instrumentation implementation - is invoked for every class loaded.
77          * Thus, we must check the classDetailsMap to see if we are 'interested'
78          * in the class.
79          *
80          * Note: when invoked by the OC4J wrapper class
81          * oracle.toplink.essentials.internal.ejb.cmp3.oc4j.OC4JClassTransformer,
82          * callbacks are made only for the 'interesting' classes
83          */

84         ClassDetails classDetails = (ClassDetails)classDetailsMap.get(className);
85         if (classDetails != null) {
86             ClassReader cr = new ClassReader(classfileBuffer);
87             ClassWriter cw = new ClassWriter(true, true);
88             TopLinkClassWeaver tcw = new TopLinkClassWeaver(cw, classDetails);
89             cr.accept(tcw, Attributes.getDefaultAttributes(), false);
90             if (tcw.alreadyWeaved) {
91                 return null;
92             }
93             byte[] bytes = cw.toByteArray();
94             
95             String JavaDoc outputPath = System.getProperty(WEAVING_OUTPUT_PATH, "");
96
97             if (!outputPath.equals("")) {
98                 outputFile(className, bytes, outputPath);
99             }
100             if (tcw.weavedVH) {
101                 return bytes;
102             }
103         }
104         return null; // returning null means 'use existing class bytes'
105
}
106     
107     protected void outputFile(String JavaDoc className, byte[] classBytes, String JavaDoc outputPath){
108         StringBuffer JavaDoc directoryName = new StringBuffer JavaDoc();;
109         StringTokenizer JavaDoc tokenizer = new StringTokenizer JavaDoc(className, "\n\\/");
110         String JavaDoc token = null;
111         while (tokenizer.hasMoreTokens()){
112             token = tokenizer.nextToken();
113             if (tokenizer.hasMoreTokens()){
114                 directoryName.append(token + File.separator);
115             }
116         }
117         try{
118             String JavaDoc usedOutputPath = outputPath;
119             if (!outputPath.endsWith(File.separator)){
120                 usedOutputPath = outputPath + File.separator;
121             }
122             File JavaDoc file = new File JavaDoc(usedOutputPath + directoryName);
123             file.mkdirs();
124             file = new File JavaDoc(file, token + ".class");
125             if (!file.exists()){
126                 file.createNewFile();
127             } else {
128                 if (!System.getProperty(WEAVING_SHOULD_OVERWRITE, "false").equalsIgnoreCase("true")){
129                     ((oracle.toplink.essentials.internal.sessions.AbstractSession)session).log(
130                             SessionLog.WARNING, SessionLog.WEAVER, WEAVER_NOT_OVERWRITING, className);
131                     return;
132                 }
133             }
134             FileOutputStream JavaDoc fos = new FileOutputStream JavaDoc(file);
135             fos.write(classBytes);
136             fos.close();
137         } catch (Exception JavaDoc e){
138             ((oracle.toplink.essentials.internal.sessions.AbstractSession)session).log(
139                     SessionLog.WARNING, SessionLog.WEAVER, WEAVER_COULD_NOT_WRITE, className, e);
140         }
141     }
142     
143     // same as in oracle.toplink.essentials.internal.helper.Helper, but uses
144
// '/' slash as delimiter, not '.'
145
protected static String JavaDoc getShortName(String JavaDoc name) {
146         int pos = name.lastIndexOf('/');
147         if (pos >= 0) {
148             name = name.substring(pos+1);
149             if (name.endsWith(";")) {
150                 name = name.substring(0, name.length()-1);
151             }
152             return name;
153         }
154         return "";
155     }
156 }
157
Popular Tags