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. Multiple classloaders " + (!productionMode && multipleClassLoaders ? "enabled" : "disabled") + "."); 325 326 pageClassLoaderContextManager.clear(); 327 328 PlasticProxyFactory proxyFactory = createPlasticProxyFactory(parent); 329 rootPageClassloaderContext = new PageClassLoaderContext( 330 "root", null, Collections.emptySet(), proxyFactory, pageClassLoaderContextManager::get); 331 } 332 else 333 { 334 logger.info("Restarting page pool"); 335 } 336 337 classToInstantiator.clear(); 338 classToModel.clear(); 339 } 340 341 private PlasticProxyFactory createPlasticProxyFactory(final ClassLoader parentClassloader) 342 { 343 PlasticManagerBuilder builder = PlasticManager.withClassLoader(parentClassloader) 344 .delegate(this) 345 .packages(controlledPackageNames); 346 if (!productionMode) 347 { 348 builder.enable(TransformationOption.FIELD_WRITEBEHIND); 349 } 350 PlasticManager plasticManager = builder.create(); 351 plasticManager.addPlasticClassListener(this); 352 PlasticProxyFactory proxyFactory = new PlasticProxyFactoryImpl(plasticManager, logger); 353 return proxyFactory; 354 } 355 356 public Instantiator getInstantiator(final String className) 357 { 358 return classToInstantiator.computeIfAbsent(className, this::createInstantiatorForClass); 359 } 360 361 private static final ThreadLocal<Set<String>> OPEN_INSTANTIATORS = 362 ThreadLocal.withInitial(HashSet::new); 363 364 private Instantiator createInstantiatorForClass(final String className) 365 { 366 return tracker.invoke(String.format("Creating instantiator for component class %s", className), 367 new Invokable<Instantiator>() 368 { 369 public Instantiator invoke() 370 { 371 372 // Force the creation of the class (and the transformation of the class). This will first 373 // trigger transformations of any base classes. 374 375 OPEN_INSTANTIATORS.get().add(className); 376 377 componentDependencyRegistry.disableInvalidations(); 378 PageClassLoaderContext context; 379 try 380 { 381 context = pageClassLoaderContextManager.get(className); 382 } 383 finally 384 { 385 componentDependencyRegistry.enableInvalidations(); 386 } 387 388 // Make sure the dependencies have been processed in case 389 // there was some invalidation going on and they're not there. 390 391 // TODO: maybe we need superclasses here too? 392 final Set<String> dependencies = componentDependencyRegistry.getDependencies(className, DependencyType.USAGE); 393 for (String dependency : dependencies) 394 { 395 if (!OPEN_INSTANTIATORS.get().contains(dependency)) 396 { 397 createInstantiatorForClass(dependency); 398 } 399 } 400 401 ClassInstantiator<Component> plasticInstantiator = context.getPlasticManager().getClassInstantiator(className); 402 final ComponentModel model = classToModel.get(className); 403 404 OPEN_INSTANTIATORS.get().remove(className); 405 406 return new Instantiator() 407 { 408 public Component newInstance(InternalComponentResources resources) 409 { 410 return plasticInstantiator.with(ComponentResources.class, resources) 411 .with(InternalComponentResources.class, resources).newInstance(); 412 } 413 414 public ComponentModel getModel() 415 { 416 return model; 417 } 418 419 @Override 420 public String toString() 421 { 422 return String.format("[Instantiator[%s:%s]", className, context); 423 } 424 }; 425 } 426 }); 427 } 428 429 public boolean exists(String className) 430 { 431 return parent.getResource(PlasticInternalUtils.toClassPath(className)) != null; 432 } 433 434 public PlasticProxyFactory getProxyFactory() 435 { 436 if (plasticProxyFactoryProxy == null) 437 { 438 plasticProxyFactoryProxy = new PlasticProxyFactoryProxy(); 439 } 440 return plasticProxyFactoryProxy; 441 } 442 443 public void transform(final PlasticClass plasticClass) 444 { 445 tracker.run(String.format("Running component class transformations on %s", plasticClass.getClassName()), 446 new Runnable() 447 { 448 public void run() 449 { 450 String className = plasticClass.getClassName(); 451 String parentClassName = plasticClass.getSuperClassName(); 452 453 // The parent model may not exist, if the super class is not in a controlled package. 454 455 ComponentModel parentModel = classToModel.get(parentClassName); 456 457 final boolean isRoot = parentModel == null; 458 459 if (isRoot 460 && !(parentClassName.equals("java.lang.Object") || parentClassName 461 .equals("groovy.lang.GroovyObjectSupport"))) 462 { 463 String suggestedPackageName = buildSuggestedPackageName(className); 464 465 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)); 466 } 467 468 // Tapestry 5.2 was more sensitive that the parent class have a public no-args constructor. 469 // Plastic 470 // doesn't care, and we don't have the tools to dig that information out. 471 472 Logger logger = loggerSource.getLogger(className); 473 474 Resource baseResource = new ClasspathResource(parent, PlasticInternalUtils 475 .toClassPath(className)); 476 477 changeTracker.add(baseResource.toURL(), new ClassName(className)); 478 479 if (isRoot) 480 { 481 implementComponentInterface(plasticClass); 482 } 483 484 boolean isPage = resolver.isPage(className); 485 486 boolean superClassImplementsPageLifecycle = plasticClass.isInterfaceImplemented(PageLifecycleListener.class); 487 488 String libraryName = resolver.getLibraryNameForClass(className); 489 490 final MutableComponentModel model = new MutableComponentModelImpl(className, logger, baseResource, 491 parentModel, isPage, libraryName); 492 493 TransformationSupportImpl transformationSupport = new TransformationSupportImpl(plasticClass, isRoot, model); 494 495 transformerChain.transform(plasticClass, transformationSupport, model); 496 497 transformationSupport.commit(); 498 499 if (!superClassImplementsPageLifecycle && plasticClass.isInterfaceImplemented(PageLifecycleListener.class)) 500 { 501 plasticClass.onConstruct(REGISTER_AS_PAGE_LIFECYCLE_LISTENER); 502 } 503 504 classToModel.put(className, model); 505 } 506 }); 507 } 508 509 private void implementComponentInterface(PlasticClass plasticClass) 510 { 511 plasticClass.introduceInterface(Component.class); 512 513 final PlasticField resourcesField = plasticClass.introduceField(InternalComponentResources.class, 514 "internalComponentResources").injectFromInstanceContext(); 515 516 plasticClass.introduceMethod(GET_COMPONENT_RESOURCES, new InstructionBuilderCallback() 517 { 518 public void doBuild(InstructionBuilder builder) 519 { 520 builder.loadThis().getField(resourcesField).returnResult(); 521 } 522 }); 523 } 524 525 public <T> ClassInstantiator<T> configureInstantiator(String className, ClassInstantiator<T> instantiator) 526 { 527 return instantiator; 528 } 529 530 private String buildSuggestedPackageName(String className) 531 { 532 for (String subpackage : InternalConstants.SUBPACKAGES) 533 { 534 String term = "." + subpackage + "."; 535 536 int pos = className.indexOf(term); 537 538 // Keep the leading '.' in the subpackage name and tack on "base". 539 540 if (pos > 0) 541 return className.substring(0, pos + 1) + InternalConstants.BASE_SUBPACKAGE; 542 } 543 544 // Is this even reachable? className should always be in a controlled package and so 545 // some subpackage above should have matched. 546 547 return null; 548 } 549 550 public void classWillLoad(PlasticClassEvent event) 551 { 552 Logger logger = loggerSource.getLogger("tapestry.transformer." + event.getPrimaryClassName()); 553 554 if (logger.isDebugEnabled()) 555 logger.debug(event.getDissasembledBytecode()); 556 } 557 558 private class TransformationSupportImpl implements TransformationSupport 559 { 560 private final PlasticClass plasticClass; 561 562 private final boolean root; 563 564 private final MutableComponentModel model; 565 566 private final List<MethodAdvice> eventHandlerAdvice = CollectionFactory.newList(); 567 568 public TransformationSupportImpl(PlasticClass plasticClass, boolean root, MutableComponentModel model) 569 { 570 this.plasticClass = plasticClass; 571 this.root = root; 572 this.model = model; 573 } 574 575 /** 576 * Commits any stored changes to the PlasticClass; this is used to defer adding advice to the dispatch method. 577 */ 578 public void commit() 579 { 580 if (!eventHandlerAdvice.isEmpty()) 581 { 582 PlasticMethod dispatchMethod = plasticClass.introduceMethod(TransformConstants.DISPATCH_COMPONENT_EVENT_DESCRIPTION); 583 for (MethodAdvice advice : eventHandlerAdvice) 584 { 585 dispatchMethod.addAdvice(advice); 586 } 587 } 588 } 589 590 public Class toClass(String typeName) 591 { 592 try 593 { 594 final PageClassLoaderContext context = pageClassLoaderContextManager.get(typeName); 595 return PlasticInternalUtils.toClass(context.getPlasticManager().getClassLoader(), typeName); 596 } catch (ClassNotFoundException ex) 597 { 598 throw new RuntimeException(String.format( 599 "Unable to convert type '%s' to a Class: %s", typeName, 600 ExceptionUtils.toMessage(ex)), ex); 601 } 602 } 603 604 public boolean isRootTransformation() 605 { 606 return root; 607 } 608 609 public void addEventHandler(final String eventType, final int minContextValues, final String operationDescription, final ComponentEventHandler handler) 610 { 611 assert InternalUtils.isNonBlank(eventType); 612 assert minContextValues >= 0; 613 assert handler != null; 614 615 model.addEventHandler(eventType); 616 617 MethodAdvice advice = new EventMethodAdvice(tracker, eventType, minContextValues, operationDescription, handler); 618 619 // The advice is added at the very end, after the logic provided by the OnEventWorker 620 621 eventHandlerAdvice.add(advice); 622 } 623 } 624 625 private static class EventMethodAdvice implements MethodAdvice 626 { 627 final OperationTracker tracker; 628 final String eventType; 629 final int minContextValues; 630 final String operationDescription; 631 final ComponentEventHandler handler; 632 633 public EventMethodAdvice(OperationTracker tracker, String eventType, int minContextValues, String operationDescription, ComponentEventHandler handler) 634 { 635 this.tracker = tracker; 636 this.eventType = eventType; 637 this.minContextValues = minContextValues; 638 this.operationDescription = operationDescription; 639 this.handler = handler; 640 } 641 642 public void advise(final MethodInvocation invocation) 643 { 644 final ComponentEvent event = (ComponentEvent) invocation.getParameter(0); 645 646 boolean matches = !event.isAborted() && event.matches(eventType, "", minContextValues); 647 648 if (matches) 649 { 650 tracker.run(operationDescription, new Runnable() 651 { 652 public void run() 653 { 654 Component instance = (Component) invocation.getInstance(); 655 656 handler.handleEvent(instance, event); 657 } 658 }); 659 } 660 661 // Order of operations is key here. This logic takes precedence; base class event dispatch and event handler methods 662 // in the class come AFTER. 663 664 invocation.proceed(); 665 666 if (matches) 667 { 668 invocation.setReturnValue(true); 669 } 670 } 671 } 672 673 private static class ClassName implements ClassNameHolder 674 { 675 private String className; 676 677 public ClassName(String className) 678 { 679 super(); 680 this.className = className; 681 } 682 683 @Override 684 public String getClassName() 685 { 686 return className; 687 } 688 689 @Override 690 public int hashCode() { 691 return Objects.hash(className); 692 } 693 694 @Override 695 public boolean equals(Object obj) 696 { 697 if (this == obj) { 698 return true; 699 } 700 if (!(obj instanceof ClassName)) { 701 return false; 702 } 703 ClassName other = (ClassName) obj; 704 return Objects.equals(className, other.className); 705 } 706 707 @Override 708 public String toString() 709 { 710 return className; 711 } 712 713 } 714 715 private class PlasticProxyFactoryProxy implements PlasticProxyFactory 716 { 717 718 @Override 719 public void addPlasticClassListener(PlasticClassListener listener) 720 { 721 throw new UnsupportedOperationException(); 722 } 723 724 @Override 725 public void removePlasticClassListener(PlasticClassListener listener) 726 { 727 throw new UnsupportedOperationException(); 728 } 729 730 @Override 731 public ClassLoader getClassLoader() { 732 return rootPageClassloaderContext.getProxyFactory().getClassLoader(); 733 } 734 735 @Override 736 public <T> ClassInstantiator<T> createProxy(Class<T> interfaceType, PlasticClassTransformer callback) 737 { 738 return getProxyFactory(interfaceType.getName()).createProxy(interfaceType, callback); 739 } 740 741 @Override 742 public <T> ClassInstantiator<T> createProxy(Class<T> interfaceType, 743 Class<? extends T> implementationType, 744 PlasticClassTransformer callback, 745 boolean introduceInterface) 746 { 747 throw new UnsupportedOperationException(); 748 } 749 750 @Override 751 public <T> ClassInstantiator<T> createProxy(Class<T> interfaceType, Class<? extends T> implementationType, PlasticClassTransformer callback) 752 { 753 throw new UnsupportedOperationException(); 754 } 755 756 @Override 757 public <T> PlasticClassTransformation<T> createProxyTransformation(Class<T> interfaceType) 758 { 759 throw new UnsupportedOperationException(); 760 } 761 762 @Override 763 public <T> PlasticClassTransformation<T> createProxyTransformation(Class<T> interfaceType, Class<? extends T> implementationType) 764 { 765 throw new UnsupportedOperationException(); 766 } 767 768 @Override 769 public <T> T createProxy(Class<T> interfaceType, ObjectCreator<T> creator, String description) 770 { 771 throw new UnsupportedOperationException(); 772 } 773 774 @Override 775 public <T> T createProxy(Class<T> interfaceType, Class<? extends T> implementationType, ObjectCreator<T> creator, String description) 776 { 777 throw new UnsupportedOperationException(); 778 } 779 780 @Override 781 public Location getMethodLocation(Method method) { 782 return getProxyFactory(method.getDeclaringClass().getName()).getMethodLocation(method); 783 } 784 785 @Override 786 public Location getConstructorLocation(Constructor constructor) 787 { 788 return getProxyFactory(constructor.getDeclaringClass().getName()).getConstructorLocation(constructor); 789 } 790 791 @Override 792 public void clearCache() { 793 throw new UnsupportedOperationException(); 794 } 795 796 @Override 797 public PlasticManager getPlasticManager() { 798 return rootPageClassloaderContext.getProxyFactory().getPlasticManager(); 799 } 800 801 @Override 802 public PlasticProxyFactory getProxyFactory(String className) 803 { 804 PageClassLoaderContext context = rootPageClassloaderContext.findByClassName(className); 805 if (context == null) 806 { 807 context = pageClassLoaderContextManager.get(className); 808 } 809 return context.getProxyFactory(); 810 } 811 812 } 813 814}