Author: buildbot
Date: Sat Jun 17 00:11:48 2023
New Revision: 1083431

Log:
Production update by buildbot for tapestry

Added:
    websites/production/tapestry/content/class-reloading.data/
    
websites/production/tapestry/content/class-reloading.data/image-2023-6-16_19-53-38.png
   (with props)
Modified:
    websites/production/tapestry/content/cache/main.pageCache
    websites/production/tapestry/content/class-reloading.html

Modified: websites/production/tapestry/content/cache/main.pageCache
==============================================================================
Binary files - no diff available.

Added: 
websites/production/tapestry/content/class-reloading.data/image-2023-6-16_19-53-38.png
==============================================================================
Binary file - no diff available.

Propchange: 
websites/production/tapestry/content/class-reloading.data/image-2023-6-16_19-53-38.png
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Modified: websites/production/tapestry/content/class-reloading.html
==============================================================================
--- websites/production/tapestry/content/class-reloading.html (original)
+++ websites/production/tapestry/content/class-reloading.html Sat Jun 17 
00:11:48 2023
@@ -177,18 +177,20 @@
 </div>
 
 
-<p>One of the best features of Tapestry is automatic reloading of changed 
classes and templates. <em>Page and component</em> classes will automatically 
reload when changed. Likewise, changes to component templates and other related 
resources will also be picked up immediately. In addition, starting in version 
5.2, your service classes will also be reloaded automatically after changes (if 
you're using <a href="ioc.html">Tapestry IoC</a>).</p><h2 
id="ClassReloading-Contents">Contents</h2><p><style 
type="text/css">/*<![CDATA[*/
-div.rbtoc1669470792007 {padding: 0px;}
-div.rbtoc1669470792007 ul {list-style: disc;margin-left: 0px;}
-div.rbtoc1669470792007 li {margin-left: 0px;padding-left: 0px;}
+<p>One of the best features of Tapestry is automatic reloading of changed 
classes and templates. <em>Page and component</em> classes will automatically 
reload when changed. Likewise, changes to component templates and other related 
resources will also be picked up immediately. In addition, starting in version 
5.2, your service classes will also be reloaded automatically after changes (if 
you're using <a href="ioc.html">Tapestry IoC</a>). Starting in version 5.8.3, 
you enable multiple classloader mode, which allows smarter page class 
invalidation.</p><div class="confluence-information-macro 
confluence-information-macro-information"><p class="title">Not necessarily 
throwing away all cached page instances</p><span class="aui-icon aui-icon-small 
aui-iconfont-info confluence-information-macro-icon"></span><div 
class="confluence-information-macro-body"><p>Since Tapestry 5.8.3, Tapestry can 
be run in multiple classloaders mode. When it's on, only the affected cached 
page instances are disc
 arded and rebuilt instead of all of them.&#160;</p></div></div><h2 
id="ClassReloading-Contents">Contents</h2><p><style 
type="text/css">/*<![CDATA[*/
+div.rbtoc1686960702841 {padding: 0px;}
+div.rbtoc1686960702841 ul {margin-left: 0px;}
+div.rbtoc1686960702841 li {margin-left: 0px;padding-left: 0px;}
 
-/*]]>*/</style></p><div class="toc-macro rbtoc1669470792007">
+/*]]>*/</style></p><div class="toc-macro rbtoc1686960702841">
 <ul class="toc-indentation"><li><a 
href="#ClassReloading-TemplateReloading">Template Reloading</a></li><li><a 
href="#ClassReloading-ClassReloading">Class Reloading</a></li><li><a 
href="#ClassReloading-PackagesScanned">Packages Scanned</a></li><li><a 
href="#ClassReloading-FileSystemOnly">File System Only</a></li><li><a 
href="#ClassReloading-ClassLoaderIssues">Class Loader Issues</a></li><li><a 
href="#ClassReloading-ClassCastExceptions">ClassCastExceptions</a></li><li><a 
href="#ClassReloading-HandlingReloadsinyourCode">Handling Reloads in your 
Code</a></li><li><a href="#ClassReloading-CheckingForUpdates">Checking For 
Updates</a></li><li><a 
href="#ClassReloading-TroubleshootingLiveClassReloading">Troubleshooting Live 
Class Reloading</a>
 <ul class="toc-indentation"><li><a href="#ClassReloading-QuickChecklist">Quick 
Checklist</a></li><li><a 
href="#ClassReloading-IfLiveClassReloadingdoesn'twork">If Live Class Reloading 
doesn't work</a>
 <ul class="toc-indentation"><li><a 
href="#ClassReloading-ProductionMode">Production Mode</a></li><li><a 
href="#ClassReloading-BuildPathIssues">Build Path Issues</a></li><li><a 
href="#ClassReloading-BuildingAutomatically">Building 
Automatically</a></li><li><a 
href="#ClassReloading-TurnoffJVMhotcodeswapping&amp;automaticrestarts">Turn off 
JVM hot code swapping &amp; automatic restarts</a></li></ul>
 </li><li><a href="#ClassReloading-TomcatSpecifics">Tomcat 
Specifics</a></li><li><a 
href="#ClassReloading-IfLiveClassReloadingworksbutisslow">If Live Class 
Reloading works but is slow</a></li></ul>
+</li><li><a 
href="#ClassReloading-[5.8.3+]MultipleClassloaderMode/SmarterPageClassInvalidation">[5.8.3+]
 Multiple Classloader Mode/Smarter Page Class Invalidation</a>
+<ul class="toc-indentation"><li><a href="#ClassReloading-HowItWorks">How It 
Works</a></li><li><a 
href="#ClassReloading-Loading,StoringandPreloadingDependencyInformation">Loading,
 Storing and Preloading Dependency Information</a></li><li><a 
href="#ClassReloading-Caveats">Caveats</a></li></ul>
 </li></ul>
-</div><h2 id="ClassReloading-TemplateReloading">Template Reloading</h2><p>When 
a template changes, all page instances (as well as the hierarchy of components 
below them) are discarded and reconstructed with the new template. However, 
classes are not reloaded in this case.</p><h2 
id="ClassReloading-ClassReloading">Class Reloading</h2><p>On a change to 
<em>any</em> loaded class from inside a controlled package (or any sub-package 
of a controlled package), Tapestry will discard all page instances, and discard 
the class loader.</p><p><a 
href="https://cwiki.apache.org/confluence/pages/viewpage.action?pageId=84804223";>Persistent
 field data</a> on the pages will usually not be affected (as it is stored 
separately, usually in the session). This allows you to make fairly significant 
changes to a component class even while the application continues to 
run.</p><h2 id="ClassReloading-PackagesScanned">Packages Scanned</h2><p>Only 
certain classes are subject to reload. Reloading is based on packa
 ge name; the packages that are reloaded are derived from the <a 
href="configuration.html">application configuration</a>.</p><p>If your root 
package is <code>org.example.myapp</code>, then only classes in the following 
packages (and their sub-packages) will be scanned for automatic 
reloads:</p><ul><li>org.example.myapp.pages</li><li>org.example.myapp.components</li><li>org.example.myapp.mixins</li><li>org.example.myapp.base</li><li>org.example.myapp.services
 (Tapestry 5.2 and later, with restrictions)</li></ul><p>Starting in Tapestry 
5.2, live class reloading includes service implementation classes. There are 
some limitations to this. See&#160;<a 
href="service-implementation-reloading.html">Service Implementation 
Reloading</a> for more details.</p><h2 id="ClassReloading-FileSystemOnly">File 
System Only</h2><p>Reloading of classes and other files applies only to files 
that are actually on the file system, and not files obtained from JAR files. 
This is perfect during development, where
  the files in question are in your local workspace. In a deployed application, 
you are somewhat subject to the implementation of your servlet container or 
application server.</p><h2 id="ClassReloading-ClassLoaderIssues">Class Loader 
Issues</h2><p>Tapestry uses an extra class loader to load page and component 
classes.</p><p>When a change to an underlying Java class file is detected, 
Tapestry discards the class loader.</p><p>You should be careful to not hold any 
references to Tapestry pages or components in other code, such as Tapestry IoC 
services. Holding such references can cause significant memory leaks, as they 
can prevent the class loader from being reclaimed by the garbage 
collector.</p><h2 
id="ClassReloading-ClassCastExceptions">ClassCastExceptions</h2><p>Tapestry's 
class loader architecture can sometimes cause a minor problem when you make use 
of a services layer without interfaces, or if that you pass component instances 
to objects that are not themselves components.</p><p>I
 n such cases you may see ClassCastException errors. This is because the same 
class name, say org.example.myapp.pages.Start, exists as two different class 
instances. One class instance is loaded by the web application's default class 
loader. A second class instance has been loaded <em>and transformed</em> by 
Tapestry's reloading class loader.</p><p>Ordinary classes, such as Tapestry IoC 
Services, will be loaded by the default class loader and expect instances to be 
loaded by the same class loader (or a parent).</p><p>The solution to this 
problem is to introduce an interface; the component class should implement the 
interface, and the service should expect an instance of the interface, rather 
than a specific type.</p><p>It is important that the interface be loaded by the 
default class loader. It should not be in the pages or components package, but 
instead be in another package, such as services.</p><h2 
id="ClassReloading-HandlingReloadsinyourCode">Handling Reloads in your 
Code</h2><p
 >On occasion, you may need to know when invalidations occur, to clear your own 
 >cache. For example, if you have a binding that creates new classes, the way 
 ><a class="external-link" 
 >href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/PropertyConduitSource.html";>PropertyConduitSource</a>
 > does, you need to discard any cached classes or instances when a change is 
 >detected in component classes.</p><p>You do this by registering a listener 
 >with the correct <a class="external-link" 
 >href="http://tapestry.apache.org/current/apidocs/org/apache/tpaestry5/services/InvalidationEventHub.html";>InvalidationEventHub</a>
 > service.</p><p>For example, your service may be in the business of creating 
 >new classes based on component classes, and keep a cache of those 
 >classes:</p><div class="code panel pdl" style="border-width: 1px;"><div 
 >class="codeContent panelContent pdl">
+</div><h2 id="ClassReloading-TemplateReloading">Template Reloading</h2><p>When 
a template changes, all page instances (as well as the hierarchy of components 
below them) are discarded and reconstructed with the new template. However, 
classes are not reloaded in this case.</p><h2 
id="ClassReloading-ClassReloading">Class Reloading</h2><p>On a change to 
<em>any</em> loaded class from inside a controlled package (or any sub-package 
of a controlled package), Tapestry will discard all page instances, and discard 
the class loader.</p><p><a href="class-reloading.html">Persistent field 
data</a> on the pages will usually not be affected (as it is stored separately, 
usually in the session). This allows you to make fairly significant changes to 
a component class even while the application continues to run.</p><h2 
id="ClassReloading-PackagesScanned">Packages Scanned</h2><p>Only certain 
classes are subject to reload. Reloading is based on package name; the packages 
that are reloaded are derived f
 rom the <a href="configuration.html">application configuration</a>.</p><p>If 
your root package is <code>org.example.myapp</code>, then only classes in the 
following packages (and their sub-packages) will be scanned for automatic 
reloads:</p><ul><li>org.example.myapp.pages</li><li>org.example.myapp.components</li><li>org.example.myapp.mixins</li><li>org.example.myapp.base</li><li>org.example.myapp.services
 (Tapestry 5.2 and later, with restrictions)</li></ul><p>Starting in Tapestry 
5.2, live class reloading includes service implementation classes. There are 
some limitations to this. See&#160;<a 
href="service-implementation-reloading.html">Service Implementation 
Reloading</a> for more details.</p><h2 id="ClassReloading-FileSystemOnly">File 
System Only</h2><p>Reloading of classes and other files applies only to files 
that are actually on the file system, and not files obtained from JAR files. 
This is perfect during development, where the files in question are in your 
local workspace. I
 n a deployed application, you are somewhat subject to the implementation of 
your servlet container or application server.</p><h2 
id="ClassReloading-ClassLoaderIssues">Class Loader Issues</h2><p>Tapestry uses 
an extra class loader to load page and component classes.</p><p>When a change 
to an underlying Java class file is detected, Tapestry discards the class 
loader.</p><p>You should be careful to not hold any references to Tapestry 
pages or components in other code, such as Tapestry IoC services. Holding such 
references can cause significant memory leaks, as they can prevent the class 
loader from being reclaimed by the garbage collector.</p><h2 
id="ClassReloading-ClassCastExceptions">ClassCastExceptions</h2><p>Tapestry's 
class loader architecture can sometimes cause a minor problem when you make use 
of a services layer without interfaces, or if that you pass component instances 
to objects that are not themselves components.</p><p>In such cases you may see 
ClassCastException errors. T
 his is because the same class name, say org.example.myapp.pages.Start, exists 
as two different class instances. One class instance is loaded by the web 
application's default class loader. A second class instance has been loaded 
<em>and transformed</em> by Tapestry's reloading class loader.</p><p>Ordinary 
classes, such as Tapestry IoC Services, will be loaded by the default class 
loader and expect instances to be loaded by the same class loader (or a 
parent).</p><p>The solution to this problem is to introduce an interface; the 
component class should implement the interface, and the service should expect 
an instance of the interface, rather than a specific type.</p><p>It is 
important that the interface be loaded by the default class loader. It should 
not be in the pages or components package, but instead be in another package, 
such as services.</p><h2 id="ClassReloading-HandlingReloadsinyourCode">Handling 
Reloads in your Code</h2><p>On occasion, you may need to know when invalidations
  occur, to clear your own cache. For example, if you have a binding that 
creates new classes, the way <a class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/PropertyConduitSource.html";>PropertyConduitSource</a>
 does, you need to discard any cached classes or instances when a change is 
detected in component classes.</p><p>You do this by registering a listener with 
the correct <a class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tpaestry5/services/InvalidationEventHub.html";>InvalidationEventHub</a>
 service.</p><p>For example, your service may be in the business of creating 
new classes based on component classes, and keep a cache of those 
classes:</p><div class="code panel pdl" style="border-width: 1px;"><div 
class="codeContent panelContent pdl">
 <pre><code class="language-java">public class MyServiceImpl implements 
MyService, InvalidationEventListener
 {
   public final Map&lt;String,Class&gt; cache = new 
ConcurrentHashMap&lt;String,Class&gt;();
@@ -209,7 +211,7 @@ div.rbtoc1669470792007 li {margin-left:
 </div></div><p>This is the intent of service builder methods; to do more than 
just injecting dependencies.</p><h2 
id="ClassReloading-CheckingForUpdates">Checking For Updates</h2><p>The built in 
InvalidationEventHub services provide notifications of changes to component 
classes, to component templates, and to component message catalogs. If you wish 
to check some other resources (for example, files in a directory of the file 
system or rows in a database table), you should register as an <a 
class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/UpdateListener.html";>UpdateListener</a>
 with the <a class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/UpdateListenerHub.html";>UpdateListenerHub</a>
 service.</p><p>Periodically (the frequency is configurable), UpdateListeners 
are notified that they should check for updates. Typically, UpdateListeners are 
also InvalidationEventHubs (or provide Invalida
 tionEventHubs), so that other interested parties can be alerted when 
underlying data changes.</p><h2 
id="ClassReloading-TroubleshootingLiveClassReloading">Troubleshooting Live 
Class Reloading</h2><h3 id="ClassReloading-QuickChecklist">Quick 
Checklist</h3><ul><li>"Production Mode" must be false (in Tapestry 5.3 and 
later)</li><li>The class must be one that Tapestry instantiates (a page, 
component, or mixin class, or a Tapestry IOC service implementation that 
implements an interface)</li><li>Turn on "Build Automatically" in your IDE, or 
remember to build manually.</li><li>Turn <em>off</em> JVM hot code swapping, if 
your servlet container supports it.</li><li>Eclipse: Uncheck the "derived" 
checkbox for the Target dir (in the Project Explorer view, right click on 
"target", select properties, uncheck "derived" on the Resource 
tab)</li></ul><p>Some of these issues are described in more detail 
below.</p><h3 id="ClassReloading-IfLiveClassReloadingdoesn'twork">If Live Class 
Reloading doesn't
  work</h3><h4 id="ClassReloading-ProductionMode">Production 
Mode</h4><p>Starting with Tapestry 5.3, Live Class Reloading only works when 
not in "Production Mode". Check your application module (usually 
AppModule.java) to be sure you have:</p><div class="code panel pdl" 
style="border-width: 1px;"><div class="codeContent panelContent pdl">
 <pre><code 
class="language-java">configuration.add(SymbolConstants.PRODUCTION_MODE, 
"false");
 </code></pre>
-</div></div><p>and that this isn't being overridden to "true" on your 
application's startup command line.</p><h4 
id="ClassReloading-BuildPathIssues">Build Path Issues</h4><p>Live Class 
Reloading can fail if your build path isn't set correctly, and the exact 
configuration may differ between Maven plugin versions and Eclipse versions. 
The build process must be set to create classes in a folder which is in the 
servlet container's classpath.</p><p>Live Class Reloading won't work correctly 
with vanilla Tomcat without some tweaks (see below).</p><p>Non-Tapestry filters 
can interfere with LCR. Try disabling other filters in your web.xml file to see 
if that helps.</p><h4 id="ClassReloading-BuildingAutomatically">Building 
Automatically</h4><p>Although LCR allows you to see changes without restarting 
your app, you still need to "build" your project (to compile the Java source 
into byte code). Your IDE can be set to do this automatically every time you 
save a file. (In Eclipse, this is done us
 ing <code>Project &gt; Build Automatically</code>.) Alternatively, you can 
manually trigger a build after you save a file. (In Eclipse, this is done using 
<code>Project &gt; Build</code>, or by pressing <code>Control-B</code>.)</p><h4 
id="ClassReloading-TurnoffJVMhotcodeswapping&amp;automaticrestarts">Turn off 
JVM hot code swapping &amp; automatic restarts</h4><p>Many servlet containers, 
including Tomcat and Jetty, support various forms of hot code swapping and/or 
automatic restarts when file changes are detected. These are generally 
<strong>much slower</strong> than LCR and usually should be turned off with 
Tapestry applications. If you're using RunJettyRun plugin for Eclipse, for 
example, edit your Run Configuration, and on the Jetty tab, click Show Advanced 
Options and uncheck the Enable Scanner checkbox.</p><h3 
id="ClassReloading-TomcatSpecifics">Tomcat Specifics</h3><p>See <a 
class="external-link" 
href="http://www.tynamo.org/Developing+with+Tomcat+and+Eclipse/"; 
rel="nofollow">t
 hese Tomcat-specific hints</a></p><h3 
id="ClassReloading-IfLiveClassReloadingworksbutisslow">If Live Class Reloading 
works but is slow</h3><p>If LCR works for you but is slow (more than a second 
or two), consider the following.</p><ul><li>Be sure your project source files 
(your workspace in Eclipse, for example), are on a local drive, NOT a network 
location. Network drives are always slower, and the file system scanning needed 
for LCR can add a noticable lag if I/O is slow. If you use Maven, be sure to 
put your local repository (e.g. ~/.m2/repository) on a local drive for similar 
reasons.</li><li><p>Java 7 and below: Since LCR adds classes to your PermGen 
space, you may be running low on PermGen memory (and may eventually get a 
"java.lang.OutOfMemoryError: PermGen space" error). Try increasing PermGen size 
with a JVM argument of something like&#160;-XX:MaxPermSize=400m. (PermGen 
settings are not relevant for Java 8 and 
above.)</p></li></ul><p></p><p></p></div>
+</div></div><p>and that this isn't being overridden to "true" on your 
application's startup command line.</p><h4 
id="ClassReloading-BuildPathIssues">Build Path Issues</h4><p>Live Class 
Reloading can fail if your build path isn't set correctly, and the exact 
configuration may differ between Maven plugin versions and Eclipse versions. 
The build process must be set to create classes in a folder which is in the 
servlet container's classpath.</p><p>Live Class Reloading won't work correctly 
with vanilla Tomcat without some tweaks (see below).</p><p>Non-Tapestry filters 
can interfere with LCR. Try disabling other filters in your web.xml file to see 
if that helps.</p><h4 id="ClassReloading-BuildingAutomatically">Building 
Automatically</h4><p>Although LCR allows you to see changes without restarting 
your app, you still need to "build" your project (to compile the Java source 
into byte code). Your IDE can be set to do this automatically every time you 
save a file. (In Eclipse, this is done us
 ing <code>Project &gt; Build Automatically</code>.) Alternatively, you can 
manually trigger a build after you save a file. (In Eclipse, this is done using 
<code>Project &gt; Build</code>, or by pressing <code>Control-B</code>.)</p><h4 
id="ClassReloading-TurnoffJVMhotcodeswapping&amp;automaticrestarts">Turn off 
JVM hot code swapping &amp; automatic restarts</h4><p>Many servlet containers, 
including Tomcat and Jetty, support various forms of hot code swapping and/or 
automatic restarts when file changes are detected. These are generally 
<strong>much slower</strong> than LCR and usually should be turned off with 
Tapestry applications. If you're using RunJettyRun plugin for Eclipse, for 
example, edit your Run Configuration, and on the Jetty tab, click Show Advanced 
Options and uncheck the Enable Scanner checkbox.</p><h3 
id="ClassReloading-TomcatSpecifics">Tomcat Specifics</h3><p>See <a 
class="external-link" 
href="http://www.tynamo.org/Developing+with+Tomcat+and+Eclipse/"; 
rel="nofollow">t
 hese Tomcat-specific hints</a></p><h3 
id="ClassReloading-IfLiveClassReloadingworksbutisslow">If Live Class Reloading 
works but is slow</h3><p>If LCR works for you but is slow (more than a second 
or two), consider the following.</p><ul><li>Be sure your project source files 
(your workspace in Eclipse, for example), are on a local drive, NOT a network 
location. Network drives are always slower, and the file system scanning needed 
for LCR can add a noticable lag if I/O is slow. If you use Maven, be sure to 
put your local repository (e.g. ~/.m2/repository) on a local drive for similar 
reasons.</li><li><p>Java 7 and below: Since LCR adds classes to your PermGen 
space, you may be running low on PermGen memory (and may eventually get a 
"java.lang.OutOfMemoryError: PermGen space" error). Try increasing PermGen size 
with a JVM argument of something like&#160;-XX:MaxPermSize=400m. (PermGen 
settings are not relevant for Java 8 and above.)</p></li></ul><h2 
id="ClassReloading-[5.8.3+]MultipleClas
 sloaderMode/SmarterPageClassInvalidation">[5.8.3+] Multiple Classloader 
Mode/Smarter Page Class Invalidation</h2><p>Since Tapestry 5.8.3, you can run 
Tapestry in multiple classloader mode, which implements smarter page class 
invalidation in live class reloading. In addition, other caches are also 
invalidated in smarter way when something changes, avoiding throwing away 
everything. Multiple classloader mode isn't available when production mode is 
on.</p><p>To enable multiple classloader mode, you need to 
<code>tapestry.multiple-classloaders</code> symbol to <code>true</code> and run 
the webapp with production mode disabled.</p><p>When multiple classloaders are 
enabled, when a class in a controlled component, template, message properties 
file or asset is changed, Tapestry tries to invalidate as few cached objects as 
possible. This include page instances, processed templates, asset information, 
property bindings, etc. This is possible by 2 new internal 
features:</p><ol><li>A component 
 dependency registry, which gathers and stores information about how component, 
page, mixin and base classes depend on each other. There are 3 kinds of 
dependencies: usage (i.e. a component or mixin used in a class), superclass 
(i.e. one class extending the other) and @InjectPage (i.e. one class injecting 
a page class using @InjectPage.</li><li>The usage of multiple classloader 
instances, organized in a tree, instead of a single one. For example: if a 
component A is used in pages B and C, when B has its class changed, there's no 
need to invalidate a cached instance of C since Tapestry knows there's no 
dependency of B and C. On the other hand, if A is changed, both B and C 
instances need to be invalidated.</li></ol><p>You can find a graph of all known 
dependencies at a time by going to the /t5dashboard/pagedependencygraph URL of 
your webapp. You can view the dependencies for one specific page by going to 
/t5dashboard/ and clicking the page's Structure Info link. Here's one partial 
exa
 mple:</p><p><span class="confluence-embedded-file-wrapper 
confluence-embedded-manual-size"><img class="confluence-embedded-image" 
draggable="false" height="250" 
src="class-reloading.data/image-2023-6-16_19-53-38.png"></span></p><h3 
id="ClassReloading-HowItWorks">How It Works</h3><p>First of all, when 
production mode is off and multiple classloaders mode is also off, Tapestry 
reacts to file (including classes in controlled packages, templates, message 
properties files and assets) changes in the same way as before and described 
above in this page: all cached information or objects about classes, templates, 
message properties files, assets, property bindings, etc is invalidated (i.e. 
thrown away). The internal services that track changes to these files notify 
all their listeners that they should invalidate their caches 
completely.</p><p>When multiple classloaders mode is on, these internal 
services notify their listeners what changed, so they can invalidate just the 
objects or informat
 ion that is actually affected by the changes. Sometimes this listeners notify 
the services that more stuff needs to be invalidated, For example, if one asset 
is changed and it's associated with a class, the asset service notifies the 
listeners that that class needs to be invalidated. For example, the component 
dependency registry, when notified that a given class was invalidated, besides 
invalidating information about that class, it informs the service that it also 
needs to invalidates the classes that depend on the changed one. This process 
repeats until there's no other class to be invalidated.</p><p>Additional 
logging was added so all files found as changed result in log entries. Same for 
the invalidation chain described in the paragraph above.</p><p>Now that it 
knows the class dependency graph, Tapestry needs to map that into a classloader 
tree, since each classloader instance can only have one parent. Internally, the 
framework has one class, PageClassLoaderContext (PCLC or cont
 ext, for short), that stores all information about one classloader in the 
tree: the classloader itself, a name, the set of names of the classes beloging 
to it, the parent PCLC and children PCLCs. When a class is invalidated, the 
classes in the context are invalidated, then the context itself is invalidated, 
including its classloader, then the child contexts are recursively invalidated 
too.</p><p>There are 2 special PCLC contexts: the root one, which is never 
invalidated, and the unknown one, where classes without dependency information 
go initially.</p><p>The PCLC tree is created class by class, starting from 
pages and then on its dependencies on them in a recursive manner. For each 
class, if there's no PCLC already containing it, Tapestry checks its dependency 
list.&#160;</p><h3 
id="ClassReloading-Loading,StoringandPreloadingDependencyInformation">Loading, 
Storing and Preloading Dependency Information</h3><p>When a page instance is 
finished building, it's processed by the component
  dependency registry, which gathers the dependencies this page has, then the 
dependencies of its dependencies recursively. The registry doesn't process 
classes it already has information.</p><p>When starting up, Tapestry checks 
whether a file named <code>tapestryComponentDependencies.json</code> exists in 
the folder where the webapp is running. If it does, component dependency is 
loaded from it.</p><p>The T5Dashboard page has 2 new buttons related to 
dependencies, <code>Store dependency information</code>, writes all the 
dependency information as known at that moment.</p><p><code>Preload dependency 
information and page classloader contexts</code> goes through all known pages, 
gathers its dependencies, also doing the same for all the components used 
directly and indirectly by them, and the preloads page the page classloader 
contexts, thus avoiding context invalidations when page instances are created. 
Notice this process won't work if any of the pages or their templates are 
invalid f
 or any reason.</p><h3 
id="ClassReloading-Caveats">Caveats</h3><p>Unfortunately, it wasn't possible to 
make the multiple classloader mode to work with all situations and code. Some 
known issues:</p><ol><li>On Java 9 and later, classes belonging to one 
classloader cannot call package-private methods of other classes even when both 
are in the same package. The solution is to change the method visibility to 
public.</li><li>If you don't have component dependency information already 
loaded for a given class, problems, usually in the form of a ClassCastException 
claiming an object of a given type cannot be assigned to a variable of the same 
type. The best way to deal with this is to use the T5Dashboard to write the 
component dependency information to a file and restart the webapp. In some 
cases, it helps to preload dependency information for all classes.</li><li>If 
you start your webapp without component dependency information, page instances 
may be created and invalidated a few times even
  when they didn't have any changes due to the page classloader context 
creation. The solution for this is the same one as the 
above.</li></ol><p></p></div>
             </div>
             <!-- /// Content End -->
           </div>


Reply via email to