001// Licensed under the Apache License, Version 2.0 (the "License"); 002// you may not use this file except in compliance with the License. 003// You may obtain a copy of the License at 004// 005// http://www.apache.org/licenses/LICENSE-2.0 006// 007// Unless required by applicable law or agreed to in writing, software 008// distributed under the License is distributed on an "AS IS" BASIS, 009// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 010// See the License for the specific language governing permissions and 011// limitations under the License. 012 013package org.apache.tapestry5.internal.services; 014 015import java.lang.reflect.Constructor; 016import java.lang.reflect.Method; 017import java.util.Collections; 018import java.util.HashSet; 019import java.util.Iterator; 020import java.util.List; 021import java.util.Map; 022import java.util.Map.Entry; 023import java.util.Objects; 024import java.util.Set; 025import java.util.stream.Collectors; 026 027import org.apache.tapestry5.ComponentResources; 028import org.apache.tapestry5.SymbolConstants; 029import org.apache.tapestry5.beanmodel.services.PlasticProxyFactoryImpl; 030import org.apache.tapestry5.commons.Location; 031import org.apache.tapestry5.commons.ObjectCreator; 032import org.apache.tapestry5.commons.Resource; 033import org.apache.tapestry5.commons.services.PlasticProxyFactory; 034import org.apache.tapestry5.commons.util.CollectionFactory; 035import org.apache.tapestry5.commons.util.ExceptionUtils; 036import org.apache.tapestry5.http.TapestryHttpSymbolConstants; 037import org.apache.tapestry5.internal.InternalComponentResources; 038import org.apache.tapestry5.internal.InternalConstants; 039import org.apache.tapestry5.internal.model.MutableComponentModelImpl; 040import org.apache.tapestry5.internal.plastic.PlasticInternalUtils; 041import org.apache.tapestry5.internal.services.ComponentDependencyRegistry.DependencyType; 042import org.apache.tapestry5.ioc.Invokable; 043import org.apache.tapestry5.ioc.LoggerSource; 044import org.apache.tapestry5.ioc.OperationTracker; 045import org.apache.tapestry5.ioc.annotations.PostInjection; 046import org.apache.tapestry5.ioc.annotations.Primary; 047import org.apache.tapestry5.ioc.annotations.Symbol; 048import org.apache.tapestry5.ioc.internal.util.ClasspathResource; 049import org.apache.tapestry5.ioc.internal.util.InternalUtils; 050import org.apache.tapestry5.ioc.internal.util.URLChangeTracker; 051import org.apache.tapestry5.ioc.services.Builtin; 052import org.apache.tapestry5.ioc.services.ClasspathURLConverter; 053import org.apache.tapestry5.ioc.services.UpdateListener; 054import org.apache.tapestry5.ioc.services.UpdateListenerHub; 055import org.apache.tapestry5.model.ComponentModel; 056import org.apache.tapestry5.model.MutableComponentModel; 057import org.apache.tapestry5.plastic.ClassInstantiator; 058import org.apache.tapestry5.plastic.ConstructorCallback; 059import org.apache.tapestry5.plastic.InstanceContext; 060import org.apache.tapestry5.plastic.InstructionBuilder; 061import org.apache.tapestry5.plastic.InstructionBuilderCallback; 062import org.apache.tapestry5.plastic.MethodAdvice; 063import org.apache.tapestry5.plastic.MethodDescription; 064import org.apache.tapestry5.plastic.MethodInvocation; 065import org.apache.tapestry5.plastic.PlasticClass; 066import org.apache.tapestry5.plastic.PlasticClassEvent; 067import org.apache.tapestry5.plastic.PlasticClassListener; 068import org.apache.tapestry5.plastic.PlasticClassTransformation; 069import org.apache.tapestry5.plastic.PlasticClassTransformer; 070import org.apache.tapestry5.plastic.PlasticField; 071import org.apache.tapestry5.plastic.PlasticManager; 072import org.apache.tapestry5.plastic.PlasticManager.PlasticManagerBuilder; 073import org.apache.tapestry5.plastic.PlasticManagerDelegate; 074import org.apache.tapestry5.plastic.PlasticMethod; 075import org.apache.tapestry5.plastic.PlasticUtils; 076import org.apache.tapestry5.plastic.TransformationOption; 077import org.apache.tapestry5.runtime.Component; 078import org.apache.tapestry5.runtime.ComponentEvent; 079import org.apache.tapestry5.runtime.ComponentResourcesAware; 080import org.apache.tapestry5.runtime.PageLifecycleListener; 081import org.apache.tapestry5.services.ComponentClassResolver; 082import org.apache.tapestry5.services.ComponentEventHandler; 083import org.apache.tapestry5.services.TransformConstants; 084import org.apache.tapestry5.services.pageload.PageClassLoaderContext; 085import org.apache.tapestry5.services.pageload.PageClassLoaderContextManager; 086import org.apache.tapestry5.services.transform.ComponentClassTransformWorker2; 087import org.apache.tapestry5.services.transform.ControlledPackageType; 088import org.apache.tapestry5.services.transform.TransformationSupport; 089import org.slf4j.Logger; 090 091/** 092 * A wrapper around a {@link PlasticManager} that allows certain classes to be modified as they are loaded. 093 */ 094public final class ComponentInstantiatorSourceImpl implements ComponentInstantiatorSource, UpdateListener, 095 Runnable, PlasticManagerDelegate, PlasticClassListener 096{ 097 private final Set<String> controlledPackageNames = CollectionFactory.newSet(); 098 099 private final URLChangeTracker<ClassName> changeTracker; 100 101 private final ClassLoader parent; 102 103 private final ComponentClassTransformWorker2 transformerChain; 104 105 private final LoggerSource loggerSource; 106 107 private final Logger logger; 108 109 private final OperationTracker tracker; 110 111 private final InternalComponentInvalidationEventHub invalidationHub; 112 113 private final boolean productionMode; 114 115 private final boolean multipleClassLoaders; 116 117 private final ComponentClassResolver resolver; 118 119 private final PageClassLoaderContextManager pageClassLoaderContextManager; 120 121 private PageClassLoaderContext rootPageClassloaderContext; 122 123 private PlasticProxyFactoryProxy plasticProxyFactoryProxy; 124 125 private ComponentDependencyRegistry componentDependencyRegistry; 126 127 private static final ThreadLocal<String> CURRENT_PAGE = ThreadLocal.withInitial(() -> null); 128 129 /** 130 * Map from class name to Instantiator. 131 */ 132 private final Map<String, Instantiator> classToInstantiator = CollectionFactory.newConcurrentMap(); 133 134 private final Map<String, ComponentModel> classToModel = CollectionFactory.newMap(); 135 136 private final MethodDescription GET_COMPONENT_RESOURCES = PlasticUtils.getMethodDescription( 137 ComponentResourcesAware.class, "getComponentResources"); 138 139 private final ConstructorCallback REGISTER_AS_PAGE_LIFECYCLE_LISTENER = new ConstructorCallback() 140 { 141 public void onConstruct(Object instance, InstanceContext context) 142 { 143 InternalComponentResources resources = context.get(InternalComponentResources.class); 144 145 resources.addPageLifecycleListener((PageLifecycleListener) instance); 146 } 147 }; 148 149 public ComponentInstantiatorSourceImpl(Logger logger, 150 151 LoggerSource loggerSource, 152 153 @Builtin 154 PlasticProxyFactory proxyFactory, 155 156 @Primary 157 ComponentClassTransformWorker2 transformerChain, 158 159 ClasspathURLConverter classpathURLConverter, 160 161 OperationTracker tracker, 162 163 Map<String, ControlledPackageType> configuration, 164 165 @Symbol(TapestryHttpSymbolConstants.PRODUCTION_MODE) 166 boolean productionMode, 167 168 @Symbol(SymbolConstants.MULTIPLE_CLASSLOADERS) 169 boolean multipleClassLoaders, 170 171 ComponentClassResolver resolver, 172 173 InternalComponentInvalidationEventHub invalidationHub, 174 175 PageClassLoaderContextManager pageClassLoaderContextManager, 176 177 ComponentDependencyRegistry componentDependencyRegistry 178 ) 179 { 180 this.parent = proxyFactory.getClassLoader(); 181 this.transformerChain = transformerChain; 182 this.logger = logger; 183 this.loggerSource = loggerSource; 184 this.changeTracker = new URLChangeTracker<ClassName>(classpathURLConverter); 185 this.tracker = tracker; 186 this.invalidationHub = invalidationHub; 187 this.productionMode = productionMode; 188 this.multipleClassLoaders = multipleClassLoaders; 189 this.resolver = resolver; 190 this.pageClassLoaderContextManager = pageClassLoaderContextManager; 191 this.componentDependencyRegistry = componentDependencyRegistry; 192 193 // For now, we just need the keys of the configuration. When there are more types of controlled 194 // packages, we'll need to do more. 195 196 controlledPackageNames.addAll(configuration.keySet()); 197 198 initializeService(); 199 200 pageClassLoaderContextManager.initialize( 201 rootPageClassloaderContext, 202 ComponentInstantiatorSourceImpl.this::createPlasticProxyFactory); 203 204 } 205 206 @PostInjection 207 public void listenForUpdates(UpdateListenerHub hub) 208 { 209 invalidationHub.addInvalidationCallback(this::invalidate); 210 hub.addUpdateListener(this); 211 } 212 213 public synchronized void checkForUpdates() 214 { 215 final Set<ClassName> changedResources = changeTracker.getChangedResourcesInfo(); 216 if (!changedResources.isEmpty()) 217 { 218 219 final List<String> classNames = changedResources.stream().map(ClassName::getClassName).collect(Collectors.toList()); 220 221 if (logger.isInfoEnabled()) 222 { 223 logger.info("Component class(es) changed: {}", String.join(", ", classNames)); 224 } 225 226 if (multipleClassLoaders) 227 { 228 229 final Set<String> classesToInvalidate = new HashSet<>(); 230 231 for (String className : classNames) 232 { 233 final PageClassLoaderContext context = rootPageClassloaderContext.findByClassName(className); 234 if (context != rootPageClassloaderContext && context != null) 235 { 236 classesToInvalidate.addAll(pageClassLoaderContextManager.invalidate(context)); 237 } 238 } 239 240 classNames.clear(); 241 classNames.addAll(classesToInvalidate); 242 243 invalidate(classNames); 244 245 invalidationHub.fireInvalidationEvent(classNames); 246 } 247 else 248 { 249 invalidationHub.classInControlledPackageHasChanged(); 250 } 251 252 } 253 } 254 255 private List<String> invalidate(final List<String> classNames) { 256 257 if (classNames.isEmpty()) 258 { 259 clearCaches(); 260 } 261 else 262 { 263 264 final String currentPage = CURRENT_PAGE.get(); 265 266 final Iterator<Entry<String, Instantiator>> classToInstantiatorIterator = classToInstantiator.entrySet().iterator(); 267 while (classToInstantiatorIterator.hasNext()) 268 { 269 final String className = classToInstantiatorIterator.next().getKey(); 270 if (!className.equals(currentPage) && classNames.contains(className)) 271 { 272 classToInstantiatorIterator.remove(); 273 } 274 } 275 276 final Iterator<Entry<String, ComponentModel>> classToModelIterator = classToModel.entrySet().iterator(); 277 while (classToModelIterator.hasNext()) 278 { 279 final String className = classToModelIterator.next().getKey(); 280 if (!className.equals(currentPage) && classNames.contains(className)) 281 { 282 classToModelIterator.remove(); 283 } 284 } 285 286 } 287 288 return Collections.emptyList(); 289 } 290 291 public void forceComponentInvalidation() 292 { 293 clearCaches(); 294 invalidationHub.classInControlledPackageHasChanged(); 295 } 296 297 private void clearCaches() 298 { 299 classToInstantiator.clear(); 300 pageClassLoaderContextManager.clear(); 301 } 302 303 public void run() 304 { 305 changeTracker.clear(); 306 classToInstantiator.clear(); 307 classToModel.clear(); 308 pageClassLoaderContextManager.clear(); 309 initializeService(); 310 } 311 312 /** 313 * Invoked at object creation, or when there are updates to class files (i.e., invalidation), to create a new set of 314 * Javassist class pools and loaders. 315 * Since TAP5-2742, this method is only called once. 316 */ 317 private void initializeService() 318 { 319 320 pageClassLoaderContextManager.clear(); 321 322 if (rootPageClassloaderContext == null) 323 { 324 logger.info("Initializing page pool. Production mode " + (productionMode ? "enabled" : "disabled") + 325 ". Multiple classloaders " + (!productionMode && multipleClassLoaders ? "enabled" : "disabled") + "."); 326 327 pageClassLoaderContextManager.clear(); 328 329 PlasticProxyFactory proxyFactory = createPlasticProxyFactory(parent); 330 rootPageClassloaderContext = new PageClassLoaderContext( 331 "root", null, Collections.emptySet(), proxyFactory, pageClassLoaderContextManager::get); 332 } 333 else 334 { 335 logger.info("Restarting page pool"); 336 } 337 338 classToInstantiator.clear(); 339 classToModel.clear(); 340 } 341 342 private PlasticProxyFactory createPlasticProxyFactory(final ClassLoader parentClassloader) 343 { 344 PlasticManagerBuilder builder = PlasticManager.withClassLoader(parentClassloader) 345 .delegate(this) 346 .packages(controlledPackageNames); 347 if (!productionMode) 348 { 349 builder.enable(TransformationOption.FIELD_WRITEBEHIND); 350 } 351 PlasticManager plasticManager = builder.create(); 352 plasticManager.addPlasticClassListener(this); 353 PlasticProxyFactory proxyFactory = new PlasticProxyFactoryImpl(plasticManager, logger); 354 return proxyFactory; 355 } 356 357 public Instantiator getInstantiator(final String className) 358 { 359 return classToInstantiator.computeIfAbsent(className, this::createInstantiatorForClass); 360 } 361 362 private static final ThreadLocal<Set<String>> OPEN_INSTANTIATORS = 363 ThreadLocal.withInitial(HashSet::new); 364 365 private Instantiator createInstantiatorForClass(final String className) 366 { 367 return tracker.invoke(String.format("Creating instantiator for component class %s", className), 368 new Invokable<Instantiator>() 369 { 370 public Instantiator invoke() 371 { 372 373 // Force the creation of the class (and the transformation of the class). This will first 374 // trigger transformations of any base classes. 375 376 OPEN_INSTANTIATORS.get().add(className); 377 378 componentDependencyRegistry.disableInvalidations(); 379 PageClassLoaderContext context; 380 try 381 { 382 context = pageClassLoaderContextManager.get(className); 383 } 384 finally 385 { 386 componentDependencyRegistry.enableInvalidations(); 387 } 388 389 // Make sure the dependencies have been processed in case 390 // there was some invalidation going on and they're not there. 391 392 // TODO: maybe we need superclasses here too? 393 final Set<String> dependencies = componentDependencyRegistry.getDependencies(className, DependencyType.USAGE); 394 for (String dependency : dependencies) 395 { 396 if (!OPEN_INSTANTIATORS.get().contains(dependency)) 397 { 398 createInstantiatorForClass(dependency); 399 } 400 } 401 402 ClassInstantiator<Component> plasticInstantiator = context.getPlasticManager().getClassInstantiator(className); 403 final ComponentModel model = classToModel.get(className); 404 405 OPEN_INSTANTIATORS.get().remove(className); 406 407 return new Instantiator() 408 { 409 public Component newInstance(InternalComponentResources resources) 410 { 411 return plasticInstantiator.with(ComponentResources.class, resources) 412 .with(InternalComponentResources.class, resources).newInstance(); 413 } 414 415 public ComponentModel getModel() 416 { 417 return model; 418 } 419 420 @Override 421 public String toString() 422 { 423 return String.format("[Instantiator[%s:%s]", className, context); 424 } 425 }; 426 } 427 }); 428 } 429 430 public boolean exists(String className) 431 { 432 return parent.getResource(PlasticInternalUtils.toClassPath(className)) != null; 433 } 434 435 public PlasticProxyFactory getProxyFactory() 436 { 437 if (plasticProxyFactoryProxy == null) 438 { 439 plasticProxyFactoryProxy = new PlasticProxyFactoryProxy(); 440 } 441 return plasticProxyFactoryProxy; 442 } 443 444 public void transform(final PlasticClass plasticClass) 445 { 446 tracker.run(String.format("Running component class transformations on %s", plasticClass.getClassName()), 447 new Runnable() 448 { 449 public void run() 450 { 451 String className = plasticClass.getClassName(); 452 String parentClassName = plasticClass.getSuperClassName(); 453 454 // The parent model may not exist, if the super class is not in a controlled package. 455 456 ComponentModel parentModel = classToModel.get(parentClassName); 457 458 final boolean isRoot = parentModel == null; 459 460 if (isRoot 461 && !(parentClassName.equals("java.lang.Object") || parentClassName 462 .equals("groovy.lang.GroovyObjectSupport"))) 463 { 464 String suggestedPackageName = buildSuggestedPackageName(className); 465 466 throw new RuntimeException(String.format("Base class %s (super class of %s) is not in a controlled package and is therefore not valid. You should try moving the class to package %s.", parentClassName, className, suggestedPackageName)); 467 } 468 469 // Tapestry 5.2 was more sensitive that the parent class have a public no-args constructor. 470 // Plastic 471 // doesn't care, and we don't have the tools to dig that information out. 472 473 Logger logger = loggerSource.getLogger(className); 474 475 Resource baseResource = new ClasspathResource(parent, PlasticInternalUtils 476 .toClassPath(className)); 477 478 changeTracker.add(baseResource.toURL(), new ClassName(className)); 479 480 if (isRoot) 481 { 482 implementComponentInterface(plasticClass); 483 } 484 485 boolean isPage = resolver.isPage(className); 486 487 boolean superClassImplementsPageLifecycle = plasticClass.isInterfaceImplemented(PageLifecycleListener.class); 488 489 String libraryName = resolver.getLibraryNameForClass(className); 490 491 final MutableComponentModel model = new MutableComponentModelImpl(className, logger, baseResource, 492 parentModel, isPage, libraryName); 493 494 TransformationSupportImpl transformationSupport = new TransformationSupportImpl(plasticClass, isRoot, model); 495 496 transformerChain.transform(plasticClass, transformationSupport, model); 497 498 transformationSupport.commit(); 499 500 if (!superClassImplementsPageLifecycle && plasticClass.isInterfaceImplemented(PageLifecycleListener.class)) 501 { 502 plasticClass.onConstruct(REGISTER_AS_PAGE_LIFECYCLE_LISTENER); 503 } 504 505 classToModel.put(className, model); 506 } 507 }); 508 } 509 510 private void implementComponentInterface(PlasticClass plasticClass) 511 { 512 plasticClass.introduceInterface(Component.class); 513 514 final PlasticField resourcesField = plasticClass.introduceField(InternalComponentResources.class, 515 "internalComponentResources").injectFromInstanceContext(); 516 517 plasticClass.introduceMethod(GET_COMPONENT_RESOURCES, new InstructionBuilderCallback() 518 { 519 public void doBuild(InstructionBuilder builder) 520 { 521 builder.loadThis().getField(resourcesField).returnResult(); 522 } 523 }); 524 } 525 526 public <T> ClassInstantiator<T> configureInstantiator(String className, ClassInstantiator<T> instantiator) 527 { 528 return instantiator; 529 } 530 531 private String buildSuggestedPackageName(String className) 532 { 533 for (String subpackage : InternalConstants.SUBPACKAGES) 534 { 535 String term = "." + subpackage + "."; 536 537 int pos = className.indexOf(term); 538 539 // Keep the leading '.' in the subpackage name and tack on "base". 540 541 if (pos > 0) 542 return className.substring(0, pos + 1) + InternalConstants.BASE_SUBPACKAGE; 543 } 544 545 // Is this even reachable? className should always be in a controlled package and so 546 // some subpackage above should have matched. 547 548 return null; 549 } 550 551 public void classWillLoad(PlasticClassEvent event) 552 { 553 Logger logger = loggerSource.getLogger("tapestry.transformer." + event.getPrimaryClassName()); 554 555 if (logger.isDebugEnabled()) 556 logger.debug(event.getDissasembledBytecode()); 557 } 558 559 private class TransformationSupportImpl implements TransformationSupport 560 { 561 private final PlasticClass plasticClass; 562 563 private final boolean root; 564 565 private final MutableComponentModel model; 566 567 private final List<MethodAdvice> eventHandlerAdvice = CollectionFactory.newList(); 568 569 public TransformationSupportImpl(PlasticClass plasticClass, boolean root, MutableComponentModel model) 570 { 571 this.plasticClass = plasticClass; 572 this.root = root; 573 this.model = model; 574 } 575 576 /** 577 * Commits any stored changes to the PlasticClass; this is used to defer adding advice to the dispatch method. 578 */ 579 public void commit() 580 { 581 if (!eventHandlerAdvice.isEmpty()) 582 { 583 PlasticMethod dispatchMethod = plasticClass.introduceMethod(TransformConstants.DISPATCH_COMPONENT_EVENT_DESCRIPTION); 584 for (MethodAdvice advice : eventHandlerAdvice) 585 { 586 dispatchMethod.addAdvice(advice); 587 } 588 } 589 } 590 591 public Class toClass(String typeName) 592 { 593 try 594 { 595 final PageClassLoaderContext context = pageClassLoaderContextManager.get(typeName); 596 return PlasticInternalUtils.toClass(context.getPlasticManager().getClassLoader(), typeName); 597 } catch (ClassNotFoundException ex) 598 { 599 throw new RuntimeException(String.format( 600 "Unable to convert type '%s' to a Class: %s", typeName, 601 ExceptionUtils.toMessage(ex)), ex); 602 } 603 } 604 605 public boolean isRootTransformation() 606 { 607 return root; 608 } 609 610 public void addEventHandler(final String eventType, final int minContextValues, final String operationDescription, final ComponentEventHandler handler) 611 { 612 assert InternalUtils.isNonBlank(eventType); 613 assert minContextValues >= 0; 614 assert handler != null; 615 616 model.addEventHandler(eventType); 617 618 MethodAdvice advice = new EventMethodAdvice(tracker, eventType, minContextValues, operationDescription, handler); 619 620 // The advice is added at the very end, after the logic provided by the OnEventWorker 621 622 eventHandlerAdvice.add(advice); 623 } 624 } 625 626 private static class EventMethodAdvice implements MethodAdvice 627 { 628 final OperationTracker tracker; 629 final String eventType; 630 final int minContextValues; 631 final String operationDescription; 632 final ComponentEventHandler handler; 633 634 public EventMethodAdvice(OperationTracker tracker, String eventType, int minContextValues, String operationDescription, ComponentEventHandler handler) 635 { 636 this.tracker = tracker; 637 this.eventType = eventType; 638 this.minContextValues = minContextValues; 639 this.operationDescription = operationDescription; 640 this.handler = handler; 641 } 642 643 public void advise(final MethodInvocation invocation) 644 { 645 final ComponentEvent event = (ComponentEvent) invocation.getParameter(0); 646 647 boolean matches = !event.isAborted() && event.matches(eventType, "", minContextValues); 648 649 if (matches) 650 { 651 tracker.run(operationDescription, new Runnable() 652 { 653 public void run() 654 { 655 Component instance = (Component) invocation.getInstance(); 656 657 handler.handleEvent(instance, event); 658 } 659 }); 660 } 661 662 // Order of operations is key here. This logic takes precedence; base class event dispatch and event handler methods 663 // in the class come AFTER. 664 665 invocation.proceed(); 666 667 if (matches) 668 { 669 invocation.setReturnValue(true); 670 } 671 } 672 } 673 674 private static class ClassName implements ClassNameHolder 675 { 676 private String className; 677 678 public ClassName(String className) 679 { 680 super(); 681 this.className = className; 682 } 683 684 @Override 685 public String getClassName() 686 { 687 return className; 688 } 689 690 @Override 691 public int hashCode() { 692 return Objects.hash(className); 693 } 694 695 @Override 696 public boolean equals(Object obj) 697 { 698 if (this == obj) { 699 return true; 700 } 701 if (!(obj instanceof ClassName)) { 702 return false; 703 } 704 ClassName other = (ClassName) obj; 705 return Objects.equals(className, other.className); 706 } 707 708 @Override 709 public String toString() 710 { 711 return className; 712 } 713 714 } 715 716 private class PlasticProxyFactoryProxy implements PlasticProxyFactory 717 { 718 719 @Override 720 public void addPlasticClassListener(PlasticClassListener listener) 721 { 722 throw new UnsupportedOperationException(); 723 } 724 725 @Override 726 public void removePlasticClassListener(PlasticClassListener listener) 727 { 728 throw new UnsupportedOperationException(); 729 } 730 731 @Override 732 public ClassLoader getClassLoader() { 733 return rootPageClassloaderContext.getProxyFactory().getClassLoader(); 734 } 735 736 @Override 737 public <T> ClassInstantiator<T> createProxy(Class<T> interfaceType, PlasticClassTransformer callback) 738 { 739 return getProxyFactory(interfaceType.getName()).createProxy(interfaceType, callback); 740 } 741 742 @Override 743 public <T> ClassInstantiator<T> createProxy(Class<T> interfaceType, 744 Class<? extends T> implementationType, 745 PlasticClassTransformer callback, 746 boolean introduceInterface) 747 { 748 throw new UnsupportedOperationException(); 749 } 750 751 @Override 752 public <T> ClassInstantiator<T> createProxy(Class<T> interfaceType, Class<? extends T> implementationType, PlasticClassTransformer callback) 753 { 754 throw new UnsupportedOperationException(); 755 } 756 757 @Override 758 public <T> PlasticClassTransformation<T> createProxyTransformation(Class<T> interfaceType) 759 { 760 throw new UnsupportedOperationException(); 761 } 762 763 @Override 764 public <T> PlasticClassTransformation<T> createProxyTransformation(Class<T> interfaceType, Class<? extends T> implementationType) 765 { 766 throw new UnsupportedOperationException(); 767 } 768 769 @Override 770 public <T> T createProxy(Class<T> interfaceType, ObjectCreator<T> creator, String description) 771 { 772 throw new UnsupportedOperationException(); 773 } 774 775 @Override 776 public <T> T createProxy(Class<T> interfaceType, Class<? extends T> implementationType, ObjectCreator<T> creator, String description) 777 { 778 throw new UnsupportedOperationException(); 779 } 780 781 @Override 782 public Location getMethodLocation(Method method) { 783 return getProxyFactory(method.getDeclaringClass().getName()).getMethodLocation(method); 784 } 785 786 @Override 787 public Location getConstructorLocation(Constructor constructor) 788 { 789 return getProxyFactory(constructor.getDeclaringClass().getName()).getConstructorLocation(constructor); 790 } 791 792 @Override 793 public void clearCache() { 794 throw new UnsupportedOperationException(); 795 } 796 797 @Override 798 public PlasticManager getPlasticManager() { 799 return rootPageClassloaderContext.getProxyFactory().getPlasticManager(); 800 } 801 802 @Override 803 public PlasticProxyFactory getProxyFactory(String className) 804 { 805 PageClassLoaderContext context = rootPageClassloaderContext.findByClassName(className); 806 if (context == null) 807 { 808 context = pageClassLoaderContextManager.get(className); 809 } 810 return context.getProxyFactory(); 811 } 812 813 } 814 815}