KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > caucho > amber > gen > AmberEnhancer


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.amber.gen;
31
32 import com.caucho.amber.field.AmberField;
33 import com.caucho.amber.manager.AmberContainer;
34 import com.caucho.amber.type.AbstractEnhancedType;
35 import com.caucho.amber.type.AbstractStatefulType;
36 import com.caucho.amber.type.EmbeddableType;
37 import com.caucho.amber.type.EntityType;
38 import com.caucho.amber.type.ListenerType;
39 import com.caucho.amber.type.SubEntityType;
40 import com.caucho.bytecode.*;
41 import com.caucho.config.ConfigException;
42 import com.caucho.java.JavaCompiler;
43 import com.caucho.java.WorkDir;
44 import com.caucho.java.gen.DependencyComponent;
45 import com.caucho.java.gen.GenClass;
46 import com.caucho.java.gen.JavaClassGenerator;
47 import com.caucho.loader.enhancer.ClassEnhancer;
48 import com.caucho.loader.enhancer.EnhancerPrepare;
49 import com.caucho.log.Log;
50 import com.caucho.util.L10N;
51 import com.caucho.vfs.Path;
52 import com.caucho.vfs.Vfs;
53
54 import java.io.IOException JavaDoc;
55 import java.lang.reflect.Method JavaDoc;
56 import java.util.ArrayList JavaDoc;
57 import java.util.logging.Level JavaDoc;
58 import java.util.logging.Logger JavaDoc;
59
60 /**
61  * Enhancing the java objects for Amber mapping.
62  */

