Modified: websites/production/tapestry/content/service-advisors.html
==============================================================================
--- websites/production/tapestry/content/service-advisors.html (original)
+++ websites/production/tapestry/content/service-advisors.html Wed Sep 20 
12:29:16 2017
@@ -27,6 +27,14 @@
       </title>
   <link type="text/css" rel="stylesheet" href="/resources/space.css" />
 
+          <link href='/resources/highlighter/styles/shCoreCXF.css' 
rel='stylesheet' type='text/css' />
+    <link href='/resources/highlighter/styles/shThemeCXF.css' rel='stylesheet' 
type='text/css' />
+    <script src='/resources/highlighter/scripts/shCore.js' 
type='text/javascript'></script>
+          <script src='/resources/highlighter/scripts/shBrushJava.js' 
type='text/javascript'></script>
+        <script>
+      SyntaxHighlighter.defaults['toolbar'] = false;
+      SyntaxHighlighter.all();
+    </script>
   
   <link href="/styles/style.css" rel="stylesheet" type="text/css"/>
 
@@ -67,7 +75,8 @@
       </div>
 
       <div id="content">
-                <div id="ConfluenceContent"><h1 
id="ServiceAdvisors-ServiceAdvisors">Service Advisors</h1><p>Service advice 
represents a powerful meta-programming facility available to services. In fact, 
it is a kind of limited Aspect Oriented Programming.</p><p>Service advice 
allows you to intercept method invocations on your services; you have the 
ability to see what methods get invoked, what the parameters are. You can let 
the normal code do it work, and then inspect or even adjust the return value, 
or any thrown exceptions. And you can do this all in normal Java code.</p><p>A 
common example of method-level service advice is to log method entry and exit, 
complete with parameter values, return values, and thrown exceptions. Other 
approaches include security checks, transaction management, and other broadly 
spanning concerns.</p><p>Let's start with a (contrived) example. Let's say you 
have an existing set of services that have methods that sometimes return null, 
and you want them t
 o return an empty string instead because you are getting some 
NullPointerExceptions elsewhere in your application.</p><p>You could track down 
the implementation of each service and fix the logic that provides a return 
value ... or you could advise the methods:</p><plain-text-body>  @Match("*")
+                <div id="ConfluenceContent"><h1 
id="ServiceAdvisors-ServiceAdvisors">Service Advisors</h1><p>Service advice 
represents a powerful meta-programming facility available to services. In fact, 
it is a kind of limited Aspect Oriented Programming.</p><p>Service advice 
allows you to intercept method invocations on your services; you have the 
ability to see what methods get invoked, what the parameters are. You can let 
the normal code do it work, and then inspect or even adjust the return value, 
or any thrown exceptions. And you can do this all in normal Java code.</p><p>A 
common example of method-level service advice is to log method entry and exit, 
complete with parameter values, return values, and thrown exceptions. Other 
approaches include security checks, transaction management, and other broadly 
spanning concerns.</p><p>Let's start with a (contrived) example. Let's say you 
have an existing set of services that have methods that sometimes return null, 
and you want them t
 o return an empty string instead because you are getting some 
NullPointerExceptions elsewhere in your application.</p><p>You could track down 
the implementation of each service and fix the logic that provides a return 
value ... or you could advise the methods:</p><div class="code panel pdl" 
style="border-width: 1px;"><div class="codeContent panelContent pdl">
+<pre class="brush: java; gutter: false; theme: Default" 
style="font-size:12px;">  @Match("*")
   public static void adviseNonNull(MethodAdviceReceiver receiver)
   {
     MethodAdvice advice = new MethodAdvice()
@@ -83,7 +92,9 @@
 
     receiver.adviseAllMethods(advice);
   };
-</plain-text-body><p>This is a method that is placed in a module class. Note 
the terminology: <em>advise</em> is the verb ("to advise a method") and 
<em>advice</em> is the noun ("with this advice"). The <a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/MethodAdviceReceiver.html";>MethodAdviceReceiver</a>
 is a wrapper around the service being advised: you can add advice to some or 
all methods of the service, and also obtain the interface of the service. It is 
automatically passed into service advisor methods.</p><p>See <a  
href="injection-in-detail.html">Injection in Detail</a> for what can be 
injected into a service advisor method.</p><p>Service advisor methods must have 
a parameter of type MethodAdviceReceiver.</p><p>A service will often be advised 
multiple times; any method may have any number of advice objects applied to it. 
Some methods may not get any advice. All of this is acceptable.</p><p>Service 
advisor methods are always voi
 d methods (this is different from <a  
href="tapestry-ioc-decorators.html">service decorator methods</a>).</p><p>The 
@<a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/Match.html";>Match</a>("*")
 annotation indicates that this advice applies to all services (both your own, 
and those defined by Tapestry). You will want to narrow down which services are 
actually targeted in most cases.</p><p>Note that some services, especially 
those built into Tapestry IoC, are marked as <a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/PreventServiceDecoration.html";>not
 subject to decoration</a>, this applies to service advice as well as service 
decoration.</p><p>The <a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/MethodAdvice.html";>MethodAdvice</a>
 interface is very simple; it receives an <a  class="external-link" 
href="http://t
 
apestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/Invocation.html">Invocation</a>
 representing a method call. Invocation has methods for inspecting the type and 
value of the parameters, and for overriding the values of the 
parameters.</p><p>The call to <code>proceed()</code> allows the invocation to 
continue; that is, the original method is invoked. If the method has been 
advised multiple times, the call to proceed() may chain into the next 
MethodAdvice object. In any case, after invoking <code>proceed()</code>, you 
may inspect and override the result (the return value).</p><p>Advice is pretty 
efficient, but it is still better to apply it only to methods that make sense. 
We can improve the service advisor method in our example to only advise methods 
that return String:</p><plain-text-body>  @Match("*")
+</pre>
+</div></div><p>This is a method that is placed in a module class. Note the 
terminology: <em>advise</em> is the verb ("to advise a method") and 
<em>advice</em> is the noun ("with this advice"). The <a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/MethodAdviceReceiver.html";>MethodAdviceReceiver</a>
 is a wrapper around the service being advised: you can add advice to some or 
all methods of the service, and also obtain the interface of the service. It is 
automatically passed into service advisor methods.</p><p>See <a  
href="injection-in-detail.html">Injection in Detail</a> for what can be 
injected into a service advisor method.</p><p>Service advisor methods must have 
a parameter of type MethodAdviceReceiver.</p><p>A service will often be advised 
multiple times; any method may have any number of advice objects applied to it. 
Some methods may not get any advice. All of this is acceptable.</p><p>Service 
advisor methods are always void meth
 ods (this is different from <a  href="tapestry-ioc-decorators.html">service 
decorator methods</a>).</p><p>The @<a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/Match.html";>Match</a>("*")
 annotation indicates that this advice applies to all services (both your own, 
and those defined by Tapestry). You will want to narrow down which services are 
actually targeted in most cases.</p><p>Note that some services, especially 
those built into Tapestry IoC, are marked as <a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/PreventServiceDecoration.html";>not
 subject to decoration</a>, this applies to service advice as well as service 
decoration.</p><p>The <a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/MethodAdvice.html";>MethodAdvice</a>
 interface is very simple; it receives an <a  class="external-link" 
href="http://tapestr
 
y.apache.org/current/apidocs/org/apache/tapestry5/ioc/Invocation.html">Invocation</a>
 representing a method call. Invocation has methods for inspecting the type and 
value of the parameters, and for overriding the values of the 
parameters.</p><p>The call to <code>proceed()</code> allows the invocation to 
continue; that is, the original method is invoked. If the method has been 
advised multiple times, the call to proceed() may chain into the next 
MethodAdvice object. In any case, after invoking <code>proceed()</code>, you 
may inspect and override the result (the return value).</p><p>Advice is pretty 
efficient, but it is still better to apply it only to methods that make sense. 
We can improve the service advisor method in our example to only advise methods 
that return String:</p><div class="code panel pdl" style="border-width: 
1px;"><div class="codeContent panelContent pdl">
+<pre class="brush: java; gutter: false; theme: Default" 
style="font-size:12px;">  @Match("*")
   public static void adviseNonNull(MethodAdviceReceiver receiver)
   {
     MethodAdvice advice = new MethodAdvice()
@@ -103,41 +114,52 @@
         receiver.adviseMethod(m, advice);
     }
   };
-</plain-text-body><h1 id="ServiceAdvisors-Built-inAdvice">Built-in 
Advice</h1><p>Tapestry includes two built-in advisor services.</p><h2 
id="ServiceAdvisors-LoggingAdvice">Logging Advice</h2><p>Logging advice is 
built into Tapestry. You can apply logging advice to your services very 
easily:</p><plain-text-body>  @Match("*")
+</pre>
+</div></div><h1 id="ServiceAdvisors-Built-inAdvice">Built-in 
Advice</h1><p>Tapestry includes two built-in advisor services.</p><h2 
id="ServiceAdvisors-LoggingAdvice">Logging Advice</h2><p>Logging advice is 
built into Tapestry. You can apply logging advice to your services very 
easily:</p><div class="code panel pdl" style="border-width: 1px;"><div 
class="codeContent panelContent pdl">
+<pre class="brush: java; gutter: false; theme: Default" 
style="font-size:12px;">  @Match("*")
   public static void adviseLogging(LoggingAdvisor loggingAdvisor, Logger 
logger, MethodAdviceReceiver receiver)
   {
     loggingAdvisor.addLoggingAdvice(logger, receiver);
   }
-</plain-text-body><p><a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/services/LoggingAdvisor.html";>LoggingAdvisor</a>
 is a built-in Tapestry IoC service. This demonstrates how services can be 
