Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

One of the best features of Tapestry is automatic reloading of changed classes and templates. Page and component 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 Tapestry IoC). Starting in version 5.8.3, you enable multiple classloader mode, which allows smarter page class invalidation.

Alertinfo
titleThrowing Not necessarily throwing away all cached pages
typeWarning
page instances

Since Tapestry 5.8.3, Tapestry can be run in multiple classloaders mode. When it's on, only the affected cached page instances are discarded and rebuilt instead of all of them. 

...

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 example:

How It Works

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.

When multiple classloaders mode is on, these internal services notify their listeners what changed, so they can invalidate just the objects or information 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.

Additional logging was added so all files found as changed result in log entries. Same for the invalidation chain described in the paragraph above.

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 context, 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.

There are 2 special PCLC contexts: the root one, which is never invalidated, and the unknown one, where classes without dependency information go initially.

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. 

Loading, Storing and Preloading Dependency Information

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.

When starting up, Tapestry checks whether a file named tapestryComponentDependencies.json exists in the folder where the webapp is running. If it does, component dependency is loaded from it.

...