Modified: 
websites/production/tapestry/content/defining-tapestry-ioc-services.html
==============================================================================
--- websites/production/tapestry/content/defining-tapestry-ioc-services.html 
(original)
+++ websites/production/tapestry/content/defining-tapestry-ioc-services.html 
Sun Apr 26 21:22:55 2020
@@ -76,7 +76,7 @@
 
       <div id="content">
                 <div id="ConfluenceContent"><p>Services consist of two main 
parts: a service interface and a service implementation.</p><p>The service 
interface is how the service will be represented throughout the rest of the 
registry. Since what gets passed around is normally a proxy, you can't expect 
to cast a service object down to the implementation class (you'll see a 
ClassCastException instead). In other words, you should be careful to ensure 
that your service interface is complete, since Tapestry IoC effectively walls 
you off from back doors such as casts.</p><h1 
id="DefiningTapestryIOCServices-ServiceLifeCycle">Service Life 
Cycle</h1><p>Every service has a very specific life cycle.</p><ul><li>Defined: 
The service has a definition (from some module) but has not yet been 
referenced.</li><li>Virtual: The service has been referenced, so a proxy for 
the class has been created.</li><li>Realized: A method on the proxy has been 
invoked, so the service implementation has been instan
 tiated, and any decorators applied.</li><li>Shutdown: The entire Registry has 
been shut down and with it, all the proxies have been 
disabled.</li></ul><p>When the Registry is first created, all modules are 
scanned and the definitions for all services are created.</p><p>Services will 
be referenced by either accessing them using the Registry, or as dependencies 
of other realized services.</p><p>Tapestry IoC waits until the last possible 
moment to <em>realize</em> the service: that's defined as when a method of the 
service is invoked. Tapestry is <em>thread-safe</em>, so even in a heavily 
contested, highly threaded environment (such as a servlet container or 
application server) things <em>Just Work</em>.</p><p><span 
class="confluence-anchor-link" 
id="DefiningTapestryIOCServices-serviceBuilderMethod"></span></p><h1 
id="DefiningTapestryIOCServices-ServiceBuilderMethods">Service Builder 
Methods</h1><p>Tapestry doesn't know how to instantiate and configure your 
service; instead it relies o
 n you to provide the code to do so, in a service builder method, a method 
whose name is (or starts with) "build":</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;">package org.example.myapp.services;
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: java; 
gutter: false; theme: Default" data-theme="Default">package 
org.example.myapp.services;
 
 public class MyAppModule
 {
@@ -86,7 +86,7 @@ public class MyAppModule
   }
 }</pre>
 </div></div><p>Here the service interface is Indexer (presumably inside the 
org.example.myapp.services package, since there isn't an import). Tapestry IoC 
doesn't know about the IndexerImpl class (the service implementation of the 
Indexer service), but it does know about the build() method.</p><p>That's one 
of the great innovations of Tapestry IoC: we don't try to encapsulate in XML or 
annotations all the different ways possible to create a service; those things 
are best expressed in Java code. For a simple case (as here), it would be hard 
for external configuration (again, in XML or Java annotations) to be shorter 
than "new IndexerImpl()".</p><p><em>The above paragraph was written before 
Binding and Autobuilding were introduced.</em></p><p>For more complex and 
realistic scenarios, such as injecting dependencies via the constructor, or 
doing more interest work (such as registering the newly created service for 
events published by some other service), the Java code is simply the most
  direct, flexible, extensible and readable approach.</p><h1 
id="DefiningTapestryIOCServices-BindingandAutobuilding">Binding and 
Autobuilding</h1><p>Tapestry IoC can also <em>autobuild</em> your service. 
Autobuilding is the <em>preferred</em> way to instantiate your 
services.</p><p>Every module may have an optional, static bind() method which 
is passed a <a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/ServiceBinder.html";>ServiceBinder</a>.
 Services may be registered with the container by "binding" a service interface 
to a service implementation:</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;">package org.example.myapp.services;
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: java; 
gutter: false; theme: Default" data-theme="Default">package 
org.example.myapp.services;
 
 import org.apache.tapestry5.ioc.ServiceBinder;
 
@@ -98,7 +98,7 @@ public class MyAppModule
   }
 }</pre>
 </div></div><p>You can make repeated calls to ServiceBinder.bind(), to bind 
additional services.</p><p>You might ask, "which is better, a builder method 
for each service, or a bind() method for the module?" For simple services, 
those that are just an instantiated instance with simple dependencies, binding 
is better than building. That covers at least 90% of all services, so bind 
away!</p><p>There are many cases, however, where constructing a service is more 
than just instantiating a class. Often the new service will (for example) be 
registered as a listener with some other service. In other cases, the 
implementation of the service is generated at runtime. These are where the 
service builder methods are most useful.</p><p>In terms of the evolution of the 
framework, service builder methods came first, and autobuilding was a later 
addition, inspired by the terseness of the <a  class="external-link" 
href="http://code.google.com/p/google-guice/"; rel="nofollow">Guice</a> IoC 
container.</p
 ><p>Following the convention over configuration principle, the autobuilding of 
 >services can be even less verbose. If a service interface is passed as a 
 >single argument to the bind() method, Tapestry will try to find an 
 >implementation in the same package whose name matches the name of the service 
 >interface followed by the suffix <em>Impl</em>.</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;">package org.example.myapp.services;
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: java; 
gutter: false; theme: Default" data-theme="Default">package 
org.example.myapp.services;
 
 import org.apache.tapestry5.ioc.ServiceBinder;
 
@@ -110,28 +110,28 @@ public class MyAppModule
   }
 }</pre>
 </div></div><h1 id="DefiningTapestryIOCServices-ServiceIds">Service 
Ids</h1><p>Every service will have a unique service id.</p><p>When using a 
service builder method, the service id is the <em>simple name</em> of the 
service interface.</p><p>This can be overridden by adding the @<a  
class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/ServiceId.html";>ServiceId</a>
 annotation to the service builder method:</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;">  @ServiceId("FileSystemIndexer")
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: java; 
gutter: false; theme: Default" data-theme="Default">  
@ServiceId("FileSystemIndexer")
   public static Indexer buildIndexer(@InjectService("FileSystem") FileSystem 
fileSystem)
   {
      . . .
   }</pre>
 </div></div><p>Another option is to add the service id to the method name, 
after "build", for 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;">  public static Indexer 
buildFileSystemIndexer(@InjectService("FileSystem") FileSystem fileSystem)
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: java; 
gutter: false; theme: Default" data-theme="Default">  public static Indexer 
buildFileSystemIndexer(@InjectService("FileSystem") FileSystem fileSystem)
   {
      . . .
   }</pre>
 </div></div><p>Here, the service id is "FileSystemIndexer" not 
"Indexer".</p><p>For autobuilt services, the service id can be specified by 
placing the @<a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/ServiceId.html";>ServiceId</a>
 annotation directly on a service implementation class.</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;">  @ServiceId("FileSystemIndexer")
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: java; 
gutter: false; theme: Default" data-theme="Default">  
@ServiceId("FileSystemIndexer")
   public class IndexerImpl implements Indexer
   {
       ...
   }</pre>
 </div></div><p>When the service is bound, the value of the annotation is used 
as id:</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;">  binder.bind(Indexer.class, IndexerImpl.class);</pre>
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: java; 
gutter: false; theme: Default" data-theme="Default">  
binder.bind(Indexer.class, IndexerImpl.class);</pre>
 </div></div><p>This id can be overriden again by calling the method <a  
class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/ServiceBindingOptions.html#withId-java.lang.String-";>withId(String)</a>:</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;">  binder.bind(Indexer.class, 
IndexerImpl.class).withId("FileSystemIndexer");</pre>
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: java; 
gutter: false; theme: Default" data-theme="Default">  
binder.bind(Indexer.class, IndexerImpl.class).withId("FileSystemIndexer");</pre>
 </div></div><h1 
id="DefiningTapestryIOCServices-Injecting_DependenciesInjectingDependencies"><span
 class="confluence-anchor-link" 