injected into service advisor methods. The Logger parameter is the logger for 
the service being advised.</p><h2 id="ServiceAdvisors-LazyAdvice">Lazy 
Advice</h2><p><a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/services/LazyAdvisor.html";>LazyAdvisor</a>
 makes method invocations lazy: methods that return an interface (rather than a 
value) will not execute immediately; instead, the method invocation is 
postponed until a method of the return value is invoked.</p><h1 
id="ServiceAdvisors-MatchingAndOrdering">Matching And Ordering</h1><p>Each 
service advice method gets a unique id, obtained by stripping the "advise" 
prefix from the method name. Advice ids must be unique across all 
modules.</p><p>If
  the @Match annotation is omitted, the advice will match against a service 
with the same id.</p><p>In many cases, the order in which the advice is given 
is very important; for example, you may want logging first, then transaction 
management, then security checks. The @<a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/Order.html";>Order</a>
 annotation allows you to explicitly set the order.</p><h1 
id="ServiceAdvisors-Annotationdrivenadvisors">Annotation driven advisors</h1><p>
+</pre>
+</div></div><p><a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/services/LoggingAdvisor.html";>LoggingAdvisor</a>
 is a built-in Tapestry IoC service. This demonstrates how services can be 
injected into service advisor methods. The Logger parameter is the logger for 
the service being advised.</p><h2 id="ServiceAdvisors-LazyAdvice">Lazy 
Advice</h2><p><a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/services/LazyAdvisor.html";>LazyAdvisor</a>
 makes method invocations lazy: methods that return an interface (rather than a 
value) will not execute immediately; instead, the method invocation is 
postponed until a method of the return value is invoked.</p><h1 
id="ServiceAdvisors-MatchingAndOrdering">Matching And Ordering</h1><p>Each 
service advice method gets a unique id, obtained by stripping the "advise" 
prefix from the method name. Advice ids must be unique across all 
modules.</p><p>If the @
 Match annotation is omitted, the advice will match against a service with the 
same id.</p><p>In many cases, the order in which the advice is given is very 
important; for example, you may want logging first, then transaction 
management, then security checks. The @<a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/Order.html";>Order</a>
 annotation allows you to explicitly set the order.</p><h1 
id="ServiceAdvisors-Annotationdrivenadvisors">Annotation driven advisors</h1><p>
 
 </p><div class="confluence-information-macro 
confluence-information-macro-information"><p class="title">Added in 
5.2</p><span class="aui-icon aui-icon-small aui-iconfont-info 
confluence-information-macro-icon"></span><div 
class="confluence-information-macro-body">
 </div></div>
 <div class="error"><span class="error">Unknown macro: {div}</span> 
-<p>&#160;</p></div>Starting from version 5.2, Tapestry supports 
annotation-driven advise methods. If the <a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/Advise.html";>@Advise</a>
 annotation is present, the advise method can be arbitrary named, as shown in 
the following example.<plain-text-body>  @Advise
+<p>&#160;</p></div>Starting from version 5.2, Tapestry supports 
annotation-driven advise methods. If the <a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/Advise.html";>@Advise</a>
 annotation is present, the advise method can be arbitrary named, as shown in 
the following example.<div class="code panel pdl" style="border-width: 
1px;"><div class="codeContent panelContent pdl">
+<pre class="brush: java; gutter: false; theme: Default" 
style="font-size:12px;">  @Advise
   @Match("*DAO")
   public static void byServiceId(MethodAdviceReceiver receiver)
   {
     ...
   }
-</plain-text-body><p>The advice above is applied to any service whose id 
matches the "*DAO" pattern.</p><p>Alternatively, marker annotations can be 
placed on the advise method to match a specific service.</p><plain-text-body>  
@Advise
+</pre>
+</div></div><p>The advice above is applied to any service whose id matches the 
"*DAO" pattern.</p><p>Alternatively, marker annotations can be placed on the 
advise method to match a specific service.</p><div class="code panel pdl" 
style="border-width: 1px;"><div class="codeContent panelContent pdl">
+<pre class="brush: java; gutter: false; theme: Default" 
style="font-size:12px;">  @Advise
   @Blue
   public static void byMarkerAnnotation(MethodAdviceReceiver receiver)
   {
     ...
   }
-</plain-text-body><p>The advice above is applied to any service that is marked 
by the @Blue annotation.</p><p>By default, <a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/Advise.html";>@Advise</a>
 annotation applies the advice to any service matched by the <a  
class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/Match.html";>@Match</a>
 or marker annotations. You can limit the matching to a single service 
interface, as shown in the following example.</p><plain-text-body>  
@Advise(serviceInterface=MyService.class)
+</pre>
+</div></div><p>The advice above is applied to any service that is marked by 
the @Blue annotation.</p><p>By default, <a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/Advise.html";>@Advise</a>
 annotation applies the advice to any service matched by the <a  
class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/Match.html";>@Match</a>
 or marker annotations. You can limit the matching to a single service 
interface, as shown in the following example.</p><div class="code panel pdl" 
style="border-width: 1px;"><div class="codeContent panelContent pdl">
+<pre class="brush: java; gutter: false; theme: Default" 
style="font-size:12px;">  @Advise(serviceInterface=MyService.class)
   @Match("*DAO")
   public static void byMatchAnnotation(MethodAdviceReceiver receiver)
   {
     ...
   }
-</plain-text-body><p>In the example above, the advice is applied to any 
implementation of MyService interfaces whose id matches the "*DAO" 
pattern.</p><plain-text-body>  @Advise(serviceInterface=MyService.class)
+</pre>
+</div></div><p>In the example above, the advice is applied to any 
implementation of MyService interfaces whose id matches the "*DAO" 
pattern.</p><div class="code panel pdl" style="border-width: 1px;"><div 
class="codeContent panelContent pdl">
+<pre class="brush: java; gutter: false; theme: Default" 
style="font-size:12px;">  @Advise(serviceInterface=MyService.class)
   @Blue
   public static void byMarkerAnnotation(MethodAdviceReceiver receiver)
   {
     ...
   }
-</plain-text-body><p>The advice above is applied to any implementation of the 
MyService interface that is marked by the @Blue annotation.</p><h1 
id="ServiceAdvisors-DecoratorsandAdvice">Decorators and Advice</h1><p><a  
href="tapestry-ioc-decorators.html">Service decorators</a> are another way to 
achieve the same thing; service advisors are a more recent addition, added in 
Tapestry 5.1.</p><p>It is not recommended that you mix advice and decoration. 
If you do, decoration take precedence; all decorators will be in effect before 
any advice (internally, they are two separate steps, with advice being 
processed and the result of that used by the 
decorators).</p><p>&#160;</p><p></p></div>
+</pre>
+</div></div><p>The advice above is applied to any implementation of the 
MyService interface that is marked by the @Blue annotation.</p><h1 
id="ServiceAdvisors-DecoratorsandAdvice">Decorators and Advice</h1><p><a  
href="tapestry-ioc-decorators.html">Service decorators</a> are another way to 
achieve the same thing; service advisors are a more recent addition, added in 
Tapestry 5.1.</p><p>It is not recommended that you mix advice and decoration. 
If you do, decoration take precedence; all decorators will be in effect before 
any advice (internally, they are two separate steps, with advice being 
processed and the result of that used by the 
decorators).</p><p>&#160;</p><p></p></div>
       </div>
 
       <div class="clearer"></div>

Modified: 
websites/production/tapestry/content/service-implementation-reloading.html
==============================================================================
--- websites/production/tapestry/content/service-implementation-reloading.html 
(original)
+++ websites/production/tapestry/content/service-implementation-reloading.html 
Wed Sep 20 12:29:16 2017
@@ -72,7 +72,40 @@
 </p><div class="confluence-information-macro 
confluence-information-macro-information"><p class="title">Added in 
5.2</p><span class="aui-icon aui-icon-small aui-iconfont-info 
confluence-information-macro-icon"></span><div 
class="confluence-information-macro-body">
 </div></div>
 <div class="error"><span class="error">Unknown macro: {div}</span> 
-<p>&#160;</p></div><strong>Service implementation reloading</strong> is the 
live reloading of Tapestry-IOC service implementation classes without having to 
stop &amp; restart the servlet container. Available for Tapestry 5.2 and later, 
it extends the developer productivity gains of Tapestry's <a  
href="class-reloading.html">Live Class Reloading</a> to your Tapestry-IOC 
service modules.<parameter ac:name="style">float:right</parameter><parameter 
ac:name="title">Related Articles</parameter><parameter 
ac:name="class">aui-label</parameter><rich-text-body><parameter 
ac:name="showLabels">false</parameter><parameter 
ac:name="showSpace">false</parameter><parameter ac:name="title">Related 
Articles</parameter><parameter ac:name="cql">label = "class-reloading" and 
space = currentSpace()</parameter></rich-text-body><p>Why is this 
important?</p><p>On the one hand, a good application design keeps the page and 
component classes "thin" and moves logic into the services layer, for easier 
reuse acros
 s pages. On the other hand, moving logic into services would be less agile if 
those services didn't auto-reload the way Tapestry pages do.</p><p>There are 
several restrictions on this, and a couple of <a  class="external-link" 
href="http://en.wikipedia.org/wiki/Leaky_abstraction"; rel="nofollow">leaky 
abstractions</a>, but on the whole it's quite serviceable.</p><p>As of release 
5.2, you can change your service implementation, and Tapestry picks up the 
change immediately. A service can even change its dependencies when being 
reloaded ... but it can't change its interface.</p><h2 
id="ServiceImplementationReloading-Limitations">Limitations</h2><ul><li>Reloading
 only works for services, and only for services with the default service scope 