63 public class AmberEnhancer implements AmberGenerator, ClassEnhancer {
64   private static final L10N L = new L10N(AmberEnhancer.class);
65   private static final Logger JavaDoc log = Log.open(AmberEnhancer.class);
66
67   private Path _configDirectory;
68   private boolean _useHibernateFiles;
69
70   private AmberContainer _amberContainer;
71
72   private EnhancerPrepare _prepare;
73   private Path _workDir;
74
75   private ArrayList JavaDoc<String JavaDoc> _pendingClassNames = new ArrayList JavaDoc<String JavaDoc>();
76
77   public AmberEnhancer(AmberContainer amberContainer)
78   {
79     _amberContainer = amberContainer;
80     _workDir = WorkDir.getLocalWorkDir().lookup("pre-enhance");
81
82     _prepare = new EnhancerPrepare();
83     _prepare.setClassLoader(Thread.currentThread().getContextClassLoader());
84     _prepare.setWorkPath(WorkDir.getLocalWorkDir());
85     _prepare.addEnhancer(this);
86   }
87
88   /**
89    * Sets the config directory.
90    */

91   public void setConfigDirectory(Path dir)
92   {
93     _configDirectory = dir;
94   }
95
96   /**
97    * Returns the work directory.
98    */

99   public Path getWorkDir()
100   {
101     return _workDir;
102   }
103
104   /**
105    * Initialize the enhancer.
106    */

107   public void init()
108     throws Exception JavaDoc
109   {
110   }
111
112   /**
113    * Checks to see if the preloaded class is modified.
114    */

115   protected boolean isModified(Class JavaDoc preloadedClass)
116   {
117     try {
118       Method JavaDoc init = preloadedClass.getMethod("_caucho_init",
119                                              new Class JavaDoc[] { Path.class });
120
121
122       if (_configDirectory != null)
123         init.invoke(null, new Object JavaDoc[] { _configDirectory });
124       else
125         init.invoke(null, new Object JavaDoc[] { Vfs.lookup() });
126
127       Method JavaDoc isModified = preloadedClass.getMethod("_caucho_is_modified",
128                                                    new Class JavaDoc[0]);
129
130       Object JavaDoc value = isModified.invoke(null, new Object JavaDoc[0]);
131
132       if (Boolean.FALSE.equals(value)) {
133         loadEntityType(preloadedClass, preloadedClass.getClassLoader());
134         return false;
135       }
136       else
137         return true;
138     } catch (Throwable JavaDoc e) {
139       log.log(Level.FINER, e.toString(), e);
140
141       return true;
142     }
143   }
144
145   /**
146    * Returns true if the class should be enhanced.
147    */

148   public boolean shouldEnhance(String JavaDoc className)
149   {
150     int p = className.lastIndexOf('-');
151
152     if (p > 0)
153       className = className.substring(0, p);
154
155     p = className.lastIndexOf('$');
156
157     if (p > 0)
158       className = className.substring(0, p);
159
160     EntityType entityType = _amberContainer.getEntity(className);
161
162     if (entityType != null && entityType.isEnhanced())
163       return true;
164
165     EmbeddableType embeddableType = _amberContainer.getEmbeddable(className);
166
167     if (embeddableType != null && embeddableType.isEnhanced())
168       return true;
169
170     ListenerType listenerType = _amberContainer.getListener(className);
171
172     if (listenerType != null && listenerType.isEnhanced())
173       return true;
174
175     return false;
176
177     /*
178       Thread thread = Thread.currentThread();
179       ClassLoader oldLoader = thread.getContextClassLoader();
180       try {
181       thread.setContextClassLoader(getRawLoader());
182
183       Class baseClass = Class.forName(className, false, getRawLoader());
184
185       type = loadEntityType(baseClass, getRawLoader());
186       } catch (ClassNotFoundException e) {
187       return false;
188       } finally {
189       thread.setContextClassLoader(oldLoader);
190       }
191
192       if (type == null)
193       return false;
194
195       return className.equals(type.getName()) || type.isFieldAccess();
196     */

197   }
198
199   /**
200    * Returns true if the class should be enhanced.
201    */

202   private EntityType loadEntityType(Class JavaDoc cl, ClassLoader JavaDoc loader)
203   {
204     EntityType parentType = null;
205
206     for (; cl != null; cl = cl.getSuperclass()) {
207       java.net.URL JavaDoc url;
208
209       String JavaDoc className = cl.getName();
210
211       EntityType type = _amberContainer.getEntity(className);
212
213       if (parentType == null)
214         parentType = type;
215
216       if (type != null && ! type.startConfigure())
217         return type;
218
219       type = loadEntityTypeImpl(cl, loader);
220
221       if (type != null && ! type.startConfigure())
222         return type;
223     }
224
225     return parentType;
226   }
227
228   protected EntityType loadEntityTypeImpl(Class JavaDoc cl, ClassLoader JavaDoc rawLoader)
229   {
230     return null;
231   }
232
233   /**
234    * Enhances the class.
235    */

236   public void preEnhance(JavaClass baseClass)
237     throws Exception JavaDoc
238   {
239     EntityType type = _amberContainer.getEntity(baseClass.getName());
240
241     if (type instanceof SubEntityType) {
242       SubEntityType subType = (SubEntityType) type;
243
244       String JavaDoc parentClass = subType.getParentType().getInstanceClassName();
245       baseClass.setSuperClass(parentClass.replace('.', '/'));
246     }
247   }
248
249   /**
250    * Enhances the class.
251    */

252   public void enhance(GenClass genClass,
253                       JClass baseClass,
254                       String JavaDoc extClassName)
255     throws Exception JavaDoc
256   {
257     String JavaDoc className = baseClass.getName();
258
259     EntityType entityType = _amberContainer.getEntity(className);
260
261     // Type can be null for subclasses and inner classes that need fixups
262
if (entityType != null) {
263
264       log.info("Amber enhancing class " + className);
265
266       // XXX: _amberContainerenceUnitenceUnit.configure();
267

268       entityType.init();
269
270       genClass.addInterfaceName("com.caucho.amber.entity.Entity");
271
272       EntityComponent entity = new EntityComponent();
273
274       entity.setEntityType(entityType);
275       entity.setBaseClassName(baseClass.getName());
276       entity.setExtClassName(extClassName);
277
278       genClass.addComponent(entity);
279
280       DependencyComponent dependency = genClass.addDependencyComponent();
281       dependency.addDependencyList(entityType.getDependencies());
282
283       return;
284
285       //_amberContainerenceUnitenceUnit.generate();
286
// generate(type);
287

288       // compile();
289

290       // XXX: _amberContainerenceUnitenceUnit.initEntityHomes();
291
}
292
293     ListenerType listenerType = _amberContainer.getListener(className);
294
295     // Type can be null for subclasses and inner classes that need fixups
296
if (listenerType != null) {
297       log.info("Amber enhancing class " + className);
298
299       listenerType.init();
300
301       genClass.addInterfaceName("com.caucho.amber.entity.Listener");
302
303       ListenerComponent listener = new ListenerComponent();
304
305       listener.setListenerType(listenerType);
306       listener.setBaseClassName(baseClass.getName());
307       listener.setExtClassName(extClassName);
308
309       genClass.addComponent(listener);
310     }
311
312     EmbeddableType embeddableType = _amberContainer.getEmbeddable(className);
313
314     // Type can be null for subclasses and inner classes that need fixups
315
if (embeddableType != null) {
316       log.info("Amber enhancing class " + className);
317
318       embeddableType.init();
319
320       genClass.addInterfaceName("com.caucho.amber.entity.Embeddable");
321
322       EmbeddableComponent embeddable = new EmbeddableComponent();
323
324       embeddable.setEmbeddableType(embeddableType);
325       embeddable.setBaseClassName(baseClass.getName());
326       embeddable.setExtClassName(extClassName);
327
328       genClass.addComponent(embeddable);
329     }
330   }
331
332   /**
333    * Generates the type.
334    */

335   public void generate(AbstractEnhancedType type)
336     throws Exception JavaDoc
337   {
338     JavaClassGenerator javaGen = new JavaClassGenerator();
339
340     javaGen.setWorkDir(getWorkDir());
341
342     String JavaDoc extClassName = type.getBeanClass().getName() + "__ResinExt";
343     type.setInstanceClassName(extClassName);
344     type.setEnhanced(true);
345
346     _pendingClassNames.add(type.getInstanceClassName());
347
348     generateJava(javaGen, type);
349   }
350
351   /**
352    * Generates the type.
353    */

354   public void generateJava(JavaClassGenerator javaGen,
355                            AbstractEnhancedType type)
356     throws Exception JavaDoc
357   {
358     if (type.isGenerated())
359       return;
360
361     type.setGenerated(true);
362
363     _prepare.renameClass(type.getBeanClass().getName(),
364                          type.getBeanClass().getName());
365
366     GenClass javaClass = new GenClass(type.getInstanceClassName());
367
368     javaClass.setSuperClassName(type.getBeanClass().getName());
369
370     if (type instanceof EntityType) {
371       javaClass.addInterfaceName("com.caucho.amber.entity.Entity");
372
373       type.setEnhanced(true);
374
375       EntityComponent entity = new EntityComponent();
376
377       entity.setEntityType((EntityType) type);
378       entity.setBaseClassName(type.getBeanClass().getName());
379
380       //String extClassName = gen.getBaseClassName() + "__ResinExt";
381
// type.setInstanceClassName(extClassName);
382

383       entity.setExtClassName(type.getInstanceClassName());
384
385       javaClass.addComponent(entity);
386     }
387     else if (type instanceof ListenerType) {
388       javaClass.addInterfaceName("com.caucho.amber.entity.Listener");
389
390       type.setEnhanced(true);
391
392       ListenerComponent listener = new ListenerComponent();
393
394       listener.setListenerType((ListenerType) type);
395       listener.setBaseClassName(type.getBeanClass().getName());
396
397       listener.setExtClassName(type.getInstanceClassName());
398
399       javaClass.addComponent(listener);
400     }
401     else {
402       javaClass.addInterfaceName("com.caucho.amber.entity.Embeddable");
403
404       type.setEnhanced(true);
405
406       EmbeddableComponent embeddable = new EmbeddableComponent();
407
408       embeddable.setEmbeddableType((EmbeddableType) type);
409       embeddable.setBaseClassName(type.getBeanClass().getName());
410
411       embeddable.setExtClassName(type.getInstanceClassName());
412
413       javaClass.addComponent(embeddable);
414     }
415
416     javaGen.generate(javaClass);
417
418     // _pendingClassNames.add(extClassName);
419
}
420
421   /**
422    * Compiles the pending classes.
423    */

424   public void compile()
425     throws Exception JavaDoc
426   {
427     if (_pendingClassNames.size() == 0)
428       return;
429
430     ArrayList JavaDoc<String JavaDoc> classNames = new ArrayList JavaDoc<String JavaDoc>(_pendingClassNames);
431     _pendingClassNames.clear();
432
433     String JavaDoc []javaFiles = new String JavaDoc[classNames.size()];
434
435     for (int i = 0; i < classNames.size(); i++) {
436       String JavaDoc name = classNames.get(i);
437
438       name = name.replace('.', '/') + ".java";
439
440       javaFiles[i] = name;
441     }
442
443     EntityGenerator gen = new EntityGenerator();
444     gen.setSearchPath(_configDirectory);
445     // XXX:
446
// gen.setClassDir(getPath());
447

448     JavaCompiler compiler = gen.getCompiler();
449
450     compiler.setClassDir(getWorkDir());
451     compiler.compileBatch(javaFiles);
452
453     for (int i = 0; i < classNames.size(); i++) {
454       String JavaDoc extClassName = classNames.get(i);
455       int tail = extClassName.length() - "__ResinExt".length();
456
457       String JavaDoc baseClassName = extClassName.substring(0, tail);
458
459       // fixup(baseClassName, extClassName);
460
}
461   }
462
463   /**
464    * Enhances the class.
465    */

466   public void postEnhance(JavaClass baseClass)
467     throws Exception JavaDoc
468   {
469     String JavaDoc className = baseClass.getThisClass();
470
471     ArrayList JavaDoc<FieldMap> fieldMaps = new ArrayList JavaDoc<FieldMap>();
472
473     JClass thisClass = _amberContainer.getJClassLoader().forName(className.replace('/', '.'));
474
475     if (thisClass == null)
476       return;
477
478     // Cache entity JClass for next fixup.
479
JClass entityClass = thisClass;
480
481     // Field-based fixup.
482
do {
483       AbstractStatefulType type;
484
485       type = _amberContainer.getEntity(thisClass.getName());
486
487       if (type == null)
488         type = _amberContainer.getEmbeddable(thisClass.getName());
489
490       if (type == null || ! type.isFieldAccess())
491         continue;
492
493       if (type instanceof EntityType) {
494         EntityType entityType = (EntityType) type;
495
496         for (AmberField field : entityType.getId().getKeys()) {
497           fieldMaps.add(new FieldMap(baseClass, field.getName()));
498         }
499       }
500
501       for (AmberField field : type.getFields()) {
502         fieldMaps.add(new FieldMap(baseClass, field.getName()));
503       }
504     }
505     while ((thisClass = thisClass.getSuperClass()) != null);
506
507     if (fieldMaps.size() > 0) {
508       FieldFixupAnalyzer analyzer = new FieldFixupAnalyzer(fieldMaps);
509
510       for (JavaMethod javaMethod : baseClass.getMethodList()) {
511         CodeVisitor visitor = new CodeVisitor(baseClass, javaMethod.getCode());
512
513         visitor.analyze(analyzer, true);
514       }
515     }
516   }
517
518   /**
519    * Parses the configuration file.
520    */

521   public void configure(AbstractEnhancedType type)
522     throws ConfigException, IOException JavaDoc
523   {
524   }
525
526   static class FieldMap {
527     private int _fieldRef = -1;
528     private int _getterRef;
529     private int _setterRef;
530
531     FieldMap(com.caucho.bytecode.JavaClass baseClass,
532              String JavaDoc fieldName)
533     {
534       ConstantPool pool = baseClass.getConstantPool();
535
536       FieldRefConstant fieldRef = pool.getFieldRef(fieldName);
537
538       if (fieldRef == null)
539         return;
540
541       _fieldRef = fieldRef.getIndex();
542
543       MethodRefConstant methodRef;
544
545       String JavaDoc getterName = "__caucho_get_" + fieldName;
546
547       methodRef = pool.addMethodRef(baseClass.getThisClass(),
548                                     getterName,
549                                     "()" + fieldRef.getType());
550
551       _getterRef = methodRef.getIndex();
552
553       String JavaDoc setterName = "__caucho_set_" + fieldName;
554
555       methodRef = pool.addMethodRef(baseClass.getThisClass(),
556                                     setterName,
557                                     "(" + fieldRef.getType() + ")V");
558
559       _setterRef = methodRef.getIndex();
560     }
561
562     int getFieldRef()
563     {
564       return _fieldRef;
565     }
566
567     int getGetterRef()
568     {
569       return _getterRef;
570     }
571
572     int getSetterRef()
573     {
574       return _setterRef;
575     }
576   }
577
578   static class FieldFixupAnalyzer extends Analyzer {
579     private ArrayList JavaDoc<FieldMap> _fieldMap;
580
581     FieldFixupAnalyzer(ArrayList JavaDoc<FieldMap> fieldMap)
582     {
583       _fieldMap = fieldMap;
584     }
585
586     int getGetter(int fieldRef)
587     {
588       for (int i = _fieldMap.size() - 1; i >= 0; i--) {
589         FieldMap fieldMap = _fieldMap.get(i);
590
591         if (fieldMap.getFieldRef() == fieldRef)
592           return fieldMap.getGetterRef();
593       }
594
595       return -1;
596     }
597
598     public void analyze(CodeVisitor visitor)
599     {
600       switch (visitor.getOpcode()) {
601       case CodeVisitor.GETFIELD:
602         int getter = getGetter(visitor.getShortArg());
603
604         if (getter > 0) {
605           visitor.setByteArg(0, CodeVisitor.INVOKEVIRTUAL);
606           visitor.setShortArg(1, getter);
607         }
608         break;
609       case CodeVisitor.PUTFIELD:
610         int setter = getSetter(visitor.getShortArg());
611
612         if (setter > 0) {
613           visitor.setByteArg(0, CodeVisitor.INVOKEVIRTUAL);
614           visitor.setShortArg(1, setter);
615         }
616         break;
617       }
618     }
619
620     int getSetter(int fieldRef)
621     {
622       for (int i = _fieldMap.size() - 1; i >= 0; i--) {
623         FieldMap fieldMap = _fieldMap.get(i);
624
625         if (fieldMap.getFieldRef() == fieldRef)
626           return fieldMap.getSetterRef();
627       }
628
629       return -1;
630     }
631   }
632 }
633
Popular Tags