KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > caucho > loader > enhancer > EnhancerManager


1 /*
2  * Copyright (c) 1998-2006 Caucho Technology -- all rights reserved
3  *
4  * This file is part of Resin(R) Open Source
5  *
6  * Each copy or derived work must preserve the copyright notice and this
7  * notice unmodified.
8  *
9  * Resin Open Source is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * Resin Open Source is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
17  * of NON-INFRINGEMENT. See the GNU General Public License for more
18  * details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with Resin Open Source; if not, write to the
22  *
23  * Free Software Foundation, Inc.
24  * 59 Temple Place, Suite 330
25  * Boston, MA 02111-1307 USA
26  *
27  * @author Scott Ferguson
28  */

29
30 package com.caucho.loader.enhancer;
31
32 import com.caucho.bytecode.ByteCodeClassMatcher;
33 import com.caucho.bytecode.ByteCodeClassScanner;
34 import com.caucho.bytecode.ByteCodeParser;
35 import com.caucho.bytecode.JClass;
36 import com.caucho.bytecode.JavaClass;
37 import com.caucho.bytecode.JavaClassLoader;
38 import com.caucho.java.WorkDir;
39 import com.caucho.java.gen.GenClass;
40 import com.caucho.java.gen.JavaClassGenerator;
41 import com.caucho.loader.DynamicClassLoader;
42 import com.caucho.loader.EnvironmentLocal;
43 import com.caucho.util.CharBuffer;
44 import com.caucho.util.L10N;
45 import com.caucho.util.Log;
46 import com.caucho.vfs.Path;
47 import com.caucho.vfs.ReadStream;
48
49 import java.io.ByteArrayInputStream JavaDoc;
50 import java.lang.instrument.*;
51 import java.util.ArrayList JavaDoc;
52 import java.security.*;
53 import java.util.logging.Level JavaDoc;
54 import java.util.logging.Logger JavaDoc;
55
56 /**
57  * Manages the enhancement
58  */