id="DefiningTapestryIOCServices-Injecting_Dependencies"></span>Injecting 
Dependencies</h1><p>It's pretty unlikely that your service will be able to 
operate in a total vacuum. It will have other dependencies.</p><p>Dependencies 
are provided to a service in one of several ways:</p><ul><li>As parameters to 
the service builder method</li><li>As parameters to the service implementation 
class' constructor (for autobuilt services)</li><li>As parameters passed to the 
constructor of the service's module class (to be cached inside instance 
variables)</li><li>Directly into fields of the service 
implementation</li></ul><p>For example, let's say the Indexer needs a 
JobScheduler to control when it executes, and a FileSystem to access files and 
store indexes.</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 static Indexer build(JobScheduler scheduler, 
FileSystem fileSystem)
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: java; 
gutter: false; theme: Default" data-theme="Default">  public static Indexer 
build(JobScheduler scheduler, FileSystem fileSystem)
   {
     IndexerImpl indexer = new IndexerImpl(fileSystem);
 
@@ -140,7 +140,7 @@ public class MyAppModule
     return indexer;
   }</pre>
 </div></div><p>Tapestry assumes that parameters to builder methods are 
dependencies; in this example it is able to figure out what services to pass in 
based just on the type (later we'll see how we can fine tune this with 
annotations, when the service type is not sufficient to identify a single 
service).</p><p>This is an example of when you would want to use the service 
builder method, rather than just binding the service interface to the 
implementation class: because we want to do something extra, in this case, 
register the new indexer service with the scheduler.</p><p>Note that we don't 
invoke those service builder methods ... we just "advertise" (via naming 
convention or annotation) that we need the named services. Tapestry IoC will 
provide the necessary proxies and, when we start to invoke methods on those 
proxies, will ensure that the full service, including its interceptors and its 
dependencies, are ready to go. Again, this is done in a thread-safe 
manner.</p><p>What happens i
 f there is more than one service that implements the JobScheduler interface, 
or the FileSystem interface? You'll see a runtime exception, because Tapestry 
is unable to resolve it down to a <em>single</em> service. At this point, it is 
necessary to <em>disambiguate</em> the link between the service interface and 
<em>one</em> service. One approach is to use the @<a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/InjectService.html";>InjectService</a>
 annotation:</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 static Indexer 
build(@InjectService("JobScheduler")
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: java; 
gutter: false; theme: Default" data-theme="Default">  public static Indexer 
build(@InjectService("JobScheduler")
     JobScheduler scheduler,
 
     @InjectService("FileSystem")
@@ -153,7 +153,7 @@ public class MyAppModule
     return indexer;
   }</pre>
 </div></div><p>If you find yourself injecting the same dependencies into 
multiple service builder (or service decorator) methods, you can <a  
href="tapestry-ioc-modules.html">cache dependency injections</a> in your 
module, by defining a constructor. This reduces duplication in your 
module.</p><h1 
id="DefiningTapestryIOCServices-DisambiguationwithMarkerAnnotations">Disambiguation
 with Marker Annotations</h1><p>In the previous example we were faced with a 
problem: multiple versions of the JobScheduler service. They had the same 
service interface but unique service ids. If you try to inject based on type, 
the service to inject will be ambiguous. Tapestry will throw an exception 
(identifying the parameter type and the matching services that implement that 
type).</p><p>The problem is that when injecting a JobScheduler into some other 
service we need to know which <em>one</em> to inject. Rather than using the 
service id, another approach is to use a <em>marker annotation</em>.</p><p>You m
 ay optionally link a service implementation with a marker 
annotation.</p><p>For example, maybe you have one JobScheduler implementation 
where the jobs are spread across a number of nodes in a cluster, and you have 
another JobScheduler where the jobs are all executed exclusively in the current 
process.</p><p>We can associate those two JobSchedulers with two 
annotations.</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;">@Target(
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: java; 
gutter: false; theme: Default" data-theme="Default">@Target(
 { PARAMETER, FIELD })
 @Retention(RUNTIME)
 @Documented
@@ -181,7 +181,7 @@ public class MyModule
   }
 }</pre>
 </div></div><p>Notice that the marker annotations have no attributes. Further, 
we support markers on fields (for use in Tapestry components) as well as 
parameters.</p><p>To get the right version of the service, you use one of the 
annotations:</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 MyServiceImpl implements MyService
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: java; 
gutter: false; theme: Default" data-theme="Default">public class MyServiceImpl 
implements MyService
 {
   private final JobScheduler jobScheduler;
 
@@ -193,13 +193,13 @@ public class MyModule
   . . .
 }  </pre>
 </div></div><p>The @Clustered annotation on the parameter is combined with the 
parameter type (JobScheduler) to find the exact service 
implementation.</p><p>Why is this better than using the service id? It's more 
refactoring-safe. Service ids can change, which can break your services. 
However, using an IDE to rename or move an annotation class or service 
interface will be able to update all the uses of the annotation or 
interface.</p><p>With a service builder method, you use the @<a  
class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/Marker.html";>Marker</a>
 annotation:</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;">  @Marker(Clustered.class)
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: java; 
gutter: false; theme: Default" data-theme="Default">  @Marker(Clustered.class)
   public JobScheduler buildClusteredJobScheduler()
   {
     return . . .;
   }</pre>
 </div></div><p>The @Marker annotation may also be placed on an implementation 
class, which means that you may omit the call to withMarker() inside the bind() 
method.</p><p>Finally, the point of injection may have multiple marker 
annotations; only services that are marked with <em>all</em> those markers will 
be considered for injection. Each marker annotation creates an increasingly 
narrow subset from the set of all possible services (compatible with the 
indicated dependency type).</p><h1 
id="DefiningTapestryIOCServices-LocalDependencies">Local Dependencies</h1><p>A 
special marker interface, @<a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/Local.html";>Local</a>,
 indicates a dependency that should only be resolved using services from within 
<em>the same module</em>.</p><p>@Local can also be combined with other marker 
annotations.</p><h1 
id="DefiningTapestryIOCServices-InjectingDependenciesforAutobuiltServices">Injecting
 D
 ependencies for Autobuilt Services</h1><p>With autobuilt services, there's no 
service builder method in which to specify injections.</p><p>Instead, the 
injections occur on <em>constructor</em> for the implementation class:</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;">package org.example.myapp.services;
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: java; 
gutter: false; theme: Default" data-theme="Default">package 
org.example.myapp.services;
 
 import org.apache.tapestry5.ioc.annotations.InjectService;
 
@@ -215,7 +215,7 @@ public class IndexerImpl implements Inde
   . . .
 }</pre>
 </div></div><p>If the class has multiple constructors, the constructor with 
the <em>most</em> parameters will be invoked. Alternately, you may mark a 
single constructor with the Inject annotation, and Tapestry will use 
<em>that</em> constructor specifically, ignoring all other 
constructors.</p><p>Note how we are using final fields for our dependencies; 
this is generally a Good Idea. These services will often execute inside a 
multi-threaded environment, such as a web application, and the use of final 
fields inside a constructor ensures that the fields will be properly published 
(meaning, "visible to other threads") in accordance with the Java Memory 
Model.</p><p>Once thing that is not a good idea is to pass in another service, 
such as JobScheduler in the previous example, and pass <code>this</code> from a 
constructor:</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;">package org.example.myapp.services;
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: java; 
gutter: false; theme: Default" data-theme="Default">package 
org.example.myapp.services;
 
 import org.apache.tapestry5.ioc.annotations.InjectService;
 
@@ -235,7 +235,7 @@ public class IndexerImpl implements Inde
   . . .
 }</pre>
 </div></div><p>Understanding why this is a bad idea involves a long detour 
into inner details of the Java Memory Model. The short form is that other 
threads may end up invoking methods on the IndexerImpl instance, and its fields 
(even though they are final, even though they appear to already have been set) 
may be uninitialized.</p><h1 
id="DefiningTapestryIOCServices-FieldInjection">Field Injection</h1><p>The @<a  
class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/Inject.html";>Inject</a>
 and @<a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/InjectService.html";>InjectService</a>
 annotations may be used on instance fields of a service implementation class, 