(i.e., global singletons). Live reloading does not apply to 
<strong>modules</strong>, <strong>service interfaces</strong>, contributions, 
or anything but just the service implementation.</li><li>Reloading is limited 
to services that can be proxied: ser
 vices with an interface and an implementation of that 
interface.</li><li>Reloading requires that the underlying class files be 
simple, local, filesystem files (not, for example, files inside a 
JAR).</li><li>If a service has internal state of any kind, that state is lost 
when the class is reloaded and the service re-instantiated. However, if a 
service has a configuration, the configuration will be 
<strong>reconstructed</strong> and injected into the service.</li><li>Services 
are decorated only once, so any decorations or advice applies to the initially 
loaded version of the class, and will not be recalculated when the class 
changes.</li></ul><h2 
id="ServiceImplementationReloading-ClassLoaderIssues">Class Loader 
Issues</h2><p>Tapestry creates a new class loader for <em>each service 
implementation</em>. When the underlying .class file changes, the class loader 
is discarded along with the instance, and a new class loader is 
created.</p><p>The class loader only loads the service implemen
 tation class, and any inner classes for the service implementation. All other 
classes are loaded by the standard class loader for the 
application.</p><p>Because of how class loaders work, the class will no longer 
be able to access package private classes and members of other classes in the 
same package. You may see some odd IllegalAccessErrors and need to change the 
visibility of package-private classes to be public.</p><p>The JVM should be 
able to eventually garbage collect the class loader. However, if the class 
publishes itself to some other service (for example, adding itself as a 
listener to an event published by some other service), then the instance and 
the garbage collector will be leaked.</p><rich-text-body><p>Be careful about 
publishing any instances of a reloadable class.</p></rich-text-body><h2 
id="ServiceImplementationReloading-UpdateChecks">Update Checks</h2><p>Update 
checks are normally driven by tapestry-core, which periodically checks for 
changed templates, message 
 catalogs, and component classes. Checks for changed service implementation 
classes occur at the same time.</p><p>In an application that is not driven by 
the web tier, you will need to periodically invoke the 
<code>fireCheckForUpdates()</code> method of the <a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/UpdateListenerHub.html";>UpdateListenerHub</a>
 service (which was moved from tapestry-core to tapestry-ioc for this 
purpose).</p><p>&#160;</p><p></p><p>&#160;</p></div>
+<p>&#160;</p></div><strong>Service implementation reloading</strong> is the 
live reloading of Tapestry-IOC service implementation classes without having to 
stop &amp; restart the servlet container. Available for Tapestry 5.2 and later, 
it extends the developer productivity gains of Tapestry's <a  
href="class-reloading.html">Live Class Reloading</a> to your Tapestry-IOC 
service modules.<div class="aui-label" style="float:right" title="Related 
Articles">
+
+
+
+
+
+
+
+
+<h3>Related Articles</h3>
+
+<ul class="content-by-label"><li>
+        <div>
+                <span class="icon aui-icon aui-icon-small 
aui-iconfont-page-default" title="Page">Page:</span>        </div>
+
+        <div class="details">
+                        <a  
href="service-implementation-reloading.html">Service Implementation 
Reloading</a>
+                
+                        
+                    </div>
+    </li><li>
+        <div>
+                <span class="icon aui-icon aui-icon-small 
aui-iconfont-page-default" title="Page">Page:</span>        </div>
+
+        <div class="details">
+                        <a  href="class-reloading.html">Class Reloading</a>
+                
+                        
+                    </div>
+    </li></ul>
+</div>
+
+
+<p>Why is this important?</p><p>On the one hand, a good application design 
keeps the page and component classes "thin" and moves logic into the services 
layer, for easier reuse across pages. On the other hand, moving logic into 
services would be less agile if those services didn't auto-reload the way 
Tapestry pages do.</p><p>There are several restrictions on this, and a couple 
of <a  class="external-link" 
href="http://en.wikipedia.org/wiki/Leaky_abstraction"; rel="nofollow">leaky 
abstractions</a>, but on the whole it's quite serviceable.</p><p>As of release 
5.2, you can change your service implementation, and Tapestry picks up the 
change immediately. A service can even change its dependencies when being 
reloaded ... but it can't change its interface.</p><h2 
id="ServiceImplementationReloading-Limitations">Limitations</h2><ul><li>Reloading
 only works for services, and only for services with the default service scope 
(i.e., global singletons). Live reloading does not apply to <strong>mo
 dules</strong>, <strong>service interfaces</strong>, contributions, or 
anything but just the service implementation.</li><li>Reloading is limited to 
services that can be proxied: services with an interface and an implementation 
of that interface.</li><li>Reloading requires that the underlying class files 
be simple, local, filesystem files (not, for example, files inside a 
JAR).</li><li>If a service has internal state of any kind, that state is lost 
when the class is reloaded and the service re-instantiated. However, if a 
service has a configuration, the configuration will be 
<strong>reconstructed</strong> and injected into the service.</li><li>Services 
are decorated only once, so any decorations or advice applies to the initially 
loaded version of the class, and will not be recalculated when the class 
changes.</li></ul><h2 
id="ServiceImplementationReloading-ClassLoaderIssues">Class Loader 
Issues</h2><p>Tapestry creates a new class loader for <em>each service 
implementation</em>. Whe
 n the underlying .class file changes, the class loader is discarded along with 
the instance, and a new class loader is created.</p><p>The class loader only 
loads the service implementation class, and any inner classes for the service 
implementation. All other classes are loaded by the standard class loader for 
the application.</p><p>Because of how class loaders work, the class will no 
longer be able to access package private classes and members of other classes 
in the same package. You may see some odd IllegalAccessErrors and need to 
change the visibility of package-private classes to be public.</p><p>The JVM 
should be able to eventually garbage collect the class loader. However, if the 
class publishes itself to some other service (for example, adding itself as a 
listener to an event published by some other service), then the instance and 
the garbage collector will be leaked.</p><div 
class="confluence-information-macro confluence-information-macro-note"><span 
class="aui-icon aui-ico
 n-small aui-iconfont-warning confluence-information-macro-icon"></span><div 
class="confluence-information-macro-body"><p>Be careful about publishing any 
instances of a reloadable class.</p></div></div><h2 
id="ServiceImplementationReloading-UpdateChecks">Update Checks</h2><p>Update 
checks are normally driven by tapestry-core, which periodically checks for 
changed templates, message catalogs, and component classes. Checks for changed 
service implementation classes occur at the same time.</p><p>In an application 
that is not driven by the web tier, you will need to periodically invoke the 
<code>fireCheckForUpdates()</code> method of the <a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/UpdateListenerHub.html";>UpdateListenerHub</a>
 service (which was moved from tapestry-core to tapestry-ioc for this 
purpose).</p><p>&#160;</p><p></p><p>&#160;</p></div>
       </div>
 
       <div class="clearer"></div>

Modified: websites/production/tapestry/content/service-serialization.html
==============================================================================
--- websites/production/tapestry/content/service-serialization.html (original)
+++ websites/production/tapestry/content/service-serialization.html Wed Sep 20 
12:29:16 2017
@@ -27,6 +27,14 @@
       </title>
   <link type="text/css" rel="stylesheet" href="/resources/space.css" />
 
+          <link href='/resources/highlighter/styles/shCoreCXF.css' 
rel='stylesheet' type='text/css' />
+    <link href='/resources/highlighter/styles/shThemeCXF.css' rel='stylesheet' 
type='text/css' />
+    <script src='/resources/highlighter/scripts/shCore.js' 
type='text/javascript'></script>
+          <script src='/resources/highlighter/scripts/shBrushJava.js' 
type='text/javascript'></script>
+        <script>
+      SyntaxHighlighter.defaults['toolbar'] = false;
+      SyntaxHighlighter.all();
+    </script>
   
   <link href="/styles/style.css" rel="stylesheet" type="text/css"/>
 
@@ -36,26 +44,13 @@
 
   <div class="wrapper bs">
 
-        <div id="navigation"><div class="nav"><ul class="alternate"><li><a  
href="index.html">Home</a></li><li><a  href="getting-started.html">Getting 
Started</a></li><li><a  href="documentation.html">Documentation</a></li><li><a  
href="download.html">Download</a></li><li><a  
href="about.html">About</a></li><li><a  class="external-link" 
href="http://www.apache.org/licenses/LICENSE-2.0";>License</a></li><li><a  
href="community.html">Community</a></li><li><a  class="external-link" 
href="http://www.apache.org/security/";>Security</a></li><li><a  
class="external-link" href="http://www.apache.org/";>Apache</a></li><li><a  
class="external-link" 
href="http://www.apache.org/foundation/sponsorship.html";>Sponsorship</a></li><li><a
  class="external-link" 
href="http://www.apache.org/foundation/thanks.html";>Thanks</a></li></ul></div>
-
-</div>
+        <div id="navigation"><div class="nav"><ul class="alternate"><li><a  
href="index.html">Home</a></li><li><a  href="getting-started.html">Getting 
Started</a></li><li><a  href="documentation.html">Documentation</a></li><li><a  
href="download.html">Download</a></li><li><a  
href="about.html">About</a></li><li><a  class="external-link" 
href="http://www.apache.org/licenses/LICENSE-2.0";>License</a></li><li><a  
href="community.html">Community</a></li><li><a  class="external-link" 
href="http://www.apache.org/security/";>Security</a></li><li><a  
class="external-link" href="http://www.apache.org/";>Apache</a></li><li><a  
class="external-link" 
href="http://www.apache.org/foundation/sponsorship.html";>Sponsorship</a></li><li><a
  class="external-link" 
