1 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 ; 55 import java.lang.reflect.Method ; 56 import java.util.ArrayList ; 57 import java.util.logging.Level ; 58 import java.util.logging.Logger ; 59 60 63 public class AmberEnhancer implements AmberGenerator, ClassEnhancer { 64 private static final L10N L = new L10N(AmberEnhancer.class); 65 private static final Logger 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 <String > _pendingClassNames = new ArrayList <String >(); 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 91 public void setConfigDirectory(Path dir) 92 { 93 _configDirectory = dir; 94 } 95 96 99 public Path getWorkDir() 100 { 101 return _workDir; 102 } 103 104 107 public void init() 108 throws Exception 109 { 110 } 111 112 115 protected boolean isModified(Class preloadedClass) 116 { 117 try { 118 Method init = preloadedClass.getMethod("_caucho_init", 119 new Class [] { Path.class }); 120 121 122 if (_configDirectory != null) 123 init.invoke(null, new Object [] { _configDirectory }); 124 else 125 init.invoke(null, new Object [] { Vfs.lookup() }); 126 127 Method isModified = preloadedClass.getMethod("_caucho_is_modified", 128 new Class [0]); 129 130 Object value = isModified.invoke(null, new Object [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 e) { 139 log.log(Level.FINER, e.toString(), e); 140 141 return true; 142 } 143 } 144 145 148 public boolean shouldEnhance(String 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 197 } 198 199 202 private EntityType loadEntityType(Class cl, ClassLoader loader) 203 { 204 EntityType parentType = null; 205 206 for (; cl != null; cl = cl.getSuperclass()) { 207 java.net.URL url; 208 209 String 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 cl, ClassLoader rawLoader) 229 { 230 return null; 231 } 232 233 236 public void preEnhance(JavaClass baseClass) 237 throws Exception 238 { 239 EntityType type = _amberContainer.getEntity(baseClass.getName()); 240 241 if (type instanceof SubEntityType) { 242 SubEntityType subType = (SubEntityType) type; 243 244 String parentClass = subType.getParentType().getInstanceClassName(); 245 baseClass.setSuperClass(parentClass.replace('.', '/')); 246 } 247 } 248 249 252 public void enhance(GenClass genClass, 253 JClass baseClass, 254 String extClassName) 255 throws Exception 256 { 257 String className = baseClass.getName(); 258 259 EntityType entityType = _amberContainer.getEntity(className); 260 261 if (entityType != null) { 263 264 log.info("Amber enhancing class " + className); 265 266 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 288 290 } 292 293 ListenerType listenerType = _amberContainer.getListener(className); 294 295 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 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 335 public void generate(AbstractEnhancedType type) 336 throws Exception 337 { 338 JavaClassGenerator javaGen = new JavaClassGenerator(); 339 340 javaGen.setWorkDir(getWorkDir()); 341 342 String 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 354 public void generateJava(JavaClassGenerator javaGen, 355 AbstractEnhancedType type) 356 throws Exception 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 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 } 420 421 424 public void compile() 425 throws Exception 426 { 427 if (_pendingClassNames.size() == 0) 428 return; 429 430 ArrayList <String > classNames = new ArrayList <String >(_pendingClassNames); 431 _pendingClassNames.clear(); 432 433 String []javaFiles = new String [classNames.size()]; 434 435 for (int i = 0; i < classNames.size(); i++) { 436 String 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 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 extClassName = classNames.get(i); 455 int tail = extClassName.length() - "__ResinExt".length(); 456 457 String baseClassName = extClassName.substring(0, tail); 458 459 } 461 } 462 463 466 public void postEnhance(JavaClass baseClass) 467 throws Exception 468 { 469 String className = baseClass.getThisClass(); 470 471 ArrayList <FieldMap> fieldMaps = new ArrayList <FieldMap>(); 472 473 JClass thisClass = _amberContainer.getJClassLoader().forName(className.replace('/', '.')); 474 475 if (thisClass == null) 476 return; 477 478 JClass entityClass = thisClass; 480 481 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 521 public void configure(AbstractEnhancedType type) 522 throws ConfigException, IOException 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 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 getterName = "__caucho_get_" + fieldName; 546 547 methodRef = pool.addMethodRef(baseClass.getThisClass(), 548 getterName, 549 "()" + fieldRef.getType()); 550 551 _getterRef = methodRef.getIndex(); 552 553 String 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 <FieldMap> _fieldMap; 580 581 FieldFixupAnalyzer(ArrayList <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 |