as an alternative to passing dependencies of the service implementation in via 
the constructor.</p><p>Note that only dependencies are settable this way; if 
you want resources, including the service's <a  href="tapes
 try-ioc-configuration.html">configuration</a>, you must pass those through the 
constructor. You <em>are</em> free to mix and match, injecting partially with 
field injection and partially with constructor injection.</p><p>Caution: 
injection via fields uses reflection to make the fields accessible. In 
addition, it may not be as thread-safe as using the constructor to assign to 
final fields.</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;">package org.example.myapp.services;
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: java; 
gutter: false; theme: Default" data-theme="Default">package 
org.example.myapp.services;
 
 import org.apache.tapestry5.ioc.annotations.InjectService;
 
@@ -247,11 +247,11 @@ public class IndexerImpl implements Inde
   . . .
 }</pre>
 </div></div><h1 
id="DefiningTapestryIOCServices-ServiceScopeDefiningServiceScope"><span 
class="confluence-anchor-link" 
id="DefiningTapestryIOCServices-ServiceScope"></span>Defining Service 
Scope</h1><p>Each service has a <em>scope</em> that controls when the service 
implementation is instantiated. There are two built in scopes: "singleton" and 
"perthread", but more can be added.</p><p>Service scope is specified using the 
@<a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/Scope.html";>Scope</a>
 annotation, which is attached to a builder method, or to the service 
implementation class. When this annotation is not present, the default scope, 
"singleton" is used.</p><h3 
id="DefiningTapestryIOCServices-singleton">singleton</h3><p>Most services use 
the default scope, "singleton". With this scope a <em>proxy</em> is created 
when the service is first referenced. By reference, we mean any situation in 
which the service is requested 
 by name, such as using the @InjectService annotation on a service builder 
method, or by using the <a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/Registry.html";>Registry</a>
 API from outside the container.</p><p>In any case, the service proxy will only 
create the service implementation when a method on the service interface is 
invoked. Until then, the service can be thought of as "virtual". As the first 
method is invoked, the service builder method is invoked, then any service 
decorations occur. This construction process, called "realization", occurs only 
once.</p><p>You should be aware when writing services that your code must be 
thread safe; any service you define could be invoked simultaneously by multiple 
threads. This is rarely an issue in practice, since most services take input, 
use local variables, and invoke methods on other services, without making use 
of non-final instance variables. The few instance variables in a servi
 ce implementation are usually references to other Tapestry IoC 
services.</p><h3 
id="DefiningTapestryIOCServices-perthread">perthread</h3><p>The perthread 
service scope exists primarily to help multi-threaded servlet applications, 
though it has other applications.</p><p>With perthread, the service proxy will 
delegate to a local service instance that is associated with the current 
thread. Two different threads, invoking methods on the same proxy, will 
ultimately be invoking methods on two different service instances, each 
reserved to their own thread.</p><p>This is useful when a service needs to keep 
request specific state, such as information extracted from the 
HttpServletRequest (in a web application). The default singleton model would 
not work in such a multithreaded environment. Using perthread on select 
services allows state to be isolated to those services. Because the dispatch 
occurs <em>inside</em> the proxy, you can treat the service as a global, like 
any other.</p><p>You wil
 l see that your service builder method is invoked more than once. It is 
invoked in each thread where the perthread service is used.</p><p>At the end of 
the request, the Registry's cleanupThread() method is invoked; it will discard 
any perthread service implementations for the current 
thread.</p><p><strong>Caution:</strong> A common technique in Tapestry IoC is 
to have a service builder method register a core service implementation as an 
event listener with some event hub service. With non-singleton objects, this 
can cause a number of problems; the event hub will hold a reference to the 
per-thread instance, even after that per-thread instance has been cleaned up 
(discarded by the inner proxy). Simply put, this is a pattern to avoid. For the 
most part, perthread services should be simple holders of data specific to a 
thread or a request, and should not have overly complex relationships with the 
other services in the registry.</p><h1 
id="DefiningTapestryIOCServices-DefiningthescopeofAu
 tobuiltServices">Defining the scope of Autobuilt Services</h1><p>There are two 
options for defining the scope for an autobuilt service.</p><p>The service 
implementation class may include the @<a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/Scope.html";>Scope</a>
 annotation. This is generally the preferred way to specify scope.</p><p>In 
addition, it is possible to specify the scope when binding the 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;">  bind(MyServiceInterface.class, 
MyServiceImpl.class).scope(ScopeConstants.PERTHREAD);</pre>
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: java; 
gutter: false; theme: Default" data-theme="Default">  
bind(MyServiceInterface.class, 
MyServiceImpl.class).scope(ScopeConstants.PERTHREAD);</pre>
 </div></div><h1 id="DefiningTapestryIOCServices-EagerLoadingServices">Eager 
Loading Services</h1><p>Services are normally created only as needed (per the 
scope discussion above).</p><p>This can be tweaked slightly; by adding the @<a  
class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/EagerLoad.html";>EagerLoad</a>
 annotation to the service builder method, Tapestry will instantiate the 
service when the Registry is first created.</p><p>This will cause the service 
builder method to be invoked, as well as any service decorator 
methods.</p><p>This feature is used when a service manages a resource, such as 
a thread, that needs to be created as soon as the application starts up. 
Another common example is a service that listens for events produced by a 
second service; the first service may need to be created, and start listening, 
before any of its service methods are invoked (which would normally trigger the 
instantiation of the servic
 e).</p><p>Many services may be annotated with @EagerLoad; the order in which 
services are created is not defined.</p><p>With the perthread scope, the 
service builder method will not be invoked (this won't happen until a service 
method is invoked), but the decorators for the service will be created.</p><h1 
id="DefiningTapestryIOCServices-EagerLoadingAutobuiltServices">Eager Loading 
Autobuilt Services</h1><p>As with service scope, there are two options for 
indicating that an autobuilt service should be eagerly loaded.</p><p>The 
service implementation class may include the @EagerLoad annotation.</p><p>You 
may also specify eager loading explicitly when binding the 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;">  bind(MyServiceInterface.class, 
MyServiceImpl.class).eagerLoad();</pre>
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: java; 
gutter: false; theme: Default" data-theme="Default">  
bind(MyServiceInterface.class, MyServiceImpl.class).eagerLoad();</pre>
 </div></div><h1 id="DefiningTapestryIOCServices-InjectingResources">Injecting 
Resources</h1><p>In addition to injecting services, Tapestry will key off of 
the parameter type to allow other things to be 
injected.</p><ul><li>java.lang.String: unique id for the service</li><li><a  
class="external-link" href="http://www.slf4j.org/api/org/slf4j/Logger.html"; 
rel="nofollow">org.slf4j.Logger</a>: logger for the 
service</li><li>java.lang.Class: service interface implemented by the service 
to be constructed</li><li><a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/ServiceResources.html";>ServiceResources</a>:
 access to other services</li></ul><p>No annotation is needed for these 
cases.</p><p>See also <a  href="defining-tapestry-ioc-services.html">service 
configuration</a> for additional special cases of resources that can be 
injected.</p><p>Note: resources may not be injected into fields, they are 
injectable only via method or constructor param
 eters.</p><p>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;">  public static Indexer build(String serviceId, Log 
serviceLog,
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: java; 
gutter: false; theme: Default" data-theme="Default">  public static Indexer 
build(String serviceId, Log serviceLog,
      JobScheduler scheduler, FileSystem fileSystem)
   {
     IndexerImpl indexer = new IndexerImpl(serviceLog, fileSystem);
@@ -261,7 +261,7 @@ public class IndexerImpl implements Inde
     return indexer;
   }</pre>
 </div></div><p>The order of parameters is completely irrelevant. They can come 