59 public class EnhancerManager
60   implements ClassFileTransformer, ByteCodeClassMatcher
61 {
62   private static final L10N L = new L10N(EnhancerManager.class);
63   private static final Logger JavaDoc log = Log.open(EnhancerManager.class);
64
65   private static EnvironmentLocal<EnhancerManager> _localEnhancer =
66     new EnvironmentLocal<EnhancerManager>();
67
68   private EnhancerManager _parent;
69   private DynamicClassLoader _loader;
70
71   private Path _workPath;
72
73   private JavaClassLoader _jClassLoader = new JavaClassLoader();
74   private JavaClassGenerator _javaGen = new JavaClassGenerator();
75   
76   private ArrayList JavaDoc<ClassEnhancer> _classEnhancerList =
77     new ArrayList JavaDoc<ClassEnhancer>();
78   
79   private EnhancerManager(ClassLoader JavaDoc loader)
80   {
81     for (;
82      loader != null && ! (loader instanceof DynamicClassLoader);
83      loader = loader.getParent()) {
84     }
85
86     _loader = (DynamicClassLoader) loader;
87
88     if (loader != null)
89       _parent = getLocalEnhancer(loader.getParent());
90
91     if (_parent != null) {
92       _classEnhancerList.addAll(_parent._classEnhancerList);
93     }
94   }
95
96   public static EnhancerManager create()
97   {
98     return create(Thread.currentThread().getContextClassLoader());
99   }
100
101   public static EnhancerManager create(ClassLoader JavaDoc loader)
102   {
103     EnhancerManager enhancer = _localEnhancer.getLevel(loader);
104
105     if (enhancer == null) {
106       enhancer = new EnhancerManager(loader);
107       _localEnhancer.set(enhancer, loader);
108
109       for (; loader != null; loader = loader.getParent()) {
110     if (loader instanceof DynamicClassLoader) {
111       ((DynamicClassLoader) loader).addTransformer(enhancer);
112       break;
113     }
114       }
115     }
116
117     return enhancer;
118   }
119
120   public static EnhancerManager getLocalEnhancer(ClassLoader JavaDoc loader)
121   {
122     return _localEnhancer.get(loader);
123   }
124
125   /**
126    * Returns the JClassLoader.
127    */

128   public JavaClassLoader getJavaClassLoader()
129   {
130     return _jClassLoader;
131   }
132
133   /**
134    * Gets the work path.
135    */

136   public Path getWorkPath()
137   {
138     if (_workPath != null)
139       return _workPath;
140     else
141       return WorkDir.getLocalWorkDir(_loader);
142   }
143
144   /**
145    * Sets the work path.
146    */

147   public void setWorkPath(Path workPath)
148   {
149     _workPath = workPath;
150   }
151
152   /**
153    * Gets the work path.
154    */

155   public final Path getPreWorkPath()
156   {
157     return getWorkPath().lookup("pre-enhance");
158   }
159
160   /**
161    * Gets the work path.
162    */

163   public final Path getPostWorkPath()
164   {
165     return getWorkPath().lookup("post-enhance");
166   }
167
168   /**
169    * Adds a class enhancer.
170    */

171   public void addClassEnhancer(ClassEnhancer classEnhancer)
172   {
173     _classEnhancerList.add(classEnhancer);
174   }
175
176   /**
177    * Adds a class annotation.
178    */

179   public void addClass(ClassEnhancerConfig config)
180   {
181     config.setEnhancerManager(this);
182
183     _classEnhancerList.add(config);
184   }
185   
186   /**
187    * Returns the enhanced .class or null if no enhancement.
188    */

189   public byte[] transform(ClassLoader JavaDoc loader,
190               String JavaDoc className,
191               Class JavaDoc oldClass,
192               ProtectionDomain domain,
193               byte []buffer)
194   {
195     int length = buffer.length;
196     
197     ByteCodeClassScanner scanner;
198
199     // XXX: temp
200
scanner = new ByteCodeClassScanner(className, buffer, 0, length, this);
201
202     if (scanner.scan()) {
203       try {
204     ByteCodeParser parser = new ByteCodeParser();
205     parser.setClassLoader(_jClassLoader);
206     
207     ByteArrayInputStream JavaDoc is;
208     is = new ByteArrayInputStream JavaDoc(buffer, 0, length);
209       
210     JavaClass jClass = parser.parse(is);
211
212     return enhance(jClass);
213       } catch (Throwable JavaDoc e) {
214     throw new EnhancerRuntimeException(e);
215       }
216     }
217
218     return null;
219   }
220
221   /**
222    * Enhances the given class.
223    */

224   public byte []enhance(JClass jClass)
225     throws ClassNotFoundException JavaDoc
226   {
227     String JavaDoc className = jClass.getName().replace('/', '.');
228     String JavaDoc extClassName = className + "__ResinExt";
229
230     try {
231       EnhancerPrepare prepare = new EnhancerPrepare();
232       prepare.setWorkPath(getWorkPath());
233       prepare.setClassLoader(_loader);
234
235       for (ClassEnhancer enhancer : _classEnhancerList) {
236     if (enhancer.shouldEnhance(className)) {
237       prepare.addEnhancer(enhancer);
238     }
239       }
240
241       //prepare.renameClass(className, extClassName);
242
prepare.renameClass(className, className);
243     } catch (Exception JavaDoc e) {
244       log.log(Level.FINE, e.toString(), e);
245
246       throw new ClassNotFoundException JavaDoc(e.toString());
247     }
248
249     boolean hasEnhancer = false;
250     GenClass genClass = new GenClass(extClassName);
251     genClass.setSuperClassName(className);
252
253     for (ClassEnhancer enhancer : _classEnhancerList) {
254       if (enhancer.shouldEnhance(className)) {
255     try {
256       hasEnhancer = true;
257       enhancer.enhance(genClass, jClass, extClassName);
258     } catch (RuntimeException JavaDoc e) {
259       throw e;
260     } catch (Exception JavaDoc e) {
261       throw new RuntimeException JavaDoc(e);
262     }
263       }
264     }
265     // XXX: class-wide enhancements need to go first
266

267     try {
268       if (hasEnhancer) {
269     _javaGen.setWorkDir(getPreWorkPath());
270     _javaGen.generate(genClass);
271     _javaGen.compilePendingJava();
272       }
273
274       EnhancerFixup fixup = new EnhancerFixup();
275       fixup.setJavaClassLoader(_jClassLoader);
276       fixup.setClassLoader(_loader);
277       fixup.setWorkPath(getWorkPath());
278
279       for (ClassEnhancer enhancer : _classEnhancerList) {
280     if (enhancer.shouldEnhance(className)) {
281       fixup.addEnhancer(enhancer);
282     }
283       }
284       
285       fixup.fixup(className, extClassName);
286
287       Path path = getPostWorkPath().lookup(className.replace('.', '/') + ".class");
288       byte []buffer = new byte[(int) path.getLength()];
289       
290       ReadStream is = path.openRead();
291       try {
292     is.readAll(buffer, 0, buffer.length);
293       } finally {
294     is.close();
295       }
296
297       return buffer;
298     } catch (RuntimeException JavaDoc e) {
299       throw e;
300     } catch (Exception JavaDoc e) {
301       log.log(Level.FINE, e.toString(), e);
302       
303       throw new ClassNotFoundException JavaDoc(e.getMessage());
304     }
305
306     // return null;
307
}
308
309   /**
310    * Returns true for a matching class.
311    */

312   public boolean isClassMatch(String JavaDoc className)
313   {
314     if (className.lastIndexOf('$') >= 0) {
315       int p = className.lastIndexOf('$');
316       char ch = className.charAt(p + 1);
317
318       if (ch >= '0' && ch <= '9')
319     return false;
320     }
321     else if (className.indexOf('+') > 0 ||
322          className.indexOf('-') > 0)
323       return false;
324     
325     for (int i = 0; i < _classEnhancerList.size(); i++) {
326       if (_classEnhancerList.get(i).shouldEnhance(className)) {
327     return true;
328       }
329     }
330
331     return false;
332   }
333
334   /**
335    * Returns true for a matching class.
336    */

337   public boolean isMatch(CharBuffer cb)
338   {
339     return false;
340   }
341 }
342
Popular Tags