href="http://www.apache.org/foundation/thanks.html";>Thanks</a></li></ul></div></div>
 
           <div id="top">
-            <div id="smallbanner"><div class="searchbox" 
style="float:right;margin: .3em 1em .1em 1em"><span style="color: #999; 
font-size: 90%">Tapestry docs, issues, wikis &amp; blogs:</span>
-<form enctype="application/x-www-form-urlencoded" method="get" 
action="http://tapestry.apache.org/search.html";>
-  <input type="text" name="q">
-  <input type="submit" value="Search">
-</form>
-
-</div>
-
-
-<div class="emblem" style="float:left"><p><a  href="index.html"><span 
class="confluence-embedded-file-wrapper"><img class="confluence-embedded-image 
confluence-external-resource" 
src="http://tapestry.apache.org/images/tapestry_small.png"; 
data-image-src="http://tapestry.apache.org/images/tapestry_small.png";></span></a></p></div>
-
-
-<div class="title" style="float:left; margin: 0 0 0 3em"><h1 
id="SmallBanner-PageTitle">Service Serialization</h1></div>
-
-</div>
+            <div id="smallbanner"><div class="searchbox" 
style="float:right;margin: .3em 1em .1em 1em"><span style="color: #999; 
font-size: 90%">Tapestry docs, issues, wikis &amp; blogs:</span><form 
enctype="application/x-www-form-urlencoded" method="get" 
action="http://tapestry.apache.org/search.html";> 
+ <input type="text" name="q"> 
+ <input type="submit" value="Search"> 
+</form></div><div class="emblem" style="float:left"><p><a  
href="index.html"><span class="confluence-embedded-file-wrapper"><img 
class="confluence-embedded-image confluence-external-resource" 
src="http://tapestry.apache.org/images/tapestry_small.png"; 
data-image-src="http://tapestry.apache.org/images/tapestry_small.png";></span></a></p></div><div
 class="title" style="float:left; margin: 0 0 0 3em"><h1 
id="SmallBanner-PageTitle">Service Serialization</h1></div></div>
       <div class="clearer"></div>
       </div>
 
@@ -67,9 +62,11 @@
       </div>
 
       <div id="content">
-                <div id="ConfluenceContent"><p><strong>Service 
serialization</strong> is the serialization of a Tapestry IOC 
service.</p><p>Every once in a while you may need to serialize a service. For 
example, you may store an object into the HttpSession that holds a reference to 
a service. In a clustered environment, that object will be serialized and 
broadcast to other servers in the cluster.</p><p>Services in Tapestry are 
serializable. Specifically, service <em>proxies</em> are serializable. However, 
your service implementations <em>do not</em> have to be 
serializable.</p><p>Serialization works as follows:</p><ul><li>When a proxy is 
serialized, it instead serializes a <em>token</em> object.</li><li>The token 
object is what's stored in the output stream.</li><li>When the token is 
de-serialized, it locates the service proxy in the current Registry and returns 
that.</li></ul><p>The end result is very efficient: just the tiny tokens are 
serialized, not the services with their proxi
 es, configurations, implementations, dependencies, internal state and so 
forth.</p><p>Again, note that the actual service implementation is not 
serialized. Due to Tapestry's lazy creation policy, the service implementation 
may not even exist. Since outside code only sees the proxy, there's no 
difference.</p><h1 id="ServiceSerialization-RegistryResolution">Registry 
Resolution</h1><p>The one trick here is locating the service proxy. Tapestry 
uses a <em>weak reference</em> to the Registry to do this. When a Registry 
starts up, it is stored in the reference, so that de-serialization can 
work.</p><p>The reference is cleared when you shut down the Registry. If you 
stop using the Registry, but fail to shut it down, the weak reference ensures 
that it will be released to the garbage collector anyway. Still, you should 
shutdown a Registry when done with it.</p><p>This all makes one BIG assumption: 
that there's just one Registry. That's normal for a web application, especially 
when the tapestr
 y-ioc JAR is included as part of the web application's WAR.</p><p>If you are 
running multiple Registries you will likely see errors in your 
console:</p><plain-text-body>[ERROR] SerializationSupport Setting a new service 
proxy provider when there's already
+                <div id="ConfluenceContent"><p><strong>Service 
serialization</strong> is the serialization of a Tapestry IOC 
service.</p><p>Every once in a while you may need to serialize a service. For 
example, you may store an object into the HttpSession that holds a reference to 
a service. In a clustered environment, that object will be serialized and 
broadcast to other servers in the cluster.</p><p>Services in Tapestry are 
serializable. Specifically, service <em>proxies</em> are serializable. However, 
your service implementations <em>do not</em> have to be 
serializable.</p><p>Serialization works as follows:</p><ul><li>When a proxy is 
serialized, it instead serializes a <em>token</em> object.</li><li>The token 
object is what's stored in the output stream.</li><li>When the token is 
de-serialized, it locates the service proxy in the current Registry and returns 
that.</li></ul><p>The end result is very efficient: just the tiny tokens are 
serialized, not the services with their proxi
 es, configurations, implementations, dependencies, internal state and so 
forth.</p><p>Again, note that the actual service implementation is not 
serialized. Due to Tapestry's lazy creation policy, the service implementation 
may not even exist. Since outside code only sees the proxy, there's no 
difference.</p><h1 id="ServiceSerialization-RegistryResolution">Registry 
Resolution</h1><p>The one trick here is locating the service proxy. Tapestry 
uses a <em>weak reference</em> to the Registry to do this. When a Registry 
starts up, it is stored in the reference, so that de-serialization can 
work.</p><p>The reference is cleared when you shut down the Registry. If you 
stop using the Registry, but fail to shut it down, the weak reference ensures 
that it will be released to the garbage collector anyway. Still, you should 
shutdown a Registry when done with it.</p><p>This all makes one BIG assumption: 
that there's just one Registry. That's normal for a web application, especially 
when the tapestr
 y-ioc JAR is included as part of the web application's WAR.</p><p>If you are 
running multiple Registries you will likely see errors in your console:</p><div 
class="code panel pdl" style="border-width: 1px;"><div class="codeContent 
panelContent pdl">
+<pre class="brush: java; gutter: false; theme: Default" 
style="font-size:12px;">[ERROR] SerializationSupport Setting a new service 
proxy provider when there's already
 an existing provider. This may indicate that you have multiple IoC Registries.
-</plain-text-body><p>&#160;</p><p></p></div>
+</pre>
+</div></div><p>&#160;</p><p></p></div>
       </div>
 
       <div class="clearer"></div>

Modified: websites/production/tapestry/content/session-storage.html
==============================================================================
--- websites/production/tapestry/content/session-storage.html (original)
+++ websites/production/tapestry/content/session-storage.html Wed Sep 20 
12:29:16 2017
@@ -27,6 +27,16 @@
       </title>
   <link type="text/css" rel="stylesheet" href="/resources/space.css" />
 
+          <link href='/resources/highlighter/styles/shCoreCXF.css' 
rel='stylesheet' type='text/css' />
+    <link href='/resources/highlighter/styles/shThemeCXF.css' rel='stylesheet' 
type='text/css' />
+    <script src='/resources/highlighter/scripts/shCore.js' 
type='text/javascript'></script>
+          <script src='/resources/highlighter/scripts/shBrushJava.js' 
type='text/javascript'></script>
+          <script src='/resources/highlighter/scripts/shBrushXml.js' 
type='text/javascript'></script>
+          <script src='/resources/highlighter/scripts/shBrushPlain.js' 
type='text/javascript'></script>
+        <script>
+      SyntaxHighlighter.defaults['toolbar'] = false;
+      SyntaxHighlighter.all();
+    </script>
   
   <link href="/styles/style.css" rel="stylesheet" type="text/css"/>
 
@@ -67,28 +77,92 @@
       </div>
 
       <div id="content">
-                <div id="ConfluenceContent"><p>&#160;</p><p>Most web 
applications will need to have some data that is shared across multiple pages. 
Perhaps you are creating a multi-page wizard, or you have an object that tracks 
the user's identify once logged in, or maybe you need to manage a shopping 
cart.</p><parameter ac:name="style">float:right</parameter><parameter 
ac:name="title">Related Articles</parameter><parameter 
ac:name="class">aui-label</parameter><rich-text-body><parameter 
ac:name="showLabels">false</parameter><parameter 
ac:name="showSpace">false</parameter><parameter ac:name="title">Related 
Articles</parameter><parameter ac:name="cql">label = "persistence" and space = 
currentSpace()</parameter></rich-text-body><p>Ordinary <a  
href="persistent-page-data.html">page-persistent fields</a> won't work for 
this, since persistent fields are available only to a specific page, not shared 
across multiple pages.</p><p>Tapestry provides two mechanisms for storing such 
data: Sessio
 n State Objects and Session Attributes. When deciding between the two, it's 
best to use Session State Objects for complex objects, and Session Attributes 
for simple types.</p><h2 id="SessionStorage-SessionStateObjects">Session State 
Objects</h2><p>With a Session State Object (SSO), the value is automatically 
stored outside the page; with the default storage strategy, it is stored in the 
session. Such a value is global to all pages <em>for the same user</em>, but is 
stored separately for different users.</p><p>A field holding an SSO is marked 
with the @<a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/annotations/SessionState.html";>SessionState</a>
 annotation.<plain-text-body>{float:right}