first or last or be interspersed however you like.</p><p>Injecting in the 
ServiceResources can be handy when you want to calculate the name of a service 
dependency on the fly. However, in the general case (where the id of service 
dependencies is known at build time), it is easier to use the @InjectService 
annotation.</p><p>The Log's name (used when configuring logging settings for 
the service) consists of the module class name and the service id seperated by 
a period, i.e. "org.example.myapp.MyModule.Indexer".</p><p>Further, 
ServiceResources includes an autobuild() method that allows you to easily 
trigger the construction of a class, including dependencies. Thus the previos 
example could be rewritten as:</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 static Indexer build(ServiceResources 
resources, JobScheduler jobScheduler)
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: java; 
gutter: false; theme: Default" data-theme="Default">  public static Indexer 
build(ServiceResources resources, JobScheduler jobScheduler)
   {
     IndexerImpl indexer = resources.autobuild(IndexerImpl.class);
 
@@ -270,7 +270,7 @@ public class IndexerImpl implements Inde
     return indexer;
   }</pre>
 </div></div><p>This works the exact same way with autobuilt services, except 
that the parameters of the service implementation constructor are considered, 
rather than the parameters of the service builder method.</p><p>The 
@InjectService annotation takes precedence over these resources.</p><p>If the 
@InjectService annotation is not present, and the parameter type does not 
exactly match a resource type, then <a  href="object-providers.html">object 
injection</a> occurs. Object injection will find the correct object to inject 
based on a number of (extensible) factors, including the parameter type and any 
additional annotations on the parameter.</p><p>Every once and a while, you'll 
have a conflict between a resource type and an object injection. For example, 
the following does not work as expected:</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 static Indexer build(String serviceId, Log 
serviceLog,
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: java; 
gutter: false; theme: Default" data-theme="Default">  public static Indexer 
build(String serviceId, Log serviceLog,
      JobScheduler scheduler, FileSystem fileSystem,
      @Value("${index-alerts-email}")
      String alertEmail)
@@ -282,7 +282,7 @@ public class IndexerImpl implements Inde
     return indexer;
   }</pre>
 </div></div><p>It doesn't work because type String always gets the service id, 
as a resource (as with the serviceId parameter). In order to get this to work, 
we need to turn off the resource injection for the alertEmail parameter. That's 
what the @<a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/Inject.html";>Inject</a>
 annotation does:</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 static Indexer build(String serviceId, Log 
serviceLog,
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: java; 
gutter: false; theme: Default" data-theme="Default">  public static Indexer 
build(String serviceId, Log serviceLog,
      JobScheduler scheduler, FileSystem fileSystem,
      @Inject @Value("${index-alerts-email}")
      String alertEmail)
@@ -294,7 +294,7 @@ public class IndexerImpl implements Inde
     return indexer;
   }</pre>
 </div></div><p>Here, the alertEmail parameter will receive the configured 
alerts email (see <span class="confluence-link">the </span><a  
href="symbols.html"><span class="confluence-link">symbols 
documentation</span></a> for more about this syntax) rather than the service 
id.</p><h1 id="DefiningTapestryIOCServices-BindingServiceBuilders">Binding 
ServiceBuilders</h1><p>Yet another option is available: instead of binding an 
interface to a implemention class, you can bind a service to a <a  
class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/ServiceBuilder.html";>ServiceBuilder</a>,
 a callback used to create the service implementation. This is very useful in 
very rare circumstances.</p><h1 
id="DefiningTapestryIOCServices-BuiltinServices">Builtin Services</h1><p>A few 
services within the Tapestry IOC Module are "builtin"; there is no service 
builder method in the <a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apac
 he/tapestry5/ioc/services/TapestryIOCModule.html">TapestryIOCModule</a> 
class.</p><div class="table-wrap"><table class="confluenceTable"><tbody><tr><td 
colspan="1" rowspan="1" class="confluenceTd"><p><strong>Service 
Id</strong></p></td><td colspan="1" rowspan="1" 
class="confluenceTd"><p><strong>Service Interface</strong></p></td></tr><tr><td 
colspan="1" rowspan="1" class="confluenceTd"><p>ClassFactory</p></td><td 
colspan="1" rowspan="1" class="confluenceTd"><p><a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/services/ClassFactory.html";>ClassFactory</a></p></td></tr><tr><td
 colspan="1" rowspan="1" class="confluenceTd"><p>LoggerSource</p></td><td 
colspan="1" rowspan="1" class="confluenceTd"><p><a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/LoggerSource.html";>LoggerSource</a></p></td></tr><tr><td
 colspan="1" rowspan="1" 
class="confluenceTd"><p>RegistryShutdownHub</p></td><td colspan=
 "1" rowspan="1" class="confluenceTd"><p><a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/services/RegistryShutdownHub.html";>RegistryShutdownHub</a></p></td></tr><tr><td
 colspan="1" rowspan="1" class="confluenceTd"><p>PerthreadManager</p></td><td 
colspan="1" rowspan="1" class="confluenceTd"><p><a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/services/PerthreadManager.html";>PerthreadManager</a></p></td></tr></tbody></table></div><p>Consult
 the JavaDoc for each of these services to identify under what circumstances 
you'll need to use them.</p><h1 
id="DefiningTapestryIOCServices-MutuallyDependentServices">Mutually Dependent 
Services</h1><p>One of the benefits of Tapestry IoC's proxy-based approach to 
just-in-time instantiation is the automatic support for mutually dependent 
services. For example, suppose that the Indexer and the FileSystem needed to 
talk directly to each other. Normally
 , this would cause a "chicken-and-the-egg" problem: which one to create 
first?</p><p>With Tapestry IoC, this is not even considered a special 
case:</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 static Indexer buildIndexer(JobScheduler 
scheduler, FileSystem fileSystem)
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: java; 
gutter: false; theme: Default" data-theme="Default">  public static Indexer 
buildIndexer(JobScheduler scheduler, FileSystem fileSystem)
   {
     IndexerImpl indexer = new IndexerImpl(fileSystem);
 

Modified: websites/production/tapestry/content/developer-bible.html
==============================================================================
--- websites/production/tapestry/content/developer-bible.html (original)
+++ websites/production/tapestry/content/developer-bible.html Sun Apr 26 
21:22:55 2020
@@ -84,56 +84,58 @@
 
 
 
+
+
 <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>
+                <span class="icon aui-icon content-type-page" 
title="Page">Page:</span>        </div>
 
         <div class="details">
-                        <a  href="building-tapestry-from-source.html">Building 
Tapestry from Source</a>
+                        <a  href="developer-information.html">Developer 
Information</a>
                 
                         
                     </div>
     </li><li>
         <div>
-                <span class="icon aui-icon aui-icon-small 
aui-iconfont-page-default" title="Page">Page:</span>        </div>
+                <span class="icon aui-icon content-type-page" 
title="Page">Page:</span>        </div>
 
         <div class="details">
-                        <a  href="version-numbers.html">Version Numbers</a>
+                        <a  href="release-process.html">Release Process</a>
                 
                         
                     </div>
     </li><li>
         <div>
-                <span class="icon aui-icon aui-icon-small 
aui-iconfont-page-default" title="Page">Page:</span>        </div>
+                <span class="icon aui-icon content-type-page" 
title="Page">Page:</span>        </div>
 
         <div class="details">
-                        <a  href="developer-bible.html">Developer Bible</a>
+                        <a  href="building-tapestry-from-source.html">Building 
Tapestry from Source</a>
                 
                         
                     </div>
     </li><li>
         <div>
-                <span class="icon aui-icon aui-icon-small 
aui-iconfont-page-default" title="Page">Page:</span>        </div>
+                <span class="icon aui-icon content-type-page" 
title="Page">Page:</span>        </div>
 
         <div class="details">
-                        <a  href="release-process.html">Release Process</a>
+                        <a  href="version-numbers.html">Version Numbers</a>
                 
                         
                     </div>
     </li><li>
         <div>
-                <span class="icon aui-icon aui-icon-small 
aui-iconfont-page-default" title="Page">Page:</span>        </div>
+                <span class="icon aui-icon content-type-page" 
title="Page">Page:</span>        </div>
 
         <div class="details">
-                        <a  href="developer-information.html">Developer 
Information</a>
+                        <a  href="developer-bible.html">Developer Bible</a>
                 
                         
                     </div>
     </li><li>
         <div>
-                <span class="icon aui-icon aui-icon-small 
aui-iconfont-page-default" title="Page">Page:</span>        </div>
+                <span class="icon aui-icon content-type-page" 
title="Page">Page:</span>        </div>
 
         <div class="details">
                         <a  href="confluence-site-setup.html">Confluence Site 
Setup</a>
@@ -144,8 +146,8 @@
 </div>
 
 
-<h2 id="DeveloperBible-IDEChoices">IDE Choices</h2><h3 
id="DeveloperBible-IntelliJ">IntelliJ</h3><p>It's a free license for all 
committers and it's just better. Yes, the first few days can be an unpleasant 
fumble because everything is almost, but not quite, familiar. Pretty soon 
you'll love IDEA and recognize that Eclipse has been bending you over and doing 
unspeakable things.</p><p>There are shared code formatting settings in the <a  
class="external-link" 
href="https://git-wip-us.apache.org/repos/asf?p=tapestry-5.git;a=tree;f=support";>support
 directory</a> (idea-settings.jar). This will prevent unexpected conflicts due 
to formatting.</p><h3 id="DeveloperBible-Eclipse">Eclipse</h3><p>Howard uses 
this ... because he can't manage to switch IDEs constantly (he uses Eclipse for 
training). Lately its gotten better.</p><p>As with IntelliJ, there are shared 
code formatting settings for Eclipse in the <a  class="external-link" 
href="https://git-wip-us.apache.org/repos/asf?p=tapestry-5.git;a
 =tree;f=support">support directory</a> (tapestry-indent-eclipse.xml).</p><h2 
