You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tapestry.apache.org by bu...@apache.org on 2018/02/18 19:21:01 UTC

svn commit: r1025566 [1/2] - in /websites/production/tapestry/content: cache/main.pageCache development-dashboard.html integration-testing.html ioc.html tapestry-ioc-modules.html tapestry-ioc-overview.html unit-testing-pages-or-components.html

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>&#160;<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>&#160;</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>&#160;<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>&#160;</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
 {