-{panel:background=#eee|title=Contents}
-{toc:minLevel=2|maxLevel=4}
-{panel}
-{float}</plain-text-body>Example:</p><parameter 
ac:name="">java</parameter><plain-text-body>public class MyPage
+                <div id="ConfluenceContent"><p>&#160;</p><p>Most web 
applications will need to have some data that is shared across multiple pages. 
Perhaps you are creating a multi-page wizard, or you have an object that tracks 
the user's identify once logged in, or maybe you need to manage a shopping 
cart.</p><div class="aui-label" style="float:right" title="Related Articles">
+
+
+
+
+
+
+
+
+<h3>Related Articles</h3>
+
+<ul class="content-by-label"><li>
+        <div>
+                <span class="icon aui-icon aui-icon-small 
aui-iconfont-page-default" title="Page">Page:</span>        </div>
+
+        <div class="details">
+                        <a  href="performance-and-clustering.html">Performance 
and Clustering</a>
+                
+                        
+                    </div>
+    </li><li>
+        <div>
+                <span class="icon aui-icon aui-icon-small 
aui-iconfont-page-default" title="Page">Page:</span>        </div>
+
+        <div class="details">
+                        <a  href="session-storage.html">Session Storage</a>
+                
+                        
+                    </div>
+    </li><li>
+        <div>
+                <span class="icon aui-icon aui-icon-small 
aui-iconfont-page-default" title="Page">Page:</span>        </div>
+
+        <div class="details">
+                        <a  href="persistent-page-data.html">Persistent Page 
Data</a>
+                
+                        
+                    </div>
+    </li></ul>
+</div>
+
+
+<p>Ordinary <a  href="persistent-page-data.html">page-persistent fields</a> 
won't work for this, since persistent fields are available only to a specific 
page, not shared across multiple pages.</p><p>Tapestry provides two mechanisms 
for storing such data: Session State Objects and Session Attributes. When 
deciding between the two, it's best to use Session State Objects for complex 
objects, and Session Attributes for simple types.</p><h2 
id="SessionStorage-SessionStateObjects">Session State Objects</h2><p>With a 
Session State Object (SSO), the value is automatically stored outside the page; 
with the default storage strategy, it is stored in the session. Such a value is 
global to all pages <em>for the same user</em>, but is stored separately for 
different users.</p><p>A field holding an SSO is marked with the @<a  
class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/annotations/SessionState.html";>SessionState</a>
 annotation.</p><div class="navmen
 u" style="float:right; background:white; margin:3px; padding:3px">
+<div class="panel" style="border-width: 1px;"><div class="panelHeader" 
style="border-bottom-width: 1px;"><b>Contents</b></div><div 
class="panelContent">
+<style type="text/css">/*<![CDATA[*/
+div.rbtoc1499639543191 {padding: 0px;}
+div.rbtoc1499639543191 ul {list-style: disc;margin-left: 0px;}
+div.rbtoc1499639543191 li {margin-left: 0px;padding-left: 0px;}
+
+/*]]>*/</style><div class="toc-macro rbtoc1499639543191">
+<ul class="toc-indentation"><li>Related Articles</li></ul>
+<ul><li><a  href="#SessionStorage-SessionStateObjects">Session State 
Objects</a>
+<ul class="toc-indentation"><li><a  
href="#SessionStorage-Pitfalls">Pitfalls</a></li><li><a  
href="#SessionStorage-CheckforCreation">Check for Creation</a></li><li><a  
href="#SessionStorage-PersistenceStrategies">Persistence 
Strategies</a></li><li><a  href="#SessionStorage-ConfiguringSSOs">Configuring 
SSOs</a></li></ul>
+</li><li><a  href="#SessionStorage-SessionAttributes">Session Attributes</a>
+<ul class="toc-indentation"><li><a  
href="#SessionStorage-Pitfalls.1">Pitfalls</a></li></ul>
+</li><li><a  href="#SessionStorage-ClusteringIssues">Clustering Issues</a>
+<ul class="toc-indentation"><li><a  
href="#SessionStorage-@ImmutableSessionPersistedObjectAnnotation">@ImmutableSessionPersistedObject
 Annotation</a></li><li><a  
href="#SessionStorage-OptimizedSessionPersistedObjectInterface">OptimizedSessionPersistedObject
 Interface</a></li><li><a  
href="#SessionStorage-SessionPersistedObjectAnalyzerService">SessionPersistedObjectAnalyzer
 Service</a></li></ul>
+</li><li><a  href="#SessionStorage-SessionLocking">Session 
Locking</a></li></ul>
+</div>
+</div></div></div>Example:<div class="code panel pdl" style="border-width: 
1px;"><div class="codeContent panelContent pdl">
+<pre class="brush: java; gutter: false; theme: Default" 
style="font-size:12px;">public class MyPage
 {
   @SessionState
   private ShoppingCart shoppingCart;
   
   . . .
 }
-</plain-text-body><p>Any other component or page that declares a field 
<strong>of the same type</strong>, regardless of name, and marks it with the 
SessionState annotation will share the same value. It's that simple. However, 
using @SessionState <em>safely</em> requires care:</p><rich-text-body><p>DO NOT 
USE @SessionState FOR SIMPLE TYPES! Only use it on variables that are of a 
custom-built class designed expressly for this purpose! <strong>See the 
Pitfalls section below</strong>.</p></rich-text-body><p>The first time you 
access an SSO, it is created automatically. Typically, the SSO will have a 
public no-args constructor ... but you may inject dependencies into the SSO via 
its constructor, as you can with a Tapestry IoC service 
implementation.</p><p><em>For Tapestry 4 Users:</em> a big change here is that 
you don't need to provide any configuration for the SSO before using it, nor do 
you provide a logical name. Tapestry 5 uses the class name to identify the SSO, 
so there's no need 
 for a logical name.</p><p>Assigning a value to an SSO field will store that 
value. Assigning null to an SSO field will remove the SSO (reading the field 
subsequently will force a new SSO instance to be created).</p><h3 
id="SessionStorage-Pitfalls">Pitfalls</h3><p>With @SessionState, you are 
creating a session-wide data storage area that is tied to the <em>type</em> 
(class) of the variable you annotate. It is not specifically tied to the 
variable itself, or even to the class in which that variable was annotated. As 
with all session data, there is the serious possibility of collisions, not just 
within your application but with other modules/libraries:</p><parameter 
ac:name="title">Example of Data Collision -- Don't Do 
This!</parameter><plain-text-body>  @SessionState
+</pre>
+</div></div><p>Any other component or page that declares a field <strong>of 
the same type</strong>, regardless of name, and marks it with the SessionState 
annotation will share the same value. It's that simple. However, using 
@SessionState <em>safely</em> requires care:</p><div 
class="confluence-information-macro confluence-information-macro-warning"><span 
class="aui-icon aui-icon-small aui-iconfont-error 
confluence-information-macro-icon"></span><div 
class="confluence-information-macro-body"><p>DO NOT USE @SessionState FOR 
SIMPLE TYPES! Only use it on variables that are of a custom-built class 
designed expressly for this purpose! <strong>See the Pitfalls section 
below</strong>.</p></div></div><p>The first time you access an SSO, it is 
created automatically. Typically, the SSO will have a public no-args 
constructor ... but you may inject dependencies into the SSO via its 
constructor, as you can with a Tapestry IoC service 
implementation.</p><p><em>For Tapestry 4 Users:</em> a big ch
 ange here is that you don't need to provide any configuration for the SSO 
before using it, nor do you provide a logical name. Tapestry 5 uses the class 
name to identify the SSO, so there's no need for a logical 
name.</p><p>Assigning a value to an SSO field will store that value. Assigning 
null to an SSO field will remove the SSO (reading the field subsequently will 
force a new SSO instance to be created).</p><h3 
id="SessionStorage-Pitfalls">Pitfalls</h3><p>With @SessionState, you are 
creating a session-wide data storage area that is tied to the <em>type</em> 
(class) of the variable you annotate. It is not specifically tied to the 
variable itself, or even to the class in which that variable was annotated. As 
with all session data, there is the serious possibility of collisions, not just 
within your application but with other modules/libraries:</p><div class="code 
panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" 
style="border-bottom-width: 1px;"><b>Example
  of Data Collision &#8211; Don't Do This!</b></div><div class="codeContent 
panelContent pdl">
+<pre class="brush: java; gutter: false; theme: Default" 
style="font-size:12px;">  @SessionState
   private String userName;     // Unsafe -- String is not a custom type
 
   ... then, later in this class or any other:
 
   @sessionState
   private String userCity;     // This overwrites value in userName, because 
it's also a String!
-</plain-text-body><p>The simple rule is, NEVER use @SessionState for 
simple-type variables. It is ALWAYS worth taking the time to build a special 
class to hold your session state information. Doing so will force you to 
consolidate that information into a single, logical unit that can't be 
accidentally accessed by other classes. (Alternatively, see the Session 
Attribute section below.)</p><h3 id="SessionStorage-CheckforCreation">Check for 
Creation</h3><p>Scalable web applications do not create the server-side session 
needlessly. If you can avoid creating the session, especially on first access 
to your web application, you will be able to handle an order of magnitude more 
users. So, if you can avoid creating the SSO, you should do so.</p><p>But how 
to avoid creating it? Simply checking ("shoppingCart!= null") will force the 
creation of the SSO and the session to store it in.</p><p>Instead, create a 
second field with a matching name but with "Exists" appended:</p><parameter 
ac:name="">
 java</parameter><plain-text-body>  private boolean shoppingCartExists;
-</plain-text-body><p>It is not annotated; it is located by naming convention 
("Exists" appended). It must be type boolean and must be a private instance 
variable. Tapestry will automatically set this variable to <code>true</code> 
when the SSO is created, so you can check it to see if the SSO already 
exists.</p><p>Alternately, you may allow for the state being 
null:</p><parameter ac:name="">java</parameter><plain-text-body>  
@SessionState(create=false)
+</pre>
+</div></div><p>The simple rule is, NEVER use @SessionState for simple-type 
variables. It is ALWAYS worth taking the time to build a special class to hold 
your session state information. Doing so will force you to consolidate that 
information into a single, logical unit that can't be accidentally accessed by 
other classes. (Alternatively, see the Session Attribute section below.)</p><h3 
id="SessionStorage-CheckforCreation">Check for Creation</h3><p>Scalable web 
applications do not create the server-side session needlessly. If you can avoid 
creating the session, especially on first access to your web application, you 
will be able to handle an order of magnitude more users. So, if you can avoid 
creating the SSO, you should do so.</p><p>But how to avoid creating it? Simply 
checking ("shoppingCart!= null") will force the creation of the SSO and the 
session to store it in.</p><p>Instead, create a second field with a matching 
name but with "Exists" appended:</p><div class="code panel pdl" 
 style="border-width: 1px;"><div class="codeContent panelContent pdl">
+<pre class="brush: java; gutter: false; theme: Default" 
style="font-size:12px;">  private boolean shoppingCartExists;
+</pre>
+</div></div><p>It is not annotated; it is located by naming convention 
("Exists" appended). It must be type boolean and must be a private instance 
variable. Tapestry will automatically set this variable to <code>true</code> 
when the SSO is created, so you can check it to see if the SSO already 
exists.</p><p>Alternately, you may allow for the state being null:</p><div 
class="code panel pdl" style="border-width: 1px;"><div class="codeContent 
panelContent pdl">
+<pre class="brush: java; gutter: false; theme: Default" 
style="font-size:12px;">  @SessionState(create=false)
   private ShoppingCart shoppingCart;
-</plain-text-body><p>In this case, the shoppingCart field will be null if the 
ShoppingCart SSO does not exist, but will be non-null if it has been created 
(either by assigning a value to the field, or by a different SSO field where 
create is true).</p><h3 id="SessionStorage-PersistenceStrategies">Persistence 
Strategies</h3><p>Main Article: <a  href="persistent-page-data.html">Persistent 
Page Data</a></p><p>Each SSO is managed according to a persistence strategy. 
The default persistence strategy, "session", stores the SSOs inside the 
session. The session is created as needed.</p><h3 
id="SessionStorage-ConfiguringSSOs">Configuring SSOs</h3><p>Generally, you will 
need to configure your Session State Object if you want to change the 
persistence strategy to other than the default. (Right now there's only one 
built in strategy, but more will be coming in the future.)</p><p>Alternately, 
you can configure a Session State Object in order to control how it is 
instantiated. You may need to inj
 ect some values into the SSO when it is first created, or otherwise initialize 
it. In this case, you may provide an <a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/ApplicationStateCreator.html";>ApplicationStateCreator</a>
 object, which will be called upon to create the SSO as necessary. This is also 
the technique to use when you want your SSO to be represented by an 
<em>interface</em> rather than a <em>class</em>: you need to provide a creator 
that knows about the class that implements the interface.</p><p>A Session State 
Object is configured using contributions to the ApplicationStateManager 
service. From your application's module:</p><parameter 
ac:name="">java</parameter><plain-text-body>  public void 
contributeApplicationStateManager(MappedConfiguration&lt;Class, 
ApplicationStateContribution&gt; configuration)
+</pre>
+</div></div><p>In this case, the shoppingCart field will be null if the 
ShoppingCart SSO does not exist, but will be non-null if it has been created 
(either by assigning a value to the field, or by a different SSO field where 
create is true).</p><h3 id="SessionStorage-PersistenceStrategies">Persistence 
Strategies</h3><p>Main Article: <a  href="persistent-page-data.html">Persistent 
Page Data</a></p><p>Each SSO is managed according to a persistence strategy. 
The default persistence strategy, "session", stores the SSOs inside the 
session. The session is created as needed.</p><h3 
id="SessionStorage-ConfiguringSSOs">Configuring SSOs</h3><p>Generally, you will 
need to configure your Session State Object if you want to change the 
persistence strategy to other than the default. (Right now there's only one 
built in strategy, but more will be coming in the future.)</p><p>Alternately, 
you can configure a Session State Object in order to control how it is 
instantiated. You may need to inject so
 me values into the SSO when it is first created, or otherwise initialize it. 
In this case, you may provide an <a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/ApplicationStateCreator.html";>ApplicationStateCreator</a>
 object, which will be called upon to create the SSO as necessary. This is also 
the technique to use when you want your SSO to be represented by an 
<em>interface</em> rather than a <em>class</em>: you need to provide a creator 
that knows about the class that implements the interface.</p><p>A Session State 
Object is configured using contributions to the ApplicationStateManager 
service. From your application's module:</p><div class="code panel pdl" 
style="border-width: 1px;"><div class="codeContent panelContent pdl">
+<pre class="brush: java; gutter: false; theme: Default" 
style="font-size:12px;">  public void 
contributeApplicationStateManager(MappedConfiguration&lt;Class, 
ApplicationStateContribution&gt; configuration)
   {
     ApplicationStateCreator&lt;MyState&gt; creator = new 
ApplicationStateCreator&lt;ShoppingCart&gt;()
     {
@@ -100,12 +174,14 @@
   
     configuration.add(ShoppingCart.class, new 
ApplicationStateContribution("session", creator));
   }
-</plain-text-body><p>Here, we have an SSO type of ShoppingCart, and we're 
providing a creator for it. We've dolled the creator up with some generic 
types, but that isn't essential.</p><p>Our creator creates a new MyState 
instance using an alternate constructor that takes the current date and time. 
Again, just an example.</p><p>Finally, we create an <a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/ApplicationStateContribution.html";>ApplicationStateContribution</a>
 identifying the strategy name and the creator, and give that to the 
configuration.</p><p><strong>Note:</strong> You might be confused by the name 
"_Application_StateManager" and "_Application_StateCreator"; these reflect a 
difference in naming between 5.0 and 5.1; SSOs were originally called 
"Application State Objects", but that naming implied they were stored in the 
ServletContext, as application global to all users. The new SessionState 
annotation was introduced, but
  the existing services need to keep thier names as-is.</p><h2 
id="SessionStorage-SessionAttributes">Session Attributes</h2>
+</pre>
+</div></div><p>Here, we have an SSO type of ShoppingCart, and we're providing 
a creator for it. We've dolled the creator up with some generic types, but that 
isn't essential.</p><p>Our creator creates a new MyState instance using an 
alternate constructor that takes the current date and time. Again, just an 
example.</p><p>Finally, we create an <a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/ApplicationStateContribution.html";>ApplicationStateContribution</a>
 identifying the strategy name and the creator, and give that to the 
configuration.</p><p><strong>Note:</strong> You might be confused by the name 
"_Application_StateManager" and "_Application_StateCreator"; these reflect a 
difference in naming between 5.0 and 5.1; SSOs were originally called 
"Application State Objects", but that naming implied they were stored in the 
ServletContext, as application global to all users. The new SessionState 
annotation was introduced, but the e
 xisting services need to keep thier names as-is.</p><h2 
id="SessionStorage-SessionAttributes">Session Attributes</h2>
 
 <div class="confluence-information-macro 
confluence-information-macro-information"><p class="title">Added in 
5.2</p><span class="aui-icon aui-icon-small aui-iconfont-info 
confluence-information-macro-icon"></span><div 
class="confluence-information-macro-body">
 </div></div>
 <div class="error"><span class="error">Unknown macro: {div}</span> 
-<p>&#160;</p></div><p>As an alternative to SSOs, Tapestry provides a 
<strong>Session Attribute</strong> mechanism, which lets you store data in the 
session by name (rather than type). It is particularly useful when integrating 
Tapestry with legacy applications that directly manipulate the 
HttpSession.</p><parameter ac:name="title">The Old 
Way</parameter><plain-text-body>public class Page {
+<p>&#160;</p></div><p>As an alternative to SSOs, Tapestry provides a 
<strong>Session Attribute</strong> mechanism, which lets you store data in the 
session by name (rather than type). It is particularly useful when integrating 
Tapestry with legacy applications that directly manipulate the 
HttpSession.</p><div class="code panel pdl" style="border-width: 1px;"><div 
class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>The Old 
Way</b></div><div class="codeContent panelContent pdl">
+<pre class="brush: java; gutter: false; theme: Default" 
style="font-size:12px;">public class Page {
     @Inject
     private Request request;
     
@@ -113,15 +189,21 @@
         return (User) 
request.getSession(true).getAttribute("loggedInUserName");
     }
 }
-</plain-text-body><p>Starting with Tapestry 5.2, this can be accomplished just 
by annotating a page or component property with @<a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/annotations/SessionAttribute.html";>SessionAttribute</a>.
 This annotation is used to map a property of a page or component to value 
stored in session. Unlike Session State Objects, the name (not the type) of the 
annotated property is used as the name of the session attribute to look 
for.</p><parameter ac:name="title">The New 
Way</parameter><plain-text-body>public class Page {
+</pre>
+</div></div><p>Starting with Tapestry 5.2, this can be accomplished just by 
annotating a page or component property with @<a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/annotations/SessionAttribute.html";>SessionAttribute</a>.
 This annotation is used to map a property of a page or component to value 
stored in session. Unlike Session State Objects, the name (not the type) of the 
annotated property is used as the name of the session attribute to look 
for.</p><div class="code panel pdl" style="border-width: 1px;"><div 
class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>The New 
Way</b></div><div class="codeContent panelContent pdl">
+<pre class="brush: java; gutter: false; theme: Default" 
style="font-size:12px;">public class Page {
     @SessionAttribute
     private User loggedInUserName;
 }
-</plain-text-body><p>You can also provide a name using the annotation's 
<code>value</code> parameter:</p><plain-text-body>public class Page {
+</pre>
+</div></div><p>You can also provide a name using the annotation's 
<code>value</code> parameter:</p><div class="code panel pdl" 
style="border-width: 1px;"><div class="codeContent panelContent pdl">
+<pre class="brush: java; gutter: false; theme: Default" 
style="font-size:12px;">public class Page {
     @SessionAttribute("loggedInUserName")
     private User userName;
 }
-</plain-text-body><h3 id="SessionStorage-Pitfalls.1">Pitfalls</h3><p>As with 
SSOs, when using Session Attributes you are creating a session-wide data 
storage area that has the serious possibility of data collisions, not just 
within your application but with other modules/libraries. To avoid problems, 
you should qualify the session attribute name with a package-like naming 
convention. For example, use something like "com.mycompany.myapp.username" 
instead of just "username".</p><p>It's best to define the session attribute 
name as constant, and use that in the annotation's value parameter, rather then 
defaulting to the instance variable name. This will help prevent subtle runtime 
errors due to misspellings. For example:</p><parameter ac:name="title">The 
Safer Way</parameter><plain-text-body>public static final String 
USER_NAME_SESSION_ATTRIBUTE = "com.example.shoppingapp.username";
+</pre>
+</div></div><h3 id="SessionStorage-Pitfalls.1">Pitfalls</h3><p>As with SSOs, 
when using Session Attributes you are creating a session-wide data storage area 
that has the serious possibility of data collisions, not just within your 
application but with other modules/libraries. To avoid problems, you should 
qualify the session attribute name with a package-like naming convention. For 
example, use something like "com.mycompany.myapp.username" instead of just 
"username".</p><p>It's best to define the session attribute name as constant, 
and use that in the annotation's value parameter, rather then defaulting to the 
instance variable name. This will help prevent subtle runtime errors due to 
misspellings. For example:</p><div class="code panel pdl" style="border-width: 
1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 
1px;"><b>The Safer Way</b></div><div class="codeContent panelContent pdl">
+<pre class="brush: java; gutter: false; theme: Default" 
style="font-size:12px;">public static final String USER_NAME_SESSION_ATTRIBUTE 
= "com.example.shoppingapp.username";
 
 ...
 
@@ -129,12 +211,41 @@ public class Page {
     @SessionAttribute(USER_NAME_SESSION_ATTRIBUTE)
     private User userName;
 }
-</plain-text-body><p><parameter ac:name=""><a  
href="clustering-issues.html">Clustering Issues</a></parameter></p><h2 
id="SessionStorage-SessionLocking">Session Locking</h2><p>Starting with version 
5.4, by default Tapestry will apply locking semantics around access to the 
HttpSession. Reading attribute names occurs with a shared read lock, and 
getting or setting an attribute upgrades the lock to an exclusive write lock. 
This can tend to serialize threads when a number of simultaneous (Ajax) 
requests from the client arrive. However, many implementations of HttpSession 
are not thread safe, and often mutable objects<br clear="none"> are stored in 
the session and shared between threads.</p><p>The 
<code>tapestry.session-locking-enabled</code> <a  
href="configuration.html">symbol</a> can control this behavior. Setting this to 
true (the default) will yield a more robust application; setting it to false 
may speed up processing for more Ajax intensive applications (but care should 
then be gi
 ven to ensuring that objects shared inside the session are themeselves 
immutable or thread-safe).</p><parameter ac:name="title">AppModule.java 
(partial)</parameter><plain-text-body>  public static void 
contributeApplicationDefaults(MappedConfiguration&lt;String,String&gt; 
configuration)
+</pre>
+</div></div><p></p><h2 id="SessionStorage-ClusteringIssues">Clustering 
Issues</h2>
+
+<p>The Servlet API was designed with the intention that there would be only a 
modest amount of server-side state, and that the stored values would be 
individual numbers and strings, and thus, immutable.</p>
+
+<p>However, many web applications do not use the HttpSession this way, instead 
storing large, mutable objects in the session. This is not a problem for single 
servers, but in a cluster, anything stored in the session must be serialized to 
a bytestream and distributed to other servers within the cluster, and restored 
there.</p>
+
+<p>Most application servers perform that serialization and distribution 
whenever HttpSession.setAttribute() is called. This creates a data consistency 
problem for mutable objects, because if you read a mutable session object, 
change its state, but <em>don't</em> invoke setAttribute(), the changes will be 
isolated to just a single server in the cluster.</p>
+
+<p>Tapestry attempts to solve this: any session-persisted object that is read 
during a request will be re-stored back into the HttpSession at the end of the 
request. This ensures that changed internal state of those mutable objects is 
properly replicated around the cluster.</p>
+
+<p>But while this solution solves the data consistency problem, it does so at 
the expense of performance, since all of those calls to setAttribute() result 
in extra session data being replicated needlessly if the internal state of the 
mutable object hasn't changed.</p>
+
+<p>Tapestry has solutions to this, too:</p>
+
+<h3 
id="SessionStorage-@ImmutableSessionPersistedObjectAnnotation">@ImmutableSessionPersistedObject
 Annotation</h3>
+
+<p>Tapestry knows that Java's String, Number and Boolean classes are 
immutable. Immutable objects do not require a re-store into the session.</p>
+
+<p>You can mark your own session objects as immutable (and thus not requiring 
session replication) using the <a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/annotations/ImmutableSessionPersistedObject.html";>ImmutableSessionPersistedObject</a>
 annotation.</p>
+
+<h3 
id="SessionStorage-OptimizedSessionPersistedObjectInterface">OptimizedSessionPersistedObject
 Interface</h3>
+
+<p>The <a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/OptimizedSessionPersistedObject";>OptimizedSessionPersistedObject</a>
 interface allows an object to control this behavior. An object with this 
interface can track when its mutable state changes. Typically, you should 
extend from the <a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/BaseOptimizedSessionPersistedObject.html";>BaseOptimizedSessionPersistedObject</a>
 base class.</p>
+
+<h3 
id="SessionStorage-SessionPersistedObjectAnalyzerService">SessionPersistedObjectAnalyzer
 Service</h3>
+
+<p>The <a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/SessionPersistedObjectAnalyzer.html";>SessionPersistedObjectAnalyzer</a>
 service is ultimately responsible for determining whether a session persisted 
object is dirty or not (dirty meaning in need of a restore into the session). 
This is an extensible service where new strategies, for new classes, can be 
introduced.</p><h2 id="SessionStorage-SessionLocking">Session 
Locking</h2><p>Starting with version 5.4, by default Tapestry will apply 
locking semantics around access to the HttpSession. Reading attribute names 
occurs with a shared read lock, and getting or setting an attribute upgrades 
the lock to an exclusive write lock. This can tend to serialize threads when a 
number of simultaneous (Ajax) requests from the client arrive. However, many 
implementations of HttpSession are not thread safe, and often mutable 
objects<br clear="none"> are stored in the session and shared betwe
 en threads.</p><p>The <code>tapestry.session-locking-enabled</code> <a  
href="configuration.html">symbol</a> can control this behavior. Setting this to 
true (the default) will yield a more robust application; setting it to false 
may speed up processing for more Ajax intensive applications (but care should 
then be given to ensuring that objects shared inside the session are 
themeselves immutable or thread-safe).</p><div class="code panel pdl" 
style="border-width: 1px;"><div class="codeHeader panelHeader pdl" 
style="border-bottom-width: 1px;"><b>AppModule.java (partial)</b></div><div 
class="codeContent panelContent pdl">
+<pre class="brush: java; gutter: false; theme: Default" 
style="font-size:12px;">  public static void 
contributeApplicationDefaults(MappedConfiguration&lt;String,String&gt; 
configuration)
   {
     configuration.add(SymbolConstants.SESSION_LOCKING_ENABLED, true);
     ...
   }
-</plain-text-body></div>
+</pre>
+</div></div></div>
       </div>
 
       <div class="clearer"></div>

Modified: websites/production/tapestry/content/shadowbuilder-service.html
==============================================================================
--- websites/production/tapestry/content/shadowbuilder-service.html (original)
+++ websites/production/tapestry/content/shadowbuilder-service.html Wed Sep 20 
12:29:16 2017
@@ -27,6 +27,14 @@
       </title>
   <link type="text/css" rel="stylesheet" href="/resources/space.css" />
 
+          <link href='/resources/highlighter/styles/shCoreCXF.css' 
rel='stylesheet' type='text/css' />
+    <link href='/resources/highlighter/styles/shThemeCXF.css' rel='stylesheet' 
type='text/css' />
+    <script src='/resources/highlighter/scripts/shCore.js' 
type='text/javascript'></script>
+          <script src='/resources/highlighter/scripts/shBrushJava.js' 
type='text/javascript'></script>
+        <script>
+      SyntaxHighlighter.defaults['toolbar'] = false;
+      SyntaxHighlighter.all();
+    </script>
   
   <link href="/styles/style.css" rel="stylesheet" type="text/css"/>
 
@@ -36,26 +44,13 @@
 
   <div class="wrapper bs">
 
-        <div id="navigation"><div class="nav"><ul class="alternate"><li><a  
href="index.html">Home</a></li><li><a  href="getting-started.html">Getting 
Started</a></li><li><a  href="documentation.html">Documentation</a></li><li><a  
href="download.html">Download</a></li><li><a  
href="about.html">About</a></li><li><a  class="external-link" 
href="http://www.apache.org/licenses/LICENSE-2.0";>License</a></li><li><a  
href="community.html">Community</a></li><li><a  class="external-link" 
href="http://www.apache.org/security/";>Security</a></li><li><a  
class="external-link" href="http://www.apache.org/";>Apache</a></li><li><a  
class="external-link" 
href="http://www.apache.org/foundation/sponsorship.html";>Sponsorship</a></li><li><a
  class="external-link" 
href="http://www.apache.org/foundation/thanks.html";>Thanks</a></li></ul></div>
-
-</div>
+        <div id="navigation"><div class="nav"><ul class="alternate"><li><a  
href="index.html">Home</a></li><li><a  href="getting-started.html">Getting 
Started</a></li><li><a  href="documentation.html">Documentation</a></li><li><a  
href="download.html">Download</a></li><li><a  
href="about.html">About</a></li><li><a  class="external-link" 
href="http://www.apache.org/licenses/LICENSE-2.0";>License</a></li><li><a  
href="community.html">Community</a></li><li><a  class="external-link" 
href="http://www.apache.org/security/";>Security</a></li><li><a  
class="external-link" href="http://www.apache.org/";>Apache</a></li><li><a  
class="external-link" 
href="http://www.apache.org/foundation/sponsorship.html";>Sponsorship</a></li><li><a
  class="external-link" 
href="http://www.apache.org/foundation/thanks.html";>Thanks</a></li></ul></div></div>
 
           <div id="top">
-            <div id="smallbanner"><div class="searchbox" 
style="float:right;margin: .3em 1em .1em 1em"><span style="color: #999; 
font-size: 90%">Tapestry docs, issues, wikis &amp; blogs:</span>
-<form enctype="application/x-www-form-urlencoded" method="get" 
action="http://tapestry.apache.org/search.html";>
-  <input type="text" name="q">
-  <input type="submit" value="Search">
-</form>
-
-</div>
-
-
-<div class="emblem" style="float:left"><p><a  href="index.html"><span 
class="confluence-embedded-file-wrapper"><img class="confluence-embedded-image 
confluence-external-resource" 
src="http://tapestry.apache.org/images/tapestry_small.png"; 
data-image-src="http://tapestry.apache.org/images/tapestry_small.png";></span></a></p></div>
-
-
-<div class="title" style="float:left; margin: 0 0 0 3em"><h1 
id="SmallBanner-PageTitle">ShadowBuilder Service</h1></div>
-
-</div>
+            <div id="smallbanner"><div class="searchbox" 
style="float:right;margin: .3em 1em .1em 1em"><span style="color: #999; 
font-size: 90%">Tapestry docs, issues, wikis &amp; blogs:</span><form 
enctype="application/x-www-form-urlencoded" method="get" 
action="http://tapestry.apache.org/search.html";> 
+ <input type="text" name="q"> 
+ <input type="submit" value="Search"> 
+</form></div><div class="emblem" style="float:left"><p><a  
href="index.html"><span class="confluence-embedded-file-wrapper"><img 
class="confluence-embedded-image confluence-external-resource" 
src="http://tapestry.apache.org/images/tapestry_small.png"; 
data-image-src="http://tapestry.apache.org/images/tapestry_small.png";></span></a></p></div><div
 class="title" style="float:left; margin: 0 0 0 3em"><h1 
id="SmallBanner-PageTitle">ShadowBuilder Service</h1></div></div>
       <div class="clearer"></div>
       </div>
 
@@ -67,18 +62,48 @@
       </div>
 
       <div id="content">
-                <div id="ConfluenceContent"><p>The <strong>ShadowBuilder 
service</strong> (see the <a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/services/PropertyShadowBuilder.html";>PropertyShadowBuilder</a>
 API) is used to build a special, delegating kind of service implementation 
that, essentially, allows a property of another service to be exposed as its 
own service.</p><parameter ac:name="style">float:right</parameter><parameter 
ac:name="title">Related Articles</parameter><parameter 
ac:name="class">aui-label</parameter><rich-text-body><parameter 
ac:name="showLabels">false</parameter><parameter 
ac:name="showSpace">false</parameter><parameter ac:name="title">Related 
Articles</parameter><parameter ac:name="cql">label = "service-builders" and 
space = currentSpace()</parameter></rich-text-body><p>For example, the 
tapestry-core module provides a Request property as a shadow of the 
RequestGlobals service's request property:</p><para
 meter ac:name="">java</parameter><plain-text-body>public Request build()
+                <div id="ConfluenceContent"><p>The <strong>ShadowBuilder 
service</strong> (see the <a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/services/PropertyShadowBuilder.html";>PropertyShadowBuilder</a>
 API) is used to build a special, delegating kind of service implementation 
that, essentially, allows a property of another service to be exposed as its 
own service.</p><div class="aui-label" style="float:right" title="Related 
Articles"><h3>Related Articles</h3><ul class="content-by-label"><li> 
+  <div> 
+   <span class="icon aui-icon aui-icon-small aui-iconfont-page-default" 
title="Page">Page:</span> 
+  </div> 
+  <div class="details"> 
+   <a  href="shadowbuilder-service.html">ShadowBuilder Service</a> 
+  </div> </li><li> 
+  <div> 
+   <span class="icon aui-icon aui-icon-small aui-iconfont-page-default" 
title="Page">Page:</span> 
+  </div> 
+  <div class="details"> 
+   <a  href="strategybuilder-service.html">StrategyBuilder Service</a> 
+  </div> </li><li> 
+  <div> 
+   <span class="icon aui-icon aui-icon-small aui-iconfont-page-default" 
title="Page">Page:</span> 
+  </div> 
+  <div class="details"> 
+   <a  href="pipelinebuilder-service.html">PipelineBuilder Service</a> 
+  </div> </li><li> 
+  <div> 
+   <span class="icon aui-icon aui-icon-small aui-iconfont-page-default" 
title="Page">Page:</span> 
+  </div> 
+  <div class="details"> 
+   <a  href="chainbuilder-service.html">ChainBuilder Service</a> 
+  </div> </li></ul></div><p>For example, the tapestry-core module provides a 
Request property as a shadow of the RequestGlobals service's request 
property:</p><div class="code panel pdl" style="border-width: 1px;"><div 
class="codeContent panelContent pdl">
+<pre class="brush: java; gutter: false; theme: Default" 
style="font-size:12px;">public Request build()
 {
   return shadowBuilder.build(requestGlobals, "request", Request.class);
-}</plain-text-body><p>(shadowBuilder and requestGlobals are injected into the 
module class instance)</p><p>This can be thought of as similar 
to:</p><parameter ac:name="">java</parameter><plain-text-body>public Request 
build()
+}</pre>
+</div></div><p>(shadowBuilder and requestGlobals are injected into the module 
class instance)</p><p>This can be thought of as similar to:</p><div class="code 
panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
+<pre class="brush: java; gutter: false; theme: Default" 
style="font-size:12px;">public Request build()
 {
   return requestGlobals.getRequest();
-}</plain-text-body><p>However there is a <em>critical</em> difference between 
the two: a shadow property is <em>re-evaluated on each method invocation</em>. 
In the former case, the Request service will always obtain the current value of 
the request property from the per-thread RequestGlobals service. The second 
example is more than likely broken, since it will expose whatever value is in 
the request property of the RequestGlobals <em>at the time the Request service 
implementation is realized</em>.</p><p>Notice that in this example, the Request 
service is a normal singleton. This service can be freely injected into any 
service throughout the framework or application. Invoking methods on this 
service will always delegate to the current thread's request. Callers don't 
have to be aware of this internal delegation; it just happens.</p><h1 
id="ShadowBuilderService-Non-Reflective">Non-Reflective</h1><p>When the shadow 
is created, reflection is used to translate the property name to a metho
 d name. This information is used to build a new class (at runtime) that is 
instantiated as the service implementation.</p><p>A typical method is 
implemented as (approximately):</p><parameter 
ac:name="">java</parameter><plain-text-body>private final RequestGlobals source;
+}</pre>
+</div></div><p>However there is a <em>critical</em> difference between the 
two: a shadow property is <em>re-evaluated on each method invocation</em>. In 
the former case, the Request service will always obtain the current value of 
the request property from the per-thread RequestGlobals service. The second 
example is more than likely broken, since it will expose whatever value is in 
the request property of the RequestGlobals <em>at the time the Request service 
implementation is realized</em>.</p><p>Notice that in this example, the Request 
service is a normal singleton. This service can be freely injected into any 
service throughout the framework or application. Invoking methods on this 
service will always delegate to the current thread's request. Callers don't 
have to be aware of this internal delegation; it just happens.</p><h1 
id="ShadowBuilderService-Non-Reflective">Non-Reflective</h1><p>When the shadow 
is created, reflection is used to translate the property name to a method name.
  This information is used to build a new class (at runtime) that is 
instantiated as the service implementation.</p><p>A typical method is 
implemented as (approximately):</p><div class="code panel pdl" 
style="border-width: 1px;"><div class="codeContent panelContent pdl">
+<pre class="brush: java; gutter: false; theme: Default" 
style="font-size:12px;">private final RequestGlobals source;
 
 public String getParameter(String name)
 {
   return source.getRequest().getParameter(name);
-}</plain-text-body><p>That is, the shadow implementation holds onto the target 
object (in the above example, the RequestGlobals service) and invokes a method 
on it directly, not using reflection, no differently than you would if you 
wrote the code yourself.</p><p>&#160;</p><p></p></div>
+}</pre>
+</div></div><p>That is, the shadow implementation holds onto the target object 
(in the above example, the RequestGlobals service) and invokes a method on it 
directly, not using reflection, no differently than you would if you wrote the 
code yourself.</p><p>&#160;</p><p></p></div>
       </div>
 
       <div class="clearer"></div>


Reply via email to