id="DeveloperBible-Copyrights">Copyrights</h2><p>All source files should have 
the ASF copyright comment on top, except where such a comment would interfere 
with its behavior. For example, component template files omit the 
comment.</p><p>As you make changes to files, update the copyright to add the 
current year to the list. The goal is that the copyright notice includes the 
year in which files change. When creating a new file, don't back date the 
copyright year ... start with the current year. Try not to change the copyright 
year on files that haven't actually changed.</p><p>IntelliJ has a great 
comparison view: Cmd-9 to see the local changes, the Cmd-D to see the 
differences. You can whip through the changes (using Cmd-forward arrow) and 
make sure copyrights are up to date as you review the changes prior to a 
commit.</p><h2 id="DeveloperBible-CommitMessages">Commit Messages</h2><p>Always 
provide a commit me
 ssage. Howard generally tries to work off the JIRA, so his commit message is 
often:</p><blockquote><p>TAP5-1234: Make the Foo Widget more 
Ajax-tastic!</p></blockquote><p>It is <em>very important</em> to include the 
JIRA issue id in the commit. This is used in many places: JIRA links issues to 
the Git&#160;commits for that issue (very handy for seeing what changed as part 
of a bug fix). The Hudson CI server does as well, and will actually link 
Git&#160;commits to issues after succesfully building.</p><h2 
id="DeveloperBible-JIRAProcedures">JIRA Procedures</h2><p>All Tapestry 
committers should be registerred with JIRA and part of the tapestry-developers 
JIRA group.</p><p>Every committer is invited to look at the list of <a  
class="external-link" 
href="https://issues.apache.org/jira/secure/IssueNavigator.jspa?mode=hide&amp;requestId=12317068";>'Review
 for closing'</a> issues and review them as it contains probably outdated or no 
more valid issues.</p><p>There's also a list of all <a  cla
 ss="external-link" 
href="https://issues.apache.org/jira/secure/IssueNavigator.jspa?mode=hide&amp;requestId=12316792";>Open</a>
 issue about the project.</p><p>Ideally, we would always work top priortity to 
low priority. Howard sometimes jump out of order, if there's something cool to 
work on that fits in an available time slot. Alternately, you are always 
allowed to change the priority of a bug before or as you work it.</p><p>As a 
general rule issues which are "<em>Invalid</em>" or "<em>Won't</em> 
<em>Fix</em>" shouldn't have a "<em>Fix</em> <em>version</em>".</p><h3 
id="DeveloperBible-Startingwork">Starting work</h3><p>When you start to work on 
an issue, make sure it is <em>assigned to you</em> and use the <em>start 
progress</em> option.</p><p>Add comments about the state of the fix, or the 
challenges in creating a fix. This often spurs the Issue's adder to<br 
clear="none"> provide more details.</p><p>Update the issue description to make 
it more legible and more precise if needed, i.
 e., "NPE in CheckUpdates" might become "NullPointerException when checking for 
updates to files that have been deleted". Verbose is good.</p><h3 
id="DeveloperBible-Closingbugs">Closing bugs</h3><p>Is it a bug fix without 
tests? <strong>No.</strong> A good plan is to write a test that fails then work 
the code until the test passes. Often code works in a unit test but fails 
unexpectedly in an integration test. As the G-Man says <em>"Expect unforeseen 
consequences"</em>.</p><p>When you check in a fix, you should 
<strong>close</strong> the issue and make sure the <strong>fix release</strong> 
is correct.</p><p>We're playing fast and loose &#8211; a better procedure would 
be to mark the bug resolved and verify the fix before closing it. That's ok, we 
have a community to double check our work <img class="emoticon emoticon-smile" 
src="https://cwiki.apache.org/confluence/s/en_GB/5997/6f42626d00e36f53fe51440403446ca61552e2a2.1/_/images/icons/emoticons/smile.png";
 data-emoticon-name="smile" alt
 ="(smile)">.</p><p>For anything non-trivial, wait for the Hudson CI server to 
build. It catches a lot of things ... such as files that were not added to Git. 
And even IntelliJ has a bit of trouble with wildly refactored code. Hudson will 
catch all that.</p><h3 id="DeveloperBible-Invalidissuesandduplicates">Invalid 
issues and duplicates</h3><p>Always provide comments about why_ an issue is 
invalid (<em>"A Ruby implementation of Tapestry is out of scope for the 
project."</em>), or at least, a link to the duplicate issues.</p><p>Consider 
writing new tests to prove that an issue is not valid and then leave the tests 
in place &#8211; then close the bug as invalid.</p><p>Close the issue but 
<em>make sure the fix release is blank</em>. Otherwise, the issue <em>will be 
listed in the release notes</em>, which we don't want.</p><h2 
id="DeveloperBible-Publicvs.Private/Internal">Public vs. 
Private/Internal</h2><p>This is a real big deal. As long as code is in the 
internal package, we have a hig
 h degree of carte-blanche to change it. As soon as code is public, we become 
handcuffed to backwards compatibility.</p><p><em>Interfaces are public, 
implementations are private</em>. You can see this is the bulk of the code, 
where org.apache.tapestry5.services is almost all interfaces and the 
implementations are in org.apache.tapestry5.internal.services.</p><p>Many more 
services have both the interface and the implementation in 
org.apache.tapestry5.internal.services.</p><p>We absolutely <em>do not</em> 
want to make Page or ComponentPageElement public. You will often see public 
service facades that take a page name as a method parameter, and convert it to 
a page instance before invoking methods on internal services.</p><h2 
id="DeveloperBible-EvolvingComponents">Evolving Components</h2><p>We do not 
have a specific plan for this yet. Future Tapestry 5 will add features to allow 
clean renames of parameters, and a way to deprecated and eventually remove 
components.</p><h2 id="DeveloperBi
 ble-EvolvingInterfaces">Evolving Interfaces</h2><p>Tapestry uses interfaces 
quite extensively.</p><p>Interfaces fall into two categories: service 
interfaces called by user code, and interfaces implemented by user 
code.</p><p>Internal interfaces may be changed at any time. That's why so much 
is kept internal.</p><h3 id="DeveloperBible-ServiceInterfaces">Service 
Interfaces</h3><p>New methods may be added if absolutely necessary, but this 
should be avoided if at all possible. Don't forget the <code>@since</code> 
Javadoc annotation.</p><p>Consider having a stable public facade service whose 
implementation calls into one or more internal service.</p><h3 
id="DeveloperBible-UserInterfaces">User Interfaces</h3><p>These should be 
frozen, no changes once released. Failure to do so causes <em>non-backwards 
compatible upgrade problems</em>; that is, classes that implement the (old) 
interface are suddenly invalid, missing methods from the (new) 
interface.</p><p>Consider introducing a new interfa
 ce that extends the old one and adds new methods. Make sure you support 
both.</p><p>You can see this with ServiceDef and ServiceDef2 (which extends 
ServiceDef). Yes this can be a bit ugly.</p><p>Howard uses utility methods that 
convert from ServiceDef to ServiceDef2, adding a wrapper implementation around 
a ServiceDef instance if necessary:</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 static ServiceDef2 toServiceDef2(final 
ServiceDef sd)
+<h2 id="DeveloperBible-IDEChoices">IDE Choices</h2><h3 
id="DeveloperBible-IntelliJ">IntelliJ</h3><p>It's a free license for all 
committers and it's just better. Yes, the first few days can be an unpleasant 
fumble because everything is almost, but not quite, familiar. Pretty soon 
you'll love IDEA and recognize that Eclipse has been bending you over and doing 
unspeakable things.</p><p>There are shared code formatting settings in the <a  
class="external-link" 
href="https://git-wip-us.apache.org/repos/asf?p=tapestry-5.git;a=tree;f=support";>support
 directory</a> (idea-settings.jar). This will prevent unexpected conflicts due 
to formatting.</p><h3 id="DeveloperBible-Eclipse">Eclipse</h3><p>Howard uses 
this ... because he can't manage to switch IDEs constantly (he uses Eclipse for 
training). Lately its gotten better.</p><p>As with IntelliJ, there are shared 
code formatting settings for Eclipse in the <a  class="external-link" 
href="https://git-wip-us.apache.org/repos/asf?p=tapestry-5.git;a
 =tree;f=support">support directory</a> (tapestry-indent-eclipse.xml).</p><h2 
