Author: buildbot
Date: Sun Feb 18 19:21:00 2018
New Revision: 1025566
Log:
Production update by buildbot for tapestry
Modified:
websites/production/tapestry/content/cache/main.pageCache
websites/production/tapestry/content/development-dashboard.html
websites/production/tapestry/content/integration-testing.html
websites/production/tapestry/content/ioc.html
websites/production/tapestry/content/tapestry-ioc-modules.html
websites/production/tapestry/content/tapestry-ioc-overview.html
websites/production/tapestry/content/unit-testing-pages-or-components.html
Modified: websites/production/tapestry/content/cache/main.pageCache
==============================================================================
Binary files - no diff available.
Modified: websites/production/tapestry/content/development-dashboard.html
==============================================================================
--- websites/production/tapestry/content/development-dashboard.html (original)
+++ websites/production/tapestry/content/development-dashboard.html Sun Feb 18
19:21:00 2018
@@ -67,7 +67,7 @@
</div>
<div id="content">
- <div id="ConfluenceContent"><p>The <strong>development
dashboard</strong> is a built-in Tapestry page that can help identify and
resolve problems in your application.</p><p>The dashboard is typically only
available to requests from localhost (the page is whitelist access only, see <a
href="development-dashboard.html">Development Dashboard</a>).</p><p><span>Some
features of the dashboard are only available in development
mode.</span></p><p>The dashboard is available via the URI "core/t5dashboard",
or can be accessed by the <a class="external-link"
href="http://tapestry.apache.org/5.4/apidocs/org/apache/tapestry5/corelib/components/DevTool.html">DevTool</a>
component's dropdown menu.</p><p><span> <span
class="confluence-embedded-file-wrapper image-center-wrapper
confluence-embedded-manual-size"><img class="confluence-embedded-image
image-center" width="500"
src="development-dashboard.data/Tapestry_5_Dashboard_-_pages.png"></span></span></p><p>By
default, there a
re three tabs (this is extensible).</p><h2
id="DevelopmentDashboard-Pages">Pages</h2><p>The pages tab shows what pages are
currently loaded into the application. Tapestry only loads a page when it is
first needed.</p><p>It is possible to clear out Tapestry's caches, forcing a
reload. You can also run a garbage collection (GC).</p><p>It is possible to
load any individual page, or attempt to load all pages. This can be a good way
to see if all pages (and templates) are error free ... loading all will catch
quite a few potential errors.</p><h2
id="DevelopmentDashboard-Services">Services</h2><p>When using Tapestry there
will often be a large number of services defined in the registry; a mix of the
built-in services provided by the framework and your own.</p><p>Services are
usually only instantiated once they are needed.</p><p><span
class="confluence-embedded-file-wrapper image-center-wrapper
confluence-embedded-manual-size"><img class="confluence-embedded-image
image-center" width="500"
src="development-dashboard.data/Tapestry_5_Dashboard.png"></span></p><p> </p><p>Services
may be builtin, defined, virtual or real.</p><p><strong>Builtin</strong> only
applies to a few special services that are part of Tapestry
IoC.</p><p><strong>Defined</strong> services are defined in some module, but
have not yet been referenced in any way.</p><p><strong>Virtual</strong>
services have been referenced and have gotten as far as creating a service
proxy.</p><p><strong>Real</strong> services have had methods invoked, this
forces the <em>realization</em> of the service which includes instantiating the
service, injecting dependencies, and decorating with any applicable
interceptors.</p><h2 id="DevelopmentDashboard-ComponentLibraries">Component
Libraries</h2><p><span class="confluence-embedded-file-wrapper
image-center-wrapper confluence-embedded-manual-size"><img
class="confluence-embedded-image image-center" width="500"
src="development-dashboard.data/Tapestry_5_Dashboard_-_libs.
png"></span></p><p>This page gives a summary of all component libraries used
in the current application.</p></div>
+ <div id="ConfluenceContent"><p>The <strong>development
dashboard</strong> is a built-in Tapestry page that can help identify and
resolve problems in your application.</p><p>The dashboard is typically only
available to requests from localhost (the page is whitelist access only, see <a
href="security.html">Security</a>).</p><p><span>Some features of the dashboard
are only available in development mode.</span></p><p>The dashboard is available
via the URI "core/t5dashboard", or can be accessed by the <a
class="external-link"
href="http://tapestry.apache.org/5.4/apidocs/org/apache/tapestry5/corelib/components/DevTool.html">DevTool</a>
component's dropdown menu.</p><p><span> <span
class="confluence-embedded-file-wrapper image-center-wrapper
confluence-embedded-manual-size"><img class="confluence-embedded-image
image-center" width="500"
src="development-dashboard.data/Tapestry_5_Dashboard_-_pages.png"></span></span></p><p>By
default, there are three tabs (this is ext
ensible).</p><h2 id="DevelopmentDashboard-Pages">Pages</h2><p>The pages tab
shows what pages are currently loaded into the application. Tapestry only loads
a page when it is first needed.</p><p>It is possible to clear out Tapestry's
caches, forcing a reload. You can also run a garbage collection (GC).</p><p>It
is possible to load any individual page, or attempt to load all pages. This can
be a good way to see if all pages (and templates) are error free ... loading
all will catch quite a few potential errors.</p><h2
id="DevelopmentDashboard-Services">Services</h2><p>When using Tapestry there
will often be a large number of services defined in the registry; a mix of the
built-in services provided by the framework and your own.</p><p>Services are
usually only instantiated once they are needed.</p><p><span
class="confluence-embedded-file-wrapper image-center-wrapper
confluence-embedded-manual-size"><img class="confluence-embedded-image
image-center" width="500" src="development-dashboar
d.data/Tapestry_5_Dashboard.png"></span></p><p> </p><p>Services may be
builtin, defined, virtual or real.</p><p><strong>Builtin</strong> only applies
to a few special services that are part of Tapestry
IoC.</p><p><strong>Defined</strong> services are defined in some module, but
have not yet been referenced in any way.</p><p><strong>Virtual</strong>
services have been referenced and have gotten as far as creating a service
proxy.</p><p><strong>Real</strong> services have had methods invoked, this
forces the <em>realization</em> of the service which includes instantiating the
service, injecting dependencies, and decorating with any applicable
interceptors.</p><h2 id="DevelopmentDashboard-ComponentLibraries">Component
Libraries</h2><p><span class="confluence-embedded-file-wrapper
image-center-wrapper confluence-embedded-manual-size"><img
class="confluence-embedded-image image-center" width="500"
src="development-dashboard.data/Tapestry_5_Dashboard_-_libs.png"></span></p><p>This
pa
ge gives a summary of all component libraries used in the current
application.</p></div>
</div>
<div class="clearer"></div>
Modified: websites/production/tapestry/content/integration-testing.html
==============================================================================
--- websites/production/tapestry/content/integration-testing.html (original)
+++ websites/production/tapestry/content/integration-testing.html Sun Feb 18
19:21:00 2018
@@ -109,7 +109,7 @@
</div>
-<p>The Tapestry Test Utilities is a small library to make it easier to build
integration test suites around <a class="external-link"
href="http://www.openqa.org/selenium/" rel="nofollow">Selenium</a> version
2.14.0.</p><p>The strategy is to start, in-process, a Selenimum Server (which,
in turn, starts and manages a web browser), a Jetty instance (for the web
browser to talk to), and a Selenium client (which talks to the
server).</p><p>The client is able to request URLs, fill in form data, click
links, and make assertions about output and behavior.</p><h1
id="IntegrationTesting-Usage">Usage</h1><p>The core part of this library is a
base class for you to extend your tests classes : <a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/test/SeleniumTestCase.html">SeleniumTestCase</a>.</p><p>This
class is responsible for starting an instance of Jetty to server your web
application, as well as a copy of Selenium Server. It also implements the <a
class="external-link"
href="http://release.openqa.org/selenium-remote-control/0.9.0/doc/java/"
rel="nofollow">Selenium</a> interface.</p><div
class="confluence-information-macro confluence-information-macro-note"><span
class="aui-icon aui-icon-small aui-iconfont-warning
confluence-information-macro-icon"></span><div
class="confluence-information-macro-body"><p>Before Tapestry 5.2, your class
should extend <a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/test/AbstractIntegrationTestSuite.html">AbstractIntegrationTestSuite</a></p></div></div><p>Here's
an example from one of the Tapestry modules:</p><div class="code panel pdl"
style="border-width: 1px;"><div class="codeHeader panelHeader pdl"
style="border-bottom-width: 1px;"><b>Your Integration Test Class :
SinglePersistenceUnitIntegrationTest.java</b></div><div class="codeContent
panelContent pdl">
+<p>The Tapestry Test Utilities is a small library to make it easier to build
integration test suites around <a class="external-link"
href="http://www.seleniumhq.org" rel="nofollow">Selenium</a> version
2.14.0.</p><p>The strategy is to start, in-process, a Selenium Server (which,
in turn, starts and manages a web browser), a Jetty instance (for the web
browser to talk to), and a Selenium client (which talks to the
server).</p><p>The client is able to request URLs, fill in form data, click
links, and make assertions about output and behavior.</p><h1
id="IntegrationTesting-Usage">Usage</h1><p>The core part of this library is a
base class for you to extend your tests classes : <a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/test/SeleniumTestCase.html">SeleniumTestCase</a>.</p><p>This
class is responsible for starting an instance of Jetty to server your web
application, as well as a copy of Selenium Server. It also implements the <a
class
="external-link"
href="http://release.openqa.org/selenium-remote-control/0.9.0/doc/java/"
rel="nofollow">Selenium</a> interface.</p><div
class="confluence-information-macro confluence-information-macro-note"><span
class="aui-icon aui-icon-small aui-iconfont-warning
confluence-information-macro-icon"></span><div
class="confluence-information-macro-body"><p>Before Tapestry 5.2, your class
should extend AbstractIntegrationTestSuite</p></div></div><p>Here's an example
from one of the Tapestry modules:</p><div class="code panel pdl"
style="border-width: 1px;"><div class="codeHeader panelHeader pdl"
style="border-bottom-width: 1px;"><b>Your Integration Test Class :
SinglePersistenceUnitIntegrationTest.java</b></div><div class="codeContent
panelContent pdl">
<pre class="brush: java; gutter: false; theme: Default"
style="font-size:12px;">package org.apache.tapestry5.jpa.integration.app2;
import org.apache.tapestry5.test.SeleniumTestCase;
Modified: websites/production/tapestry/content/ioc.html
==============================================================================
--- websites/production/tapestry/content/ioc.html (original)
+++ websites/production/tapestry/content/ioc.html Sun Feb 18 19:21:00 2018
@@ -118,7 +118,7 @@
</div>
-<p>An additional benefit of using IoC is that, by breaking a complex system
into small pieces, it becomes easier to modify and extend the system, by
overriding or replacing selected parts of the system.</p><p>The use of IoC in
Tapestry represents an evolution from Tapestry 3 to Tapestry 4 to Tapestry 5.
Tapestry 3 did not use IoC, though it included some weaker mechanisms, such as
extensions, that served a similar purpose. To make large scale changes to the
behavior of Tapestry 3 required subclassing key classes and overriding
methods.</p><p>Tapestry 4 introduced the use of the <a class="external-link"
href="http://hivemind.apache.org/">Apache HiveMind</a> IoC container. In fact,
the HiveMind project was created specifically for use as the IoC container for
Tapestry 4. Tapestry 4 has met its goals for extensibility and configurability,
largely because of HiveMind's flexibility.</p><p>Tapestry 5 extends on this,
replacing HiveMind with a new container specifically build for Tapestry
5, designed for greater ease of use, expressiveness and performance. HiveMind
itself has been subsequently shelved; T5 IoC can be considered a streamlined
and improved HiveMind. And T5 IoC can be used separately from the rest of
Tapestry!</p><h2 id="IOC-WhyNotSpring?">Why Not Spring?</h2><p><a
class="external-link" href="http://www.springframework.org"
rel="nofollow">Spring</a> is the most successful IoC container project. The
Spring project combines a very good IoC container, integrated <a
class="external-link" href="http://www.eclipse.org/aspectj/"
rel="nofollow">AspectJ</a> support, and a large number of libraries built on
top of the container. Spring is an excellent <em>application</em> container,
but lacks a number of features necessary for a <em>framework</em>
container:</p><ul><li>Spring beans can be wired together by name (or id), but
it is not possible to introduce additional naming abstractions. Tapestry 4's
"infrastructure:" abstraction was the key to allowing easy spo
t overrides of internal Tapestry services without having to duplicate the
large web of interrelated services (nearly 200 in Tapestry
4.0).</li><li>Although Spring allows beans to be intercepted, it does so in the
form of a new bean, leaving the un-intercepted bean visible (and subject to
misuse). Tapestry IoC "wraps" the service inside interceptors, preventing
un-intercepted access to the core service implementation.</li><li>Spring's XML
configuration files are quite verbose. This has improved with Spring 2.0, but
still far more verbose that T5 IoC module classes.</li><li>Spring has a simple
map/list/value configuration scheme, but it is not distributed; it is part of a
single bean definition. Tapestry 5 IoC allows a service configuration to be
assembled from multiple modules. This is very important for seamless
extensibility of the framework, with zero configuration (just drop the module
into the classpath and everything hooks together).</li></ul><h2
id="IOC-WhyNotHiveMind?">Why No
t HiveMind?</h2><p>The difficulty of managing the release schedules of two
complex frameworks proved to be an issue.</p><p>The use of HiveMind was also
related to one of the common criticisms of Tapestry 4: startup time. The time
it took to parse and organize all that XML showed up as several seconds of
startup time. Creating a streamlined IoC container that is not driven by XML
has alleviated those issues.</p><p>With the advent of new technologies (in
particular, JDK 1.5 <a class="external-link"
href="http://download.oracle.com/javase/tutorial/java/javaOO/annotations.html"
rel="nofollow">Annotations</a> and runtime class generation via <a
class="external-link" href="http://www.jboss.org/products/javassist"
rel="nofollow">Javassist</a>) some of the precepts of HiveMind were undermined.
That is to say, in HiveMind (as in Spring), all that XML was an awkward way to
describe a few basic Java operations: instantiating classes and invoking
methods on those classes (to inject dependenci
es into the instantiated instances). The central concept in Tapestry IoC is to
eliminate XML and build an equivalent system around simple objects and
methods.</p><p>Tapestry IoC also represents many simplifications of HiveMind,
building on lessons learned from both HiveMind and Tapestry 4. The HiveMind
project itself is no longer under development, and most of the user base has
moved to Tapestry 5.</p><h2 id="IOC-WhynotGuice?">Why not Guice?</h2><p><a
class="external-link" href="http://code.google.com/p/google-guice/"
rel="nofollow">Google Guice</a> is a relative newcomer to the IoC landscape.
Guice and T5 IoC are very close and, in fact, T5 IoC expressly borrows many
great and innovative ideas from Guice. Guice abandons not only XML but even any
concept of a service id ... for injection, services are matched by type and
perhaps filtered based on annotations.</p><p>Guice is still missing some core
ideas needed in T5 IoC. There's no concept of configurations or anything
similar. And
there are limitations on injection based on scope (a request scoped value
can't be injected into a global scope service; in T5 IoC, scope is internal to
the proxy and never an issue).</p><h1 id="IOC-Goals">Goals</h1><p>As with
Tapestry 5 in general, the goal of Tapestry IoC is greater simplicity, greater
power, and an avoidance of XML.</p><p>Existing IoC containers such as HiveMind
and Spring typically contain large amounts of XML configuration that exists to
describe how and when to instantiate a particular JavaBean, and how to provide
that bean with its dependencies (either by constructor injection, or by
property injection). Other XML is used to hook objects into some form of life
cycle ... typically callback methods invoked when the object is instantiated
and configured, or when it is being discarded.</p><p>The core concept of
Tapestry IoC is that the Java language itself is the easiest and most succinct
way to describe object creation and method invocation. Any approximation i
n XML is ultimately more verbose and unwieldy. As the <a
href="ioc.html">examples</a> show, a small amount of Java code and a handful of
naming conventions and annotations is far simpler and easier than a big chunk
of XML.</p><p>In addition, moving from XML to Java code encourages testing; you
can unit test the service builder methods of your module class, but you can't
realistically unit test an XML descriptor.</p><p>Tapestry IoC modules are
easily packaged into JAR files, supporting zero-configuration usage: just drop
the JAR onto the classpath.</p><p>Another goal is "developer friendliness".
This is a true cross-cutting concern, and one not likely to be packaged into an
aspect any time soon. The Tapestry IoC framework is designed to be easy to use
and easy to understand. Further, when things go wrong, it actively attempts to
help you via comprehensive checks and carefully composed error messages.
Further, all user-visible objects implement a <a class="external-link"
href="http:
//howardlewisship.com/blog/2003/08/importance-of-tostring.html"
rel="nofollow">reasonable toString() method</a>, to help you understand what's
going when you inevitably try to figure things out in the debugger.</p><p>In
terms of building services using Tapestry IoC ... the objective here is
"lightness", a term borrowed from the board game <a class="external-link"
href="http://boardgamegeek.com/game/188" rel="nofollow">Go</a>. In Go, two
players place stones on an initially empty board, creating walls to enclose
territory or eliminate the encroaching stones played by the opponent. The
winner at the end of the game controls the most territory, and it is the
constant tension between taking territory and defending existing territory that
drives the game. In Go, groups of playing stones are "light" (or have "good
shape") when the minimum number of them control the maximum area on the board.
Playing "heavy" just gives your opponent a free chance to take control of
another section of the
board.</p><p>In software development, we are also attempting to create complex
systems from simple pieces, but our tension is derived from the need to add
functionality balanced against the need to test and maintain existing code. Too
often in the world of software development, the need to add functionality
trumps all, and testing and maintenance is deferred ... until too
late.</p><p>IoC containers in general, and Tapestry IoC very specifically,
exist to address this issue, to provide the foundations for balancing the need
to quickly add functionality against the need to test new functionality and
maintain existing functionality. IoC containers provide the means to break
large, complex, monolithic blocks into light, small, testable
pieces.</p><p>When building a registry of services, lightness refers to the
proper division of responsibility, the separation of concerns, and the limiting
of dependencies between different parts of the system. This style is often
called <a class="extern
al-link"
href="http://www.ccs.neu.edu/research/demeter/demeter-method/LawOfDemeter/general-formulation.html"
rel="nofollow">Law of Demeter</a>. Using an IoC container makes it easier to
embrace this approach, since one critical concern, which objects are
responsible for instantiating which others, is entirely managed by the
container. With this life cycle concern removed, it becomes very easy to reduce
complex chunks of code into small, testable, reusable services.</p><p>"Light"
means:</p><ul><li>Small interfaces of two or three methods.</li><li>Small
methods, with two or three parameters (because dependencies are injected in
behind the scenes, rather than passed into the method).</li><li>Anonymous
communication via events, rather than explicit method invocations. The service
implementation can implement an event listener interface.</li></ul><p>See <a
class="external-link"
href="http://www.pragmaticprogrammer.com/ppbook/index.shtml" rel="nofollow">The
Pragmatic Programmer</a> for m
ore insights into building solid code.</p><h1
id="IOC-Terminology">Terminology</h1><p>The basic unit in Tapestry IoC is a
<strong>service</strong>. A service consists of a <strong>service
interface</strong> and a <strong>service implementation</strong>. The service
interface is an ordinary Java interface. The service implementation is a Java
object that implements the service interface. Often there will only be a single
service per service interface, but in some situations, there may be many
different services and service implementations all sharing the same service
interface.</p><p>Services are identified by a unique id. Typically, a service
id matches the unqualified name of the service interface, but this is simply a
convention.</p><div class="confluence-information-macro
confluence-information-macro-note"><span class="aui-icon aui-icon-small
aui-iconfont-warning confluence-information-macro-icon"></span><div
class="confluence-information-macro-body"><p>The evolutionary direction
of the Tapestry IoC is to eventually eliminate service ids and work totally
in terms of service interfaces and marker
annotations.</p></div></div><p>Services are aggregated into
<strong>modules</strong>:</p><ul><li>A module is defined by a <strong>module
class</strong>, a specific class containing a mix of static or instance
methods, used to define services, decorate them (see below), or contribute to
service configurations (again, more below).</li><li>Methods of the module class
define the services provided by the module, and the same methods are
responsible for instantiating the service implementation.</li></ul><p>The
methods which define and construct services are called <strong>service builder
methods</strong>.</p><p>The <strong>registry</strong> is the outside world's
view of the modules and services. From the registry, it is possible to obtain a
service, via its unique id or by its service interface. Access by unique id is
<em>caseless</em> (meaning, a match will be found eve
n the case of the search key doesn't match the case of the service id
itself).</p><p>Services may be <strong>decorated</strong> by <strong>service
decorator methods</strong>. These methods create <strong>interceptor</strong>
objects that wrap around core service implementations, adding behavior such as
logging, security access, or transaction management. Interceptors implement the
same service interface as the service. Control is given over the order in which
decorators are applied to a service.</p><p>A service may have a
<strong>configuration</strong>. The configuration is either a map, a
collection, or an ordered list. The service defines the type of object allowed
to be contributed into the configuration. The configuration is constructed from
<strong>contributions</strong> provided by one or more modules. <strong>Service
contributor methods</strong> are invoked to contribute objects into
configurations.</p><p>Services are instantiated as needed. In this case, "need"
translates to
"when a method of the service is invoked". A service is represented (to the
outside world, or to other services) as a <strong>proxy</strong> that
implements the service interface. The first time a method is invoked on the
proxy, the full service (consisting of the core service implementation wrapped
with any interceptors) is constructed. This occurs in a completely
<strong>thread-safe</strong> manner. Just-in-time instantiation allows for more
complex, more finely grained networks of services, and improves start-up
time.</p><p>Instantiating a service, injecting dependencies, and decorating the
service are all parts of service <strong>realization</strong>, the point at
which a service transitions from virtual (just a proxy) to real (fully
instantiated and ready to operate).</p><p>Services define a
<strong>scope</strong> that controls when the service is constructed, as well
as its visibility. The default scope is <strong>singleton</strong>, meaning a
single global instance created a
s needed. Other scopes allow service implementations to be bound to the
current thread (i.e., the current request in a servlet
application).</p><p><strong>Dependencies</strong> are other services (or other
objects) that are needed by a service implementation. These dependencies can be
<strong>injected</strong> into a service builder method and provided, from
there, to a service implementation via its constructor, or via methods on the
service implementation. These may also be referred to as
<strong>collaborators</strong>, especially in the context of writing unit
tests.</p><p>The <strong>point of Injection</strong> is a field, method
parameter, or constructor parameter that receives an injected value. The type
of service (or other dependency) is determined by the type of the field or
parameter. Often, annotations further identify what is to be injected, or in
the case of field injection, that an injection is required.</p><h2
id="IOC-IoCSubtopics">IoC Subtopics</h2><p></p><ul class="
childpages-macro"><li><a href="tapestry-ioc-overview.html">Tapestry IoC
Overview</a></li><li><a href="tapestry-ioc-modules.html">Tapestry IoC
Modules</a></li><li><a href="defining-tapestry-ioc-services.html">Defining
Tapestry IOC Services</a></li><li><a href="service-advisors.html">Service
Advisors</a></li><li><a href="tapestry-ioc-decorators.html">Tapestry IoC
Decorators</a></li><li><a href="tapestry-ioc-configuration.html">Tapestry IoC
Configuration</a></li><li><a href="case-insensitivity.html">Case
Insensitivity</a></li><li><a href="autoloading-modules.html">Autoloading
Modules</a></li><li><a href="service-implementation-reloading.html">Service
Implementation Reloading</a></li><li><a
href="ordering-by-constraints.html">Ordering by Constraints</a></li><li><a
href="symbols.html">Symbols</a></li><li><a
href="chainbuilder-service.html">ChainBuilder Service</a></li><li><a
href="pipelinebuilder-service.html">PipelineBuilder Service</a></li><li><a
href="shadowbuilder-servi
ce.html">ShadowBuilder Service</a></li><li><a
href="strategybuilder-service.html">StrategyBuilder Service</a></li><li><a
href="injection-in-detail.html">Injection in Detail</a></li><li><a
href="object-providers.html">Object Providers</a></li><li><a
href="service-serialization.html">Service Serialization</a></li><li><a
href="type-coercion.html">Type Coercion</a></li><li><a
href="starting-the-ioc-registry.html">Starting the IoC Registry</a></li><li><a
href="registry-startup.html">Registry Startup</a></li><li><a
href="parallel-execution.html">Parallel Execution</a></li><li><a
href="logging-in-tapestry.html">Logging in Tapestry</a></li><li><a
href="using-jsr-330-standard-annotations.html">Using JSR 330 standard
annotations</a></li><li><a href="operation-tracker.html">Operation
Tracker</a></li></ul></div>
+<p>An additional benefit of using IoC is that, by breaking a complex system
into small pieces, it becomes easier to modify and extend the system, by
overriding or replacing selected parts of the system.</p><p>The use of IoC in
Tapestry represents an evolution from Tapestry 3 to Tapestry 4 to Tapestry 5.
Tapestry 3 did not use IoC, though it included some weaker mechanisms, such as
extensions, that served a similar purpose. To make large scale changes to the
behavior of Tapestry 3 required subclassing key classes and overriding
methods.</p><p>Tapestry 4 introduced the use of the <a class="external-link"
href="http://hivemind.apache.org/">Apache HiveMind</a> IoC container. In fact,
the HiveMind project was created specifically for use as the IoC container for
Tapestry 4. Tapestry 4 has met its goals for extensibility and configurability,
largely because of HiveMind's flexibility.</p><p>Tapestry 5 extends on this,
replacing HiveMind with a new container specifically build for Tapestry
5, designed for greater ease of use, expressiveness and performance. HiveMind
itself has been subsequently shelved; T5 IoC can be considered a streamlined
and improved HiveMind. And T5 IoC can be used separately from the rest of
Tapestry!</p><h2 id="IOC-WhyNotSpring?">Why Not Spring?</h2><p><a
class="external-link" href="http://www.springframework.org"
rel="nofollow">Spring</a> is the most successful IoC container project. The
Spring project combines a very good IoC container, integrated <a
class="external-link" href="http://www.eclipse.org/aspectj/"
rel="nofollow">AspectJ</a> support, and a large number of libraries built on
top of the container. Spring is an excellent <em>application</em> container,
but lacks a number of features necessary for a <em>framework</em>
container:</p><ul><li>Spring beans can be wired together by name (or id), but
it is not possible to introduce additional naming abstractions. Tapestry 4's
"infrastructure:" abstraction was the key to allowing easy spo
t overrides of internal Tapestry services without having to duplicate the
large web of interrelated services (nearly 200 in Tapestry
4.0).</li><li>Although Spring allows beans to be intercepted, it does so in the
form of a new bean, leaving the un-intercepted bean visible (and subject to
misuse). Tapestry IoC "wraps" the service inside interceptors, preventing
un-intercepted access to the core service implementation.</li><li>Spring's XML
configuration files are quite verbose. This has improved with Spring 2.0, but
still far more verbose that T5 IoC module classes.</li><li>Spring has a simple
map/list/value configuration scheme, but it is not distributed; it is part of a
single bean definition. Tapestry 5 IoC allows a service configuration to be
assembled from multiple modules. This is very important for seamless
extensibility of the framework, with zero configuration (just drop the module
into the classpath and everything hooks together).</li></ul><h2
id="IOC-WhyNotHiveMind?">Why No
t HiveMind?</h2><p>The difficulty of managing the release schedules of two
complex frameworks proved to be an issue.</p><p>The use of HiveMind was also
related to one of the common criticisms of Tapestry 4: startup time. The time
it took to parse and organize all that XML showed up as several seconds of
startup time. Creating a streamlined IoC container that is not driven by XML
has alleviated those issues.</p><p>With the advent of new technologies (in
particular, JDK 1.5 <a class="external-link"
href="http://download.oracle.com/javase/tutorial/java/javaOO/annotations.html"
rel="nofollow">Annotations</a> and runtime class generation via <a
class="external-link" href="http://www.jboss.org/products/javassist"
rel="nofollow">Javassist</a>) some of the precepts of HiveMind were undermined.
That is to say, in HiveMind (as in Spring), all that XML was an awkward way to
describe a few basic Java operations: instantiating classes and invoking
methods on those classes (to inject dependenci
es into the instantiated instances). The central concept in Tapestry IoC is to
eliminate XML and build an equivalent system around simple objects and
methods.</p><p>Tapestry IoC also represents many simplifications of HiveMind,
building on lessons learned from both HiveMind and Tapestry 4. The HiveMind
project itself is no longer under development, and most of the user base has
moved to Tapestry 5.</p><h2 id="IOC-WhynotGuice?">Why not Guice?</h2><p><a
class="external-link" href="http://code.google.com/p/google-guice/"
rel="nofollow">Google Guice</a> is a relative newcomer to the IoC landscape.
Guice and T5 IoC are very close and, in fact, T5 IoC expressly borrows many
great and innovative ideas from Guice. Guice abandons not only XML but even any
concept of a service id ... for injection, services are matched by type and
perhaps filtered based on annotations.</p><p>Guice is still missing some core
ideas needed in T5 IoC. There's no concept of configurations or anything
similar. And
there are limitations on injection based on scope (a request scoped value
can't be injected into a global scope service; in T5 IoC, scope is internal to
the proxy and never an issue).</p><h1 id="IOC-Goals">Goals</h1><p>As with
Tapestry 5 in general, the goal of Tapestry IoC is greater simplicity, greater
power, and an avoidance of XML.</p><p>Existing IoC containers such as HiveMind
and Spring typically contain large amounts of XML configuration that exists to
describe how and when to instantiate a particular JavaBean, and how to provide
that bean with its dependencies (either by constructor injection, or by
property injection). Other XML is used to hook objects into some form of life
cycle ... typically callback methods invoked when the object is instantiated
and configured, or when it is being discarded.</p><p>The core concept of
Tapestry IoC is that the Java language itself is the easiest and most succinct
way to describe object creation and method invocation. Any approximation i
n XML is ultimately more verbose and unwieldy. As the <a
href="defining-tapestry-ioc-services.html">Tapestry IOC examples</a> show, a
small amount of Java code and a handful of naming conventions and annotations
is far simpler and easier than a big chunk of XML.</p><p>In addition, moving
from XML to Java code encourages testing; you can unit test the service builder
methods of your module class, but you can't realistically unit test an XML
descriptor.</p><p>Tapestry IoC modules are easily packaged into JAR files,
supporting zero-configuration usage: just drop the JAR onto the
classpath.</p><p>Another goal is "developer friendliness". This is a true
cross-cutting concern, and one not likely to be packaged into an aspect any
time soon. The Tapestry IoC framework is designed to be easy to use and easy to
understand. Further, when things go wrong, it actively attempts to help you via
comprehensive checks and carefully composed error messages. Further, all
user-visible objects implement
a <a class="external-link"
href="https://web.archive.org/web/20041125140446/http://howardlewisship.com/blog/2003/08/importance-of-tostring.html"
rel="nofollow">reasonable toString() method</a>, to help you understand what's
going when you inevitably try to figure things out in the debugger.</p><p>In
terms of building services using Tapestry IoC ... the objective here is
"lightness", a term borrowed from the board game <a class="external-link"
href="http://boardgamegeek.com/game/188" rel="nofollow">Go</a>. In Go, two
players place stones on an initially empty board, creating walls to enclose
territory or eliminate the encroaching stones played by the opponent. The
winner at the end of the game controls the most territory, and it is the
constant tension between taking territory and defending existing territory that
drives the game. In Go, groups of playing stones are "light" (or have "good
shape") when the minimum number of them control the maximum area on the board.
Playing "heavy
" just gives your opponent a free chance to take control of another section of
the board.</p><p>In software development, we are also attempting to create
complex systems from simple pieces, but our tension is derived from the need to
add functionality balanced against the need to test and maintain existing code.
Too often in the world of software development, the need to add functionality
trumps all, and testing and maintenance is deferred ... until too
late.</p><p>IoC containers in general, and Tapestry IoC very specifically,
exist to address this issue, to provide the foundations for balancing the need
to quickly add functionality against the need to test new functionality and
maintain existing functionality. IoC containers provide the means to break
large, complex, monolithic blocks into light, small, testable
pieces.</p><p>When building a registry of services, lightness refers to the
proper division of responsibility, the separation of concerns, and the limiting
of dependencies
between different parts of the system. This style is often called <a
class="external-link"
href="http://www.ccs.neu.edu/research/demeter/demeter-method/LawOfDemeter/general-formulation.html"
rel="nofollow">Law of Demeter</a>. Using an IoC container makes it easier to
embrace this approach, since one critical concern, which objects are
responsible for instantiating which others, is entirely managed by the
container. With this life cycle concern removed, it becomes very easy to reduce
complex chunks of code into small, testable, reusable services.</p><p>"Light"
means:</p><ul><li>Small interfaces of two or three methods.</li><li>Small
methods, with two or three parameters (because dependencies are injected in
behind the scenes, rather than passed into the method).</li><li>Anonymous
communication via events, rather than explicit method invocations. The service
implementation can implement an event listener interface.</li></ul><p>See <a
class="external-link" href="http://www.pragmaticp
rogrammer.com/ppbook/index.shtml" rel="nofollow">The Pragmatic Programmer</a>
for more insights into building solid code.</p><h1
id="IOC-Terminology">Terminology</h1><p>The basic unit in Tapestry IoC is a
<strong>service</strong>. A service consists of a <strong>service
interface</strong> and a <strong>service implementation</strong>. The service
interface is an ordinary Java interface. The service implementation is a Java
object that implements the service interface. Often there will only be a single
service per service interface, but in some situations, there may be many
different services and service implementations all sharing the same service
interface.</p><p>Services are identified by a unique id. Typically, a service
id matches the unqualified name of the service interface, but this is simply a
convention.</p><div class="confluence-information-macro
confluence-information-macro-note"><span class="aui-icon aui-icon-small
aui-iconfont-warning confluence-information-macro-icon">
</span><div class="confluence-information-macro-body"><p>The evolutionary
direction of the Tapestry IoC is to eventually eliminate service ids and work
totally in terms of service interfaces and marker
annotations.</p></div></div><p>Services are aggregated into
<strong>modules</strong>:</p><ul><li>A module is defined by a <strong>module
class</strong>, a specific class containing a mix of static or instance
methods, used to define services, decorate them (see below), or contribute to
service configurations (again, more below).</li><li>Methods of the module class
define the services provided by the module, and the same methods are
responsible for instantiating the service implementation.</li></ul><p>The
methods which define and construct services are called <strong>service builder
methods</strong>.</p><p>The <strong>registry</strong> is the outside world's
view of the modules and services. From the registry, it is possible to obtain a
service, via its unique id or by its service inte
rface. Access by unique id is <em>caseless</em> (meaning, a match will be
found even the case of the search key doesn't match the case of the service id
itself).</p><p>Services may be <strong>decorated</strong> by <strong>service
decorator methods</strong>. These methods create <strong>interceptor</strong>
objects that wrap around core service implementations, adding behavior such as
logging, security access, or transaction management. Interceptors implement the
same service interface as the service. Control is given over the order in which
decorators are applied to a service.</p><p>A service may have a
<strong>configuration</strong>. The configuration is either a map, a
collection, or an ordered list. The service defines the type of object allowed
to be contributed into the configuration. The configuration is constructed from
<strong>contributions</strong> provided by one or more modules. <strong>Service
contributor methods</strong> are invoked to contribute objects into configurat
ions.</p><p>Services are instantiated as needed. In this case, "need"
translates to "when a method of the service is invoked". A service is
represented (to the outside world, or to other services) as a
<strong>proxy</strong> that implements the service interface. The first time a
method is invoked on the proxy, the full service (consisting of the core
service implementation wrapped with any interceptors) is constructed. This
occurs in a completely <strong>thread-safe</strong> manner. Just-in-time
instantiation allows for more complex, more finely grained networks of
services, and improves start-up time.</p><p>Instantiating a service, injecting
dependencies, and decorating the service are all parts of service
<strong>realization</strong>, the point at which a service transitions from
virtual (just a proxy) to real (fully instantiated and ready to
operate).</p><p>Services define a <strong>scope</strong> that controls when the
service is constructed, as well as its visibility. The defa
ult scope is <strong>singleton</strong>, meaning a single global instance
created as needed. Other scopes allow service implementations to be bound to
the current thread (i.e., the current request in a servlet
application).</p><p><strong>Dependencies</strong> are other services (or other
objects) that are needed by a service implementation. These dependencies can be
<strong>injected</strong> into a service builder method and provided, from
there, to a service implementation via its constructor, or via methods on the
service implementation. These may also be referred to as
<strong>collaborators</strong>, especially in the context of writing unit
tests.</p><p>The <strong>point of Injection</strong> is a field, method
parameter, or constructor parameter that receives an injected value. The type
of service (or other dependency) is determined by the type of the field or
parameter. Often, annotations further identify what is to be injected, or in
the case of field injection, that an injec
tion is required.</p><h2 id="IOC-IoCSubtopics">IoC Subtopics</h2><p></p><ul
class="childpages-macro"><li><a href="tapestry-ioc-overview.html">Tapestry IoC
Overview</a></li><li><a href="tapestry-ioc-modules.html">Tapestry IoC
Modules</a></li><li><a href="defining-tapestry-ioc-services.html">Defining
Tapestry IOC Services</a></li><li><a href="service-advisors.html">Service
Advisors</a></li><li><a href="tapestry-ioc-decorators.html">Tapestry IoC
Decorators</a></li><li><a href="tapestry-ioc-configuration.html">Tapestry IoC
Configuration</a></li><li><a href="case-insensitivity.html">Case
Insensitivity</a></li><li><a href="autoloading-modules.html">Autoloading
Modules</a></li><li><a href="service-implementation-reloading.html">Service
Implementation Reloading</a></li><li><a
href="ordering-by-constraints.html">Ordering by Constraints</a></li><li><a
href="symbols.html">Symbols</a></li><li><a
href="chainbuilder-service.html">ChainBuilder Service</a></li><li><a
href="pipelinebuil
der-service.html">PipelineBuilder Service</a></li><li><a
href="shadowbuilder-service.html">ShadowBuilder Service</a></li><li><a
href="strategybuilder-service.html">StrategyBuilder Service</a></li><li><a
href="injection-in-detail.html">Injection in Detail</a></li><li><a
href="object-providers.html">Object Providers</a></li><li><a
href="service-serialization.html">Service Serialization</a></li><li><a
href="type-coercion.html">Type Coercion</a></li><li><a
href="starting-the-ioc-registry.html">Starting the IoC Registry</a></li><li><a
href="registry-startup.html">Registry Startup</a></li><li><a
href="parallel-execution.html">Parallel Execution</a></li><li><a
href="logging-in-tapestry.html">Logging in Tapestry</a></li><li><a
href="using-jsr-330-standard-annotations.html">Using JSR 330 standard
annotations</a></li><li><a href="operation-tracker.html">Operation
Tracker</a></li></ul></div>
</div>
<div class="clearer"></div>
Modified: websites/production/tapestry/content/tapestry-ioc-modules.html
==============================================================================
--- websites/production/tapestry/content/tapestry-ioc-modules.html (original)
+++ websites/production/tapestry/content/tapestry-ioc-modules.html Sun Feb 18
19:21:00 2018
@@ -85,7 +85,7 @@ public class MyAppModule
return new IndexerImpl();
}
}</pre>
-</div></div><p>Any public method (static or instance) whose name starts with
"build" is a service builder method, implicitly defining a service within the
module.</p><p>Here we're defining a service around the Indexer service
interface (presumably also in the org.example.myapp.services
package).</p><p>Every service has a unique id, used to identify it throughout
the Registry of services (the Registry is the combined sum of all services from
all modules). If you don't provide an explicit service id, as in this example,
the service id is drawn from the return type; this service has an id of
"Indexer".</p><p>You can give a service an explicit id by adding it to the
method name: buildIndexer(). This is useful when you do not want the service id
to match the service interface name (for example, when you have different
services that implement the same interface), or when you need to avoid name
collisions on the method name (Java allows only a single method with a given
name and set of par
ameters, even if the return types are different, so if you have two different
service builder methods that take the same parameters, you should give them
explicit service ids in the method name).</p><p>Tapestry IoC is <a
href="tapestry-ioc-modules.html">case insensitive</a>; later we can refer to
this service as "indexer" or "INDEXER" or any variation thereof, and connect to
this service.</p><p>Service ids must be unique; if another module contributes a
service with the id "Indexer" (or any case variation thereof) a runtime
exception will occur when the Registry is created.</p><p>We could extend this
example by adding additional service builder methods, or by showing how to
inject dependencies. See <a href="tapestry-ioc-modules.html">the service
documentation</a> for more details.</p><h1
id="TapestryIoCModules-AutobuildingServices">Autobuilding Services</h1><p>Main
article: <a href="tapestry-ioc-modules.html">Tapestry IoC Modules</a></p><p>An
alternate, and usually preferred, way
to define a service is via a module's bind() method. The previous example can
be rewritten as:</p><div class="code panel pdl" style="border-width: 1px;"><div
class="codeContent panelContent pdl">
+</div></div><p>Any public method (static or instance) whose name starts with
"build" is a service builder method, implicitly defining a service within the
module.</p><p>Here we're defining a service around the Indexer service
interface (presumably also in the org.example.myapp.services
package).</p><p>Every service has a unique id, used to identify it throughout
the Registry of services (the Registry is the combined sum of all services from
all modules). If you don't provide an explicit service id, as in this example,
the service id is drawn from the return type; this service has an id of
"Indexer".</p><p>You can give a service an explicit id by adding it to the
method name: buildIndexer(). This is useful when you do not want the service id
to match the service interface name (for example, when you have different
services that implement the same interface), or when you need to avoid name
collisions on the method name (Java allows only a single method with a given
name and set of par
ameters, even if the return types are different, so if you have two different
service builder methods that take the same parameters, you should give them
explicit service ids in the method name).</p><p>Tapestry IoC is <a
href="case-insensitivity.html">case insensitive</a>; later we can refer to this
service as "indexer" or "INDEXER" or any variation thereof, and connect to this
service.</p><p>Service ids must be unique; if another module contributes a
service with the id "Indexer" (or any case variation thereof) a runtime
exception will occur when the Registry is created.</p><p>We could extend this
example by adding additional service builder methods, or by showing how to
inject dependencies. See <a href="defining-tapestry-ioc-services.html">the
service documentation</a> for more details.</p><h1
id="TapestryIoCModules-AutobuildingServices">Autobuilding Services</h1><p>Main
article: <a href="defining-tapestry-ioc-services.html">Defining Tapestry IOC
Services</a></p><p>An alternate
, and usually preferred, way to define a service is via a module's bind()
method. The previous example can 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;">package org.example.myapp.services;
import org.apache.tapestry5.ioc.ServiceBinder;
@@ -97,7 +97,7 @@ public class MyAppModule
binder.bind(Indexer.class, IndexerImpl.class);
}
}</pre>
-</div></div><p>For more details, see see <a
href="tapestry-ioc-modules.html">Tapestry IoC Modules</a>. In most cases,
autobuilding is the <em>preferred</em> approach.</p><p>Generally speaking, you
should always bind and autobuild your services. The only exceptions are
when:</p><ul><li>You wish to do more than just instantiate a class; for
example, to register the class as an event listener with some other
service.</li><li>There is <em>no implementation class</em>; in some cases, you
can create your implementation on the fly using JDK dynamic proxies or bytecode
generation.</li></ul><p>The bind() method must be static; an exception is
thrown if the bind() method exists but is an instance method.</p><h1
id="TapestryIoCModules-Cacheing_ServicesCachingServices"><span
class="confluence-anchor-link"
id="TapestryIoCModules-Cacheing_Services"></span>Caching Services</h1><p>You
will occasionally find yourself in the position of injecting the same services
into your service builder or servic
e decorator methods repeatedly (this occurs much less often since the
introduction of service autobuilding). This can result in quite a bit of
redundant typing. Less code is better code, so as an alternative, you may
define a <em>constructor</em> for your module that accepts annotated parameters
(as with <a href="tapestry-ioc-modules.html">service builder
injection</a>).</p><p>This gives you a chance to store common services in
instance variables for later use inside service builder methods.</p><div
class="code panel pdl" style="border-width: 1px;"><div class="codeContent
panelContent pdl">
+</div></div><p class="confluence-link">For more details, see see <a
href="defining-tapestry-ioc-services.html">Defining Tapestry IOC Services</a>.
In most cases, autobuilding is the <em>preferred</em> approach.</p><p>Generally
speaking, you should always bind and autobuild your services. The only
exceptions are when:</p><ul><li>You wish to do more than just instantiate a
class; for example, to register the class as an event listener with some other
service.</li><li>There is <em>no implementation class</em>; in some cases, you
can create your implementation on the fly using JDK dynamic proxies or bytecode
generation.</li></ul><p>The bind() method must be static; an exception is
thrown if the bind() method exists but is an instance method.</p><h1
id="TapestryIoCModules-Cacheing_ServicesCachingServices"><span
class="confluence-anchor-link"
id="TapestryIoCModules-Cacheing_Services"></span>Caching Services</h1><p>You
will occasionally find yourself in the position of injecting the same
services into your service builder or service decorator methods repeatedly
(this occurs much less often since the introduction of service autobuilding).
This can result in quite a bit of redundant typing. Less code is better code,
so as an alternative, you may define a <em>constructor</em> for your module
that accepts annotated parameters (as with <a
href="defining-tapestry-ioc-services.html">service builder
injection</a>).</p><p>This gives you a chance to store common services in
instance variables for later use inside service builder 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;">public class MyModule
{
private final JobScheduler scheduler;
@@ -118,7 +118,7 @@ public class MyAppModule
return indexer;
}
}</pre>
-</div></div><p>Notice that we've switched from <em>static</em> methods to
<em>instance</em> methods. Since the builder methods are not static, the
MyModule class will be instantiated so that the methods may be invoked. The
constructor receives two common dependencies, which are stored into instance
fields that may later be used inside service builder methods such as
buildIndexer().</p><p>This approach is far from required; all the builder
methods of your module can be static if you wish. It is used when you have many
common dependencies and wish to avoid defining those dependencies as parameters
to multiple methods.</p><p>Tapestry IoC automatically resolves the parameter
type (JobScheduler and FileSystem, in the example) to the corresponding
services that implement that type. When there's more than one service that
implements the service interface, you'll get an error (but additional
annotations and configuration can be used to ensure the correct service
injected).</p><p>For modules
, there are two additional parameter types that are used to refer to
<em>resources</em> that can be provided to the module instance (rather than
<em>services</em> which may be injected).</p><ul><li><a class="external-link"
href="http://www.slf4j.org/api/org/slf4j/Logger.html"
rel="nofollow">org.slf4j.Logger</a>: logger for the module (derived from the
module's class name)</li><li><a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/ObjectLocator.html">ObjectLocator</a>:
access to other services<br clear="none"> Note that the fields are final: this
is important. Tapestry IoC is thread-safe and you largely never have to think
about concurrency issues. But in a busy application, different services may be
built by different threads simultaneously. Each module class is a singleton,
instantiated at most once, and making these fields final ensures that the
values are available across multiple threads. Refer to Brian Goetz's <a
class="externa
l-link" href="http://www.javaconcurrencyinpractice.com/" rel="nofollow">Java
Concurrency in Practice</a> for a more complete explanation of the relationship
between final fields, constructors, and threads ... or just trust
us!</li></ul><p>Care should be taken with this approach: in some circumstances,
you may force a situation in which the module constructor is dependent on
itself. For example, if you invoke a method on any injected services defined
within the same module from the module class' constructor, then the service
implementation will be needed. Creating service implementations requires the
module builder instance ... that's a recursive reference.</p><p>Tapestry
detects these scenarios and throws a runtime exception to prevent an endless
loop.</p><h1 id="TapestryIoCModules-ModuleClassImplementationNotes">Module
Class Implementation Notes</h1><p>Module classes are designed to be very, very
simple to implement.</p><p>Again, keep the methods very simple. Use <a
href="tapestry
-ioc-modules.html">parameter injection</a> to gain access to the dependencies
you need.</p><p>Be careful about inheritance. Tapestry will see all
<em>public</em> methods, even those inherited from base classes. Tapestry
<em>only</em> sees public methods.</p><p>By convention, module class names end
in Module and are final classes.</p><p>You don't <em>have</em> to define your
methods as static. The use of static methods is only absolutely necessary in a
few cases, where the constructor for a module is dependent on contributions
from the same module (this creates a chicken-and-the-egg situation that is
resolved through static methods).</p><h1
id="TapestryIoCModules-DefaultMarker">Default Marker</h1><p>Services are often
referenced by a particular marker interface on the method or constructor
parameter. Tapestry will use the intersection of services with that exact
marker and assignable by type to find a unique service to inject.</p><p>Often,
all services in a module should share a mark
er, this can be specified with a @Marker annotation on the module class. For
example, the TapestryIOCModule:</p><div class="code panel pdl"
style="border-width: 1px;"><div class="codeContent panelContent pdl">
+</div></div><p>Notice that we've switched from <em>static</em> methods to
<em>instance</em> methods. Since the builder methods are not static, the
MyModule class will be instantiated so that the methods may be invoked. The
constructor receives two common dependencies, which are stored into instance
fields that may later be used inside service builder methods such as
buildIndexer().</p><p>This approach is far from required; all the builder
methods of your module can be static if you wish. It is used when you have many
common dependencies and wish to avoid defining those dependencies as parameters
to multiple methods.</p><p>Tapestry IoC automatically resolves the parameter
type (JobScheduler and FileSystem, in the example) to the corresponding
services that implement that type. When there's more than one service that
implements the service interface, you'll get an error (but additional
annotations and configuration can be used to ensure the correct service
injected).</p><p>For modules
, there are two additional parameter types that are used to refer to
<em>resources</em> that can be provided to the module instance (rather than
<em>services</em> which may be injected).</p><ul><li><a class="external-link"
href="http://www.slf4j.org/api/org/slf4j/Logger.html"
rel="nofollow">org.slf4j.Logger</a>: logger for the module (derived from the
module's class name)</li><li><a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/ObjectLocator.html">ObjectLocator</a>:
access to other services</li></ul><p>Note that the fields are final: this is
important. Tapestry IoC is thread-safe and you largely never have to think
about concurrency issues. But in a busy application, different services may be
built by different threads simultaneously. Each module class is a singleton,
instantiated at most once, and making these fields final ensures that the
values are available across multiple threads. Refer to Brian Goetz's <a
class="external-lin
k" href="http://www.javaconcurrencyinpractice.com/" rel="nofollow">Java
Concurrency in Practice</a> for a more complete explanation of the relationship
between final fields, constructors, and threads ... or just trust
us!</p><p>Care should be taken with this approach: in some circumstances, you
may force a situation in which the module constructor is dependent on itself.
For example, if you invoke a method on any injected services defined within the
same module from the module class' constructor, then the service implementation
will be needed. Creating service implementations requires the module builder
instance ... that's a recursive reference.</p><p>Tapestry detects these
scenarios and throws a runtime exception to prevent an endless loop.</p><h1
id="TapestryIoCModules-ModuleClassImplementationNotes">Module Class
Implementation Notes</h1><p>Module classes are designed to be very, very simple
to implement.</p><p>Again, keep the methods very simple. Use <a
href="defining-tapestry-i
oc-services.html">parameter injection</a> to gain access to the dependencies
you need.</p><p>Be careful about inheritance. Tapestry will see all
<em>public</em> methods, even those inherited from base classes. Tapestry
<em>only</em> sees public methods.</p><p>By convention, module class names end
in Module and are final classes.</p><p>You don't <em>have</em> to define your
methods as static. The use of static methods is only absolutely necessary in a
few cases, where the constructor for a module is dependent on contributions
from the same module (this creates a chicken-and-the-egg situation that is
resolved through static methods).</p><h1
id="TapestryIoCModules-DefaultMarker">Default Marker</h1><p>Services are often
referenced by a particular marker interface on the method or constructor
parameter. Tapestry will use the intersection of services with that exact
marker and assignable by type to find a unique service to inject.</p><p>Often,
all services in a module should share a marke
r, this can be specified with a @Marker annotation on the module class. For
example, the TapestryIOCModule:</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(Builtin.class)
public final class TapestryIOCModule
{