id="DeveloperBible-Copyrights">Copyrights</h2><p>All source files should have 
the ASF copyright comment on top, except where such a comment would interfere 
with its behavior. For example, component template files omit the 
comment.</p><p>As you make changes to files, update the copyright to add the 
current year to the list. The goal is that the copyright notice includes the 
year in which files change. When creating a new file, don't back date the 
copyright year ... start with the current year. Try not to change the copyright 
year on files that haven't actually changed.</p><p>IntelliJ has a great 
comparison view: Cmd-9 to see the local changes, the Cmd-D to see the 
differences. You can whip through the changes (using Cmd-forward arrow) and 
make sure copyrights are up to date as you review the changes prior to a 
commit.</p><h2 id="DeveloperBible-CommitMessages">Commit Messages</h2><p>Always 
provide a commit me
 ssage. Howard generally tries to work off the JIRA, so his commit message is 
often:</p><blockquote><p>TAP5-1234: Make the Foo Widget more 
Ajax-tastic!</p></blockquote><p>It is <em>very important</em> to include the 
JIRA issue id in the commit. This is used in many places: JIRA links issues to 
the Git&#160;commits for that issue (very handy for seeing what changed as part 
of a bug fix). The Hudson CI server does as well, and will actually link 
Git&#160;commits to issues after succesfully building.</p><h2 
id="DeveloperBible-JIRAProcedures">JIRA Procedures</h2><p>All Tapestry 
committers should be registerred with JIRA and part of the tapestry-developers 
JIRA group.</p><p>Every committer is invited to look at the list of <a  
class="external-link" 
href="https://issues.apache.org/jira/secure/IssueNavigator.jspa?mode=hide&amp;requestId=12317068";>'Review
 for closing'</a> issues and review them as it contains probably outdated or no 
more valid issues.</p><p>There's also a list of all <a  cla
 ss="external-link" 
href="https://issues.apache.org/jira/secure/IssueNavigator.jspa?mode=hide&amp;requestId=12316792";>Open</a>
 issue about the project.</p><p>Ideally, we would always work top priortity to 
low priority. Howard sometimes jump out of order, if there's something cool to 
work on that fits in an available time slot. Alternately, you are always 
allowed to change the priority of a bug before or as you work it.</p><p>As a 
general rule issues which are "<em>Invalid</em>" or "<em>Won't</em> 
<em>Fix</em>" shouldn't have a "<em>Fix</em> <em>version</em>".</p><h3 
id="DeveloperBible-Startingwork">Starting work</h3><p>When you start to work on 
an issue, make sure it is <em>assigned to you</em> and use the <em>start 
progress</em> option.</p><p>Add comments about the state of the fix, or the 
challenges in creating a fix. This often spurs the Issue's adder to<br 
clear="none"> provide more details.</p><p>Update the issue description to make 
it more legible and more precise if needed, i.
 e., "NPE in CheckUpdates" might become "NullPointerException when checking for 
updates to files that have been deleted". Verbose is good.</p><h3 
id="DeveloperBible-Closingbugs">Closing bugs</h3><p>Is it a bug fix without 
tests? <strong>No.</strong> A good plan is to write a test that fails then work 
the code until the test passes. Often code works in a unit test but fails 
unexpectedly in an integration test. As the G-Man says <em>"Expect unforeseen 
consequences"</em>.</p><p>When you check in a fix, you should 
<strong>close</strong> the issue and make sure the <strong>fix release</strong> 
is correct.</p><p>We're playing fast and loose &#8211; a better procedure would 
be to mark the bug resolved and verify the fix before closing it. That's ok, we 
have a community to double check our work <img class="emoticon emoticon-smile" 
src="https://cwiki.apache.org/confluence/s/-7iq2vk/8301/13280cd41a592ca5883bbc1ae415b58671505365/_/images/icons/emoticons/smile.svg";
 data-emoticon-name="smile" alt
 ="(smile)">.</p><p>For anything non-trivial, wait for the Hudson CI server to 
build. It catches a lot of things ... such as files that were not added to Git. 
And even IntelliJ has a bit of trouble with wildly refactored code. Hudson will 
catch all that.</p><h3 id="DeveloperBible-Invalidissuesandduplicates">Invalid 
issues and duplicates</h3><p>Always provide comments about why_ an issue is 
invalid (<em>"A Ruby implementation of Tapestry is out of scope for the 
project."</em>), or at least, a link to the duplicate issues.</p><p>Consider 
writing new tests to prove that an issue is not valid and then leave the tests 
in place &#8211; then close the bug as invalid.</p><p>Close the issue but 
<em>make sure the fix release is blank</em>. Otherwise, the issue <em>will be 
listed in the release notes</em>, which we don't want.</p><h2 
id="DeveloperBible-Publicvs.Private/Internal">Public vs. 
Private/Internal</h2><p>This is a real big deal. As long as code is in the 
internal package, we have a hig
 h degree of carte-blanche to change it. As soon as code is public, we become 
handcuffed to backwards compatibility.</p><p><em>Interfaces are public, 
implementations are private</em>. You can see this is the bulk of the code, 
where org.apache.tapestry5.services is almost all interfaces and the 
implementations are in org.apache.tapestry5.internal.services.</p><p>Many more 
services have both the interface and the implementation in 
org.apache.tapestry5.internal.services.</p><p>We absolutely <em>do not</em> 
want to make Page or ComponentPageElement public. You will often see public 
service facades that take a page name as a method parameter, and convert it to 
a page instance before invoking methods on internal services.</p><h2 
id="DeveloperBible-EvolvingComponents">Evolving Components</h2><p>We do not 
have a specific plan for this yet. Future Tapestry 5 will add features to allow 
clean renames of parameters, and a way to deprecated and eventually remove 
components.</p><h2 id="DeveloperBi
 ble-EvolvingInterfaces">Evolving Interfaces</h2><p>Tapestry uses interfaces 
quite extensively.</p><p>Interfaces fall into two categories: service 
interfaces called by user code, and interfaces implemented by user 
code.</p><p>Internal interfaces may be changed at any time. That's why so much 
is kept internal.</p><h3 id="DeveloperBible-ServiceInterfaces">Service 
Interfaces</h3><p>New methods may be added if absolutely necessary, but this 
should be avoided if at all possible. Don't forget the <code>@since</code> 
Javadoc annotation.</p><p>Consider having a stable public facade service whose 
implementation calls into one or more internal service.</p><h3 
id="DeveloperBible-UserInterfaces">User Interfaces</h3><p>These should be 
frozen, no changes once released. Failure to do so causes <em>non-backwards 
compatible upgrade problems</em>; that is, classes that implement the (old) 
interface are suddenly invalid, missing methods from the (new) 
interface.</p><p>Consider introducing a new interfa
 ce that extends the old one and adds new methods. Make sure you support 
both.</p><p>You can see this with ServiceDef and ServiceDef2 (which extends 
ServiceDef). Yes this can be a bit ugly.</p><p>Howard uses utility methods that 
convert from ServiceDef to ServiceDef2, adding a wrapper implementation around 
a ServiceDef instance if necessary:</p><div class="code panel pdl" 
style="border-width: 1px;"><div class="codeContent panelContent pdl">
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: java; 
gutter: false; theme: Default" data-theme="Default">  public static ServiceDef2 
toServiceDef2(final ServiceDef sd)
   {
     if (sd instanceof ServiceDef2)
         return (ServiceDef2) sd;
@@ -166,7 +168,7 @@
     };
   }
 </pre>
-</div></div><h2 id="DeveloperBible-Useof@since">Use of @since</h2><p>When 
adding new classes or interface, or adding new methods to existing types, add 
an @since Javadoc comment.</p><p>Use the complete version number of the release 
in which the type or method was added: i.e., <em>@since 5.1.0.3</em>.</p><h2 
id="DeveloperBible-CodeStyle&amp;Formatting">Code Style &amp; 
Formatting</h2><p>Yes, at one time Howard used leading underscores for field 
names. He has since changed my mind, but this unfortunately infected other 
people; please try to make your code blend in when modifying existing 
source.</p><p>Long ago, Tapestry (3) code used the regrettable 
"leading-I-on-interfaces" style. Don't do that. Instead, name the 
implementation class with an "Impl" at the end.</p><p>Howard prefers braces on 
a new line (and thus, open braces lined up with close braces), so that's what 
the default code formatting is set up for. It's okay to omit braces for trivial 
one-liner if statements, such as <code
 >if (!test) return;</code>.</p><p>Indent with 4 spaces instead of 
 >tabs.</p><p>Use a lot of vertical whitespace to break methods into logical 
 >sections.</p><p>We're coding Java, not Pascal; it's better to have a few 
 >checks early on with quick returns or exceptions than have ten-levels deep 
 >block nesting just so a method can have a single return statement. In other 
 >words, <em>else considered harmful</em>. Low code complexity is better, more 
 >readable, more maintainable code.</p><p>Don't bother alphabetizing things, 
 >because the IDE lets you jump around easily.</p><p><em>Final is the new 
 >private.</em> Final fields are great for multi-threaded code. Especially when 
 >creating service implementations with dependencies, store those dependencies 
 >into final fields. Once we're all running on 100 core workstations, you'll 
 >thank me. Seriously, Java's memory model is seriously twisted stuff, and 
 >assigning to a non-final field from a constructor opens up a tiny window of 
 >non-thread safety.</p><h2 id=
 "DeveloperBible-Comments">Comments</h2><p>Comments are overwhelmingly 
important. Try to capture the <em>why</em> of a class or method. Add lots of 
links, to code that will be invoked by the method, to related methods or 
classes, and so forth. For instance, you may often have an annotation, a worker 
class for the annotation, and a related service all cross-linked.</p><p>Comment 
the <em>interfaces</em> and don't get worked up on the 
<em>implementations</em>. Javadoc does a perfectly good job of copying 
interface comments to implementations, so this falls under the <em>Don't Repeat 
Yourself</em> guideline.</p><p>Be very careful about documenting what methods 
can accept null, and what methods may return null. Generally speaking, people 
will assume that null is not allowed for parameters, and method will never 
return null, unless it is explicitly documented that null is allowed (or 
potentially returned).</p><h2 
id="DeveloperBible-Documentation">Documentation</h2><p>Try and keep the docum
 entation up-to date as you make changes; it is <em>much</em> harder to do so 
later. This is now much easier using the Confluence wiki (you're reading the 
result <img class="emoticon emoticon-smile" 
src="https://cwiki.apache.org/confluence/s/en_GB/5997/6f42626d00e36f53fe51440403446ca61552e2a2.1/_/images/icons/emoticons/smile.png";
 data-emoticon-name="smile" alt="(smile)">).</p><p>Documentation was at one 
point the <em>#1 criticism</em> of Tapestry!</p><h2 
id="DeveloperBible-ClassandMethodNamingConventions">Class and Method Naming 
Conventions</h2><p>Naming things is hard. Names that make sense to one person 
won't to another.</p><p>That being said, Howard has tried to be somewhat 
consistent with naming. Not perfectly.</p><h3 
id="DeveloperBible-Factory,Creator">Factory, Creator</h3><p>A factory class 
creates new objects. Methods will often be prefixed with "create" or "new". 
Don't expect a Factory to cache anything, it just creates new things.</p><h3 
id="DeveloperBible-Source">Source</h3
 ><p>A source is a level up from a Factory. It <em>may</em> combine multiple 
 >factories together. It <em>usually</em> will cache the result. Method are 
 >often prefixed with "get".</p><h3 id="DeveloperBible-Findvs.Get">Find vs. 
 >Get</h3><p>For methods: A "find" prefix indicates that a non-match is valid 
 >and null may be returned. A "get" prefix indicates that a non-match is 
 >invalid and an exception will be thrown in that case (and null will never be 
 >returned).</p><h3 id="DeveloperBible-Contribution">Contribution</h3><p>A data 
 >object usually associated with a Tapestry IoC service's configuration.</p><h3 
 >id="DeveloperBible-Filter">Filter</h3><p>Part of a pipeline, where there's an 
 >associated main interface, and the Filter wraps around that main interface. 
 >Each main interface method is duplicated in the Filter, with an extra 
 >parameter used to chain the interface.</p><h3 
 >id="DeveloperBible-Manager">Manager</h3><p>Often a wrapper around a service 
 >configuration, it provides access to the contri
 buted values (possibly after some transformation).</p><h3 
id="DeveloperBible-To">To</h3><p>A method prefix that indicates a conversion or 
coersion from one type to another. I.e., 
<code>toUserPresentable()</code>.</p><h3 
id="DeveloperBible-Worker">Worker</h3><p>An object that peforms a specific job. 
Workers will be stateless, but will be passed a stateful object to perform some 
operation upon.</p><h3 id="DeveloperBible-Builder">Builder</h3><p>An object 
whose job is to create other objects, typically in the context of creating a 
core service implementation for a Tapestry IoC service (such as PipelineBuilder 
or ChainBuilder).</p><h3 id="DeveloperBible-Support">Support</h3><p>An object 
that provides supporting operations to other objects; this is a kind of "loose 
aggregation".</p><h3 id="DeveloperBible-Parameters">Parameters</h3><p>A data 
object that holds a number of related values that would otherwise be separate 
parameter values to a method. This tends to streamline code (especially 
 when using a Filter interface) and allows the parameters to be evolved without 
changing the method signature.</p><h3 
id="DeveloperBible-Strategy">Strategy</h3><p>An object that "plugs into" some 
other code, allowing certain decisions to be deferred to the Strategy. Often a 
Strategy is selected based on the type of some object being operated 
upon.</p><h3 id="DeveloperBible-Context">Context</h3><p>Captures some stateful 
information that may be passed around between stateless services.</p><h3 
id="DeveloperBible-Constants">Constants</h3><p>A non-instantiable class that 
contains public static fields that are referenced in multiple places.</p><h3 
id="DeveloperBible-Hub">Hub</h3><p>An object that allows listeners to be 
registered. Often includes a method prefixed with "trigger" that will send 
notifications to listeners.</p><h2 
id="DeveloperBible-ImplementtoString()">Implement 
<code>toString()</code></h2><p>Objects that are exposed to user code should 
generally implement a meaningful toStri
 ng() method. And that method should be tested.</p><h2 
id="DeveloperBible-Subclassing">Subclassing</h2><p>You'll notice there isn't a 
lot of inheritance in Tapestry. Given the function of the IoC container, it is 
much more common to use some variation of <em>aggregation</em> rather than 
<em>inheritance</em>.</p><p>Where subclassing exists, the guideline for 
constructor parameters is: the subclass should include all the constructor 
parameters of the superclass, in the same positions. Thus subclass constructor 
parameters are appended to the list of super-class constructor 
parameters.</p></div>
+</div></div><h2 id="DeveloperBible-Useof@since">Use of @since</h2><p>When 
adding new classes or interface, or adding new methods to existing types, add 
an @since Javadoc comment.</p><p>Use the complete version number of the release 
in which the type or method was added: i.e., <em>@since 5.1.0.3</em>.</p><h2 
id="DeveloperBible-CodeStyle&amp;Formatting">Code Style &amp; 
Formatting</h2><p>Yes, at one time Howard used leading underscores for field 
names. He has since changed my mind, but this unfortunately infected other 
people; please try to make your code blend in when modifying existing 
source.</p><p>Long ago, Tapestry (3) code used the regrettable 
"leading-I-on-interfaces" style. Don't do that. Instead, name the 
implementation class with an "Impl" at the end.</p><p>Howard prefers braces on 
a new line (and thus, open braces lined up with close braces), so that's what 
the default code formatting is set up for. It's okay to omit braces for trivial 
one-liner if statements, such as <code
 >if (!test) return;</code>.</p><p>Indent with 4 spaces instead of 
 >tabs.</p><p>Use a lot of vertical whitespace to break methods into logical 
 >sections.</p><p>We're coding Java, not Pascal; it's better to have a few 
 >checks early on with quick returns or exceptions than have ten-levels deep 
 >block nesting just so a method can have a single return statement. In other 
 >words, <em>else considered harmful</em>. Low code complexity is better, more 
 >readable, more maintainable code.</p><p>Don't bother alphabetizing things, 
 >because the IDE lets you jump around easily.</p><p><em>Final is the new 
 >private.</em> Final fields are great for multi-threaded code. Especially when 
 >creating service implementations with dependencies, store those dependencies 
 >into final fields. Once we're all running on 100 core workstations, you'll 
 >thank me. Seriously, Java's memory model is seriously twisted stuff, and 
 >assigning to a non-final field from a constructor opens up a tiny window of 
 >non-thread safety.</p><h2 id=
 "DeveloperBible-Comments">Comments</h2><p>Comments are overwhelmingly 
important. Try to capture the <em>why</em> of a class or method. Add lots of 
links, to code that will be invoked by the method, to related methods or 
classes, and so forth. For instance, you may often have an annotation, a worker 
class for the annotation, and a related service all cross-linked.</p><p>Comment 
the <em>interfaces</em> and don't get worked up on the 
<em>implementations</em>. Javadoc does a perfectly good job of copying 
interface comments to implementations, so this falls under the <em>Don't Repeat 
Yourself</em> guideline.</p><p>Be very careful about documenting what methods 
can accept null, and what methods may return null. Generally speaking, people 
will assume that null is not allowed for parameters, and method will never 
return null, unless it is explicitly documented that null is allowed (or 
potentially returned).</p><h2 
id="DeveloperBible-Documentation">Documentation</h2><p>Try and keep the docum
 entation up-to date as you make changes; it is <em>much</em> harder to do so 
later. This is now much easier using the Confluence wiki (you're reading the 
result <img class="emoticon emoticon-smile" 
src="https://cwiki.apache.org/confluence/s/-7iq2vk/8301/13280cd41a592ca5883bbc1ae415b58671505365/_/images/icons/emoticons/smile.svg";
 data-emoticon-name="smile" alt="(smile)">).</p><p>Documentation was at one 
point the <em>#1 criticism</em> of Tapestry!</p><h2 
id="DeveloperBible-ClassandMethodNamingConventions">Class and Method Naming 
Conventions</h2><p>Naming things is hard. Names that make sense to one person 
won't to another.</p><p>That being said, Howard has tried to be somewhat 
consistent with naming. Not perfectly.</p><h3 
id="DeveloperBible-Factory,Creator">Factory, Creator</h3><p>A factory class 
creates new objects. Methods will often be prefixed with "create" or "new". 
Don't expect a Factory to cache anything, it just creates new things.</p><h3 
id="DeveloperBible-Source">Source</h3
 ><p>A source is a level up from a Factory. It <em>may</em> combine multiple 
 >factories together. It <em>usually</em> will cache the result. Method are 
 >often prefixed with "get".</p><h3 id="DeveloperBible-Findvs.Get">Find vs. 
 >Get</h3><p>For methods: A "find" prefix indicates that a non-match is valid 
 >and null may be returned. A "get" prefix indicates that a non-match is 
 >invalid and an exception will be thrown in that case (and null will never be 
 >returned).</p><h3 id="DeveloperBible-Contribution">Contribution</h3><p>A data 
 >object usually associated with a Tapestry IoC service's configuration.</p><h3 
 >id="DeveloperBible-Filter">Filter</h3><p>Part of a pipeline, where there's an 
 >associated main interface, and the Filter wraps around that main interface. 
 >Each main interface method is duplicated in the Filter, with an extra 
 >parameter used to chain the interface.</p><h3 
 >id="DeveloperBible-Manager">Manager</h3><p>Often a wrapper around a service 
 >configuration, it provides access to the contri
 buted values (possibly after some transformation).</p><h3 
id="DeveloperBible-To">To</h3><p>A method prefix that indicates a conversion or 
coersion from one type to another. I.e., 
<code>toUserPresentable()</code>.</p><h3 
id="DeveloperBible-Worker">Worker</h3><p>An object that peforms a specific job. 
Workers will be stateless, but will be passed a stateful object to perform some 
operation upon.</p><h3 id="DeveloperBible-Builder">Builder</h3><p>An object 
whose job is to create other objects, typically in the context of creating a 
core service implementation for a Tapestry IoC service (such as PipelineBuilder 
or ChainBuilder).</p><h3 id="DeveloperBible-Support">Support</h3><p>An object 
that provides supporting operations to other objects; this is a kind of "loose 
aggregation".</p><h3 id="DeveloperBible-Parameters">Parameters</h3><p>A data 
object that holds a number of related values that would otherwise be separate 
parameter values to a method. This tends to streamline code (especially 
 when using a Filter interface) and allows the parameters to be evolved without 
changing the method signature.</p><h3 
id="DeveloperBible-Strategy">Strategy</h3><p>An object that "plugs into" some 
other code, allowing certain decisions to be deferred to the Strategy. Often a 
Strategy is selected based on the type of some object being operated 
upon.</p><h3 id="DeveloperBible-Context">Context</h3><p>Captures some stateful 
information that may be passed around between stateless services.</p><h3 
id="DeveloperBible-Constants">Constants</h3><p>A non-instantiable class that 
contains public static fields that are referenced in multiple places.</p><h3 
id="DeveloperBible-Hub">Hub</h3><p>An object that allows listeners to be 
registered. Often includes a method prefixed with "trigger" that will send 
notifications to listeners.</p><h2 
id="DeveloperBible-ImplementtoString()">Implement 
<code>toString()</code></h2><p>Objects that are exposed to user code should 
generally implement a meaningful toStri
 ng() method. And that method should be tested.</p><h2 
id="DeveloperBible-Subclassing">Subclassing</h2><p>You'll notice there isn't a 
lot of inheritance in Tapestry. Given the function of the IoC container, it is 
much more common to use some variation of <em>aggregation</em> rather than 
<em>inheritance</em>.</p><p>Where subclassing exists, the guideline for 
constructor parameters is: the subclass should include all the constructor 
parameters of the superclass, in the same positions. Thus subclass constructor 
parameters are appended to the list of super-class constructor 
parameters.</p></div>
       </div>
 
       <div class="clearer"></div>


Reply via email to