tapestry-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From conflue...@apache.org
Subject [CONF] Apache Tapestry > IoC
Date Wed, 08 Dec 2010 01:04:00 GMT
<html>
<head>
    <base href="https://cwiki.apache.org/confluence">
            <link rel="stylesheet" href="/confluence/s/1810/9/12/_/styles/combined.css?spaceKey=TAPESTRY&amp;forWysiwyg=true"
type="text/css">
    </head>
<body style="background: white;" bgcolor="white" class="email-body">
<div id="pageContent">
<div id="notificationFormat">
<div class="wiki-content">
<div class="email">
    <h2><a href="https://cwiki.apache.org/confluence/display/TAPESTRY/IoC">IoC</a></h2>
    <h4>Page <b>edited</b> by             <a href="https://cwiki.apache.org/confluence/display/~bobharner">Bob
Harner</a>
    </h4>
        <div id="versionComment">
        <b>Comment:</b>
        Reverted from v. 8<br />
    </div>
        <br/>
                         <h4>Changes (1)</h4>
                                 
    
<div id="page-diffs">
            <table class="diff" cellpadding="0" cellspacing="0">
            <tr><td class="diff-snipped" >...<br></td></tr>
            <tr><td class="diff-unchanged" > <br>The *point of Injection*
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. <br></td></tr>
            <tr><td class="diff-added-lines" style="background-color: #dfd;">
<br>---- <br>{display-footnotes} <br></td></tr>
        </table>
</div>                            <h4>Full Content</h4>
                    <div class="notificationGreySide">
        <h1><a name="IoC-TapestryInversionofControlContainer"></a>Tapestry
Inversion of Control Container</h1>

<div class='navmenu' style='float:right; background:white; margin:3px; padding:3px'><div
class='panelMacro'><table class='infoMacro'><colgroup><col width='24'><col></colgroup><tr><td
valign='top'><img src="/confluence/images/icons/emoticons/information.gif" width="16"
height="16" align="absmiddle" alt="" border="0"></td><td><b>Related Article</b><br
/><ul>
	<li><a href="/confluence/display/TAPESTRY/Tapestry+Inversion+of+Control+Container"
title="Tapestry Inversion of Control Container">IoC FAQ</a></li>
</ul>
</td></tr></table></div></div>

<p>The inner construction of the Tapestry framework is based on <em>inversion
of control</em><style type='text/css'>
.FootnoteMarker, .FootnoteNum a {
  background: transparent url(/confluence/download/resources/com.adaptavist.confluence.footnoteMacros:footnote/gfx/footnote.png)
no-repeat top right;
  padding: 1px 2px 0px 1px;
  border-left: 1px solid #8898B8;
  border-bottom: 1px solid #6B7C9B;
  margin: 1px;
  text-decoration: none;
}
.FootnoteNum a {
  margin-top: 2px;
  margin-right: 0px;
}
.FootnoteNum {
  font-size: x-small;
  text-align: right;
  padding-bottom: 4px;
}
.footnote-th1 {
  text-align: right;
}
.Footnote {
  padding-left: 7px;
  margin-bottom: 4px;
  border: 1px none #DDDDDD;
  writingMode: tb-rl;
}
.accessibility {
     display: none;
     visibility: hidden;
}
@media aural,braille,embossed {
        .FootnoteMarker, .FootnoteNum a {
         border: 1px solid #000000;
         background: #ffffff none;
    }
    .accessibility {
         display: run-in;
         visibility: visible;
    }
}
</style>
<script type='text/javascript' language='JavaScript'>
//<!--\n
var effectInProgress = {};
var despamEffect = function (id,effectType,duration) {
  if ((effectInProgress[id]) || (typeof(Effect)=="undefined") || (typeof(Effect[effectType])=="undefined"))
return;
  new Effect[effectType](id);
  effectInProgress[id]=true;
  setTimeout('effectInProgress[\"'+id+'\"]=false;',duration*1000);
};
var oldFootnoteId = '';
var footnoteHighlight = function(id,pulsateNum) {
  if (oldFootnoteId!='') document.getElementById('Footnote'+oldFootnoteId).style['borderStyle']
= 'none';
  oldFootnoteId = id;
  document.getElementById('Footnote'+id).style['borderStyle'] = 'solid';
  despamEffect('Footnote'+id,'Highlight',1)
  if (pulsateNum) despamEffect('FootnoteNum'+id,'Pulsate',3)
}
var footnoteMarkerHighlight = function(id) {
  if (oldFootnoteId!='') document.getElementById('Footnote'+oldFootnoteId).style['borderStyle']
= 'none';
  oldFootnoteId = '';
  despamEffect('FootnoteMarker'+id,'Pulsate',3)
}
//-->
</script>

<sup id='FootnoteMarker1'>
    <a name='FootnoteMarker1'
        href='#Footnote1'
        onClick='footnoteHighlight("1",true);'
        alt='Footnote: Click here to display the footnote'
        title='Footnote: Click here to display the footnote'
        class='FootnoteMarker'>
            1
    </a>
</sup>
 (IoC), a design approach that allows a working system to be fabricated from many small, easily
testable pieces.</p>

<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 Apache HiveMind
<sup id='FootnoteMarker2'>
    <a name='FootnoteMarker2'
        href='#Footnote2'
        onClick='footnoteHighlight("2",true);'
        alt='Footnote: Click here to display the footnote'
        title='Footnote: Click here to display the footnote'
        class='FootnoteMarker'>
            2
    </a>
</sup>
 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><a name="IoC-WhyNotSpring%3F"></a>Why Not Spring?</h2>

<p>Spring
<sup id='FootnoteMarker3'>
    <a name='FootnoteMarker3'
        href='#Footnote3'
        onClick='footnoteHighlight("3",true);'
        alt='Footnote: Click here to display the footnote'
        title='Footnote: Click here to display the footnote'
        class='FootnoteMarker'>
            3
    </a>
</sup>
 is the most successful IoC container project. The Spring project combines a very good IoC
container, integrated AspectJ
<sup id='FootnoteMarker4'>
    <a name='FootnoteMarker4'
        href='#Footnote4'
        onClick='footnoteHighlight("4",true);'
        alt='Footnote: Click here to display the footnote'
        title='Footnote: Click here to display the footnote'
        class='FootnoteMarker'>
            4
    </a>
</sup>
 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 spot 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.</li>
</ul>


<p>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).</p>

<h2><a name="IoC-WhyNotHiveMind%3F"></a>Why Not HiveMind?</h2>

<p>The difficulty of managing the release schedules of two complex frameworks has proven
to be an issue. HiveMind's 2.0 release will incorporate ideas similar to those present in
Tapestry 5 IoC, but will also maintain legacy support for the existing XML-driven approach.</p>

<p>The use of HiveMind is also related to one of the common criticisms of Tapestry 4:
startup time. The time it takes to parse and organize all that XML shows 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 Annotations
<sup id='FootnoteMarker5'>
    <a name='FootnoteMarker5'
        href='#Footnote5'
        onClick='footnoteHighlight("5",true);'
        alt='Footnote: Click here to display the footnote'
        title='Footnote: Click here to display the footnote'
        class='FootnoteMarker'>
            5
    </a>
</sup>
 and runtime class generation via Javassist
<sup id='FootnoteMarker6'>
    <a name='FootnoteMarker6'
        href='#Footnote6'
        onClick='footnoteHighlight("6",true);'
        alt='Footnote: Click here to display the footnote'
        title='Footnote: Click here to display the footnote'
        class='FootnoteMarker'>
            6
    </a>
</sup>
) some of the precepts of HiveMind have been undermined. That is to say, in HiveMind (and
Spring), all that XML is an awkward way to describe a few basic Java operations: instantiating
classes and invoking methods on those classes (to inject dependencies 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, representing lessons
learned while creating both HiveMind and Tapestry 4. HiveMind itself has wound down (it is
not longer in active development), with the user base moving to Tapestry 5.</p>

<h2><a name="IoC-WhynotGuice%3F"></a>Why not Guice?</h2>

<p>Google Guice
<sup id='FootnoteMarker7'>
    <a name='FootnoteMarker7'
        href='#Footnote7'
        onClick='footnoteHighlight("7",true);'
        alt='Footnote: Click here to display the footnote'
        title='Footnote: Click here to display the footnote'
        class='FootnoteMarker'>
            7
    </a>
</sup>
 is a 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><a name="IoC-Goals"></a>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
in XML is ultimately more verbose and unwieldy. As the <a href="/confluence/display/TAPESTRY/Defining+Tapestry+IOC+Services"
title="Defining Tapestry IOC Services">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 reasonable toString() method
<sup id='FootnoteMarker8'>
    <a name='FootnoteMarker8'
        href='#Footnote8'
        onClick='footnoteHighlight("8",true);'
        alt='Footnote: Click here to display the footnote'
        title='Footnote: Click here to display the footnote'
        class='FootnoteMarker'>
            8
    </a>
</sup>
, 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 href="http://boardgamegeek.com/game/188" class="external-link"
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 <em>Law of Demeter</em>
<sup id='FootnoteMarker9'>
    <a name='FootnoteMarker9'
        href='#Footnote9'
        onClick='footnoteHighlight("9",true);'
        alt='Footnote: Click here to display the footnote'
        title='Footnote: Click here to display the footnote'
        class='FootnoteMarker'>
            9
    </a>
</sup>
. 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 <em>The Pragmatic Programmer</em>
<sup id='FootnoteMarker10'>
    <a name='FootnoteMarker10'
        href='#Footnote10'
        onClick='footnoteHighlight("10",true);'
        alt='Footnote: Click here to display the footnote'
        title='Footnote: Click here to display the footnote'
        class='FootnoteMarker'>
            10
    </a>
</sup>
 for more insights into building solid code.</p>

<h1><a name="IoC-Overview"></a>Overview</h1>

<p>The Tapestry IoC container takes over all the plumbing necessary for a highly scalable,
extensible, thread-safe, testable application. Please see the <a href="/confluence/display/TAPESTRY/IoC+-+overview"
title="IoC - overview">main Tapestry IoC overview</a> for more details.</p>

<h1><a name="IoC-Terminology"></a>Terminology</h1>

<p>The basic unit in Tapestry IoC is a <b>service</b>. A service consists
of a <b>service interface</b> and a <b>service implementation</b>.
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='panelMacro'><table class='noteMacro'><colgroup><col width='24'><col></colgroup><tr><td
valign='top'><img src="/confluence/images/icons/emoticons/warning.gif" width="16" height="16"
align="absmiddle" alt="" border="0"></td><td>The evolution of the Tapestry
IoC is to eventually eliminate service ids and work totally in terms of service interfaces
and marker annotations.</td></tr></table></div>

<p>Services are aggregated into <b>modules</b>:</p>

<ul>
	<li>A module is defined by a <b>module class</b>, 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 <b>service builder
methods</b>.</p>

<p>The <b>registry</b> 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 even the case of the search key doesn't match the case of the service id itself).</p>

<p>Services may be <b>decorated</b> by <b>service decorator methods</b>.
These methods create <b>interceptor</b> 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 <b>configuration</b>. 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 <b>contributions</b>
provided by one or more modules. <b>Service contributor methods</b> 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 <b>proxy</b> 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 <b>thread-safe</b>
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 <b>realization</b>, 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 <b>scope</b> that controls when the service is constructed,
as well as its visibility. The default scope is <b>singleton</b>, 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><b>Dependencies</b> are other services (or other objects) that are needed
by a service implementation. These dependencies can be <b>injected</b> 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 <b>collaborators</b>,
especially in the context of writing unit tests.</p>

<p>The <b>point of Injection</b> 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>

<hr />
<p><table class='Footnotes' style='width: 100%; border:none;' cellspacing='0' cellpadding='0'
summary='This table contains one or more notes for references made elsewhere on the page.'>
  <caption class='accessibility'>Footnotes</caption>
  <thead class='accessibility'>
    <tr class='accessibility'>
      <th class='accessibility' id='footnote-th1'>Reference</th>
      <th class='accessibility' id='footnote-th2'>Notes</th>
    </tr>
  </thead>
  <tbody>
    <tr name='Footnote1'>
      <td valign='top' class='FootnoteNum' headings='footnote-th1'>
        <a href='#FootnoteMarker1'
          onClick='footnoteMarkerHighlight("1");'
          onMouseOver='footnoteHighlight("1",false);'
          alt='Footnote: Click to return to reference in text'
          title='Footnote: Click to return to reference in text'
          id='FootnoteNum1'>
            1
        </a>
      </td>
      <td id='Footnote1'
        valign='top'
        width='100%'
        class='Footnote'
        headings='footnote-th2'>
          <a href="http://www.martinfowler.com/articles/injection.html" class="external-link"
rel="nofollow">http://www.martinfowler.com/articles/injection.html</a>
      </td>
    </tr>
    <tr name='Footnote2'>
      <td valign='top' class='FootnoteNum' headings='footnote-th1'>
        <a href='#FootnoteMarker2'
          onClick='footnoteMarkerHighlight("2");'
          onMouseOver='footnoteHighlight("2",false);'
          alt='Footnote: Click to return to reference in text'
          title='Footnote: Click to return to reference in text'
          id='FootnoteNum2'>
            2
        </a>
      </td>
      <td id='Footnote2'
        valign='top'
        width='100%'
        class='Footnote'
        headings='footnote-th2'>
          <a href="http://hivemind.apache.org/" class="external-link" rel="nofollow">http://hivemind.apache.org/</a>
      </td>
    </tr>
    <tr name='Footnote3'>
      <td valign='top' class='FootnoteNum' headings='footnote-th1'>
        <a href='#FootnoteMarker3'
          onClick='footnoteMarkerHighlight("3");'
          onMouseOver='footnoteHighlight("3",false);'
          alt='Footnote: Click to return to reference in text'
          title='Footnote: Click to return to reference in text'
          id='FootnoteNum3'>
            3
        </a>
      </td>
      <td id='Footnote3'
        valign='top'
        width='100%'
        class='Footnote'
        headings='footnote-th2'>
          <a href="http://www.springframework.org" class="external-link" rel="nofollow">http://www.springframework.org</a>
      </td>
    </tr>
    <tr name='Footnote4'>
      <td valign='top' class='FootnoteNum' headings='footnote-th1'>
        <a href='#FootnoteMarker4'
          onClick='footnoteMarkerHighlight("4");'
          onMouseOver='footnoteHighlight("4",false);'
          alt='Footnote: Click to return to reference in text'
          title='Footnote: Click to return to reference in text'
          id='FootnoteNum4'>
            4
        </a>
      </td>
      <td id='Footnote4'
        valign='top'
        width='100%'
        class='Footnote'
        headings='footnote-th2'>
          <a href="http://www.eclipse.org/aspectj/" class="external-link" rel="nofollow">http://www.eclipse.org/aspectj/</a>
      </td>
    </tr>
    <tr name='Footnote5'>
      <td valign='top' class='FootnoteNum' headings='footnote-th1'>
        <a href='#FootnoteMarker5'
          onClick='footnoteMarkerHighlight("5");'
          onMouseOver='footnoteHighlight("5",false);'
          alt='Footnote: Click to return to reference in text'
          title='Footnote: Click to return to reference in text'
          id='FootnoteNum5'>
            5
        </a>
      </td>
      <td id='Footnote5'
        valign='top'
        width='100%'
        class='Footnote'
        headings='footnote-th2'>
          <a href="http://download.oracle.com/javase/tutorial/java/javaOO/annotations.html"
class="external-link" rel="nofollow">http://download.oracle.com/javase/tutorial/java/javaOO/annotations.html</a>
      </td>
    </tr>
    <tr name='Footnote6'>
      <td valign='top' class='FootnoteNum' headings='footnote-th1'>
        <a href='#FootnoteMarker6'
          onClick='footnoteMarkerHighlight("6");'
          onMouseOver='footnoteHighlight("6",false);'
          alt='Footnote: Click to return to reference in text'
          title='Footnote: Click to return to reference in text'
          id='FootnoteNum6'>
            6
        </a>
      </td>
      <td id='Footnote6'
        valign='top'
        width='100%'
        class='Footnote'
        headings='footnote-th2'>
          <a href="http://www.jboss.org/products/javassist" class="external-link" rel="nofollow">http://www.jboss.org/products/javassist</a>]
      </td>
    </tr>
    <tr name='Footnote7'>
      <td valign='top' class='FootnoteNum' headings='footnote-th1'>
        <a href='#FootnoteMarker7'
          onClick='footnoteMarkerHighlight("7");'
          onMouseOver='footnoteHighlight("7",false);'
          alt='Footnote: Click to return to reference in text'
          title='Footnote: Click to return to reference in text'
          id='FootnoteNum7'>
            7
        </a>
      </td>
      <td id='Footnote7'
        valign='top'
        width='100%'
        class='Footnote'
        headings='footnote-th2'>
          <a href="http://code.google.com/p/google-guice/" class="external-link" rel="nofollow">http://code.google.com/p/google-guice/</a>
      </td>
    </tr>
    <tr name='Footnote8'>
      <td valign='top' class='FootnoteNum' headings='footnote-th1'>
        <a href='#FootnoteMarker8'
          onClick='footnoteMarkerHighlight("8");'
          onMouseOver='footnoteHighlight("8",false);'
          alt='Footnote: Click to return to reference in text'
          title='Footnote: Click to return to reference in text'
          id='FootnoteNum8'>
            8
        </a>
      </td>
      <td id='Footnote8'
        valign='top'
        width='100%'
        class='Footnote'
        headings='footnote-th2'>
          <a href="http://howardlewisship.com/blog/2003/08/importance-of-tostring.html"
class="external-link" rel="nofollow">http://howardlewisship.com/blog/2003/08/importance-of-tostring.html</a>
      </td>
    </tr>
    <tr name='Footnote9'>
      <td valign='top' class='FootnoteNum' headings='footnote-th1'>
        <a href='#FootnoteMarker9'
          onClick='footnoteMarkerHighlight("9");'
          onMouseOver='footnoteHighlight("9",false);'
          alt='Footnote: Click to return to reference in text'
          title='Footnote: Click to return to reference in text'
          id='FootnoteNum9'>
            9
        </a>
      </td>
      <td id='Footnote9'
        valign='top'
        width='100%'
        class='Footnote'
        headings='footnote-th2'>
          <a href="http://www.ccs.neu.edu/research/demeter/demeter-method/LawOfDemeter/general-formulation.html"
class="external-link" rel="nofollow">http://www.ccs.neu.edu/research/demeter/demeter-method/LawOfDemeter/general-formulation.html</a>
      </td>
    </tr>
    <tr name='Footnote10'>
      <td valign='top' class='FootnoteNum' headings='footnote-th1'>
        <a href='#FootnoteMarker10'
          onClick='footnoteMarkerHighlight("10");'
          onMouseOver='footnoteHighlight("10",false);'
          alt='Footnote: Click to return to reference in text'
          title='Footnote: Click to return to reference in text'
          id='FootnoteNum10'>
            10
        </a>
      </td>
      <td id='Footnote10'
        valign='top'
        width='100%'
        class='Footnote'
        headings='footnote-th2'>
          <a href="http://www.pragmaticprogrammer.com/ppbook/index.shtml" class="external-link"
rel="nofollow">http://www.pragmaticprogrammer.com/ppbook/index.shtml</a>
      </td>
    </tr>
  </tbody>
</table></p>
    </div>
        <div id="commentsSection" class="wiki-content pageSection">
        <div style="float: right;">
            <a href="https://cwiki.apache.org/confluence/users/viewnotifications.action"
class="grey">Change Notification Preferences</a>
        </div>
        <a href="https://cwiki.apache.org/confluence/display/TAPESTRY/IoC">View Online</a>
        |
        <a href="https://cwiki.apache.org/confluence/pages/diffpagesbyversion.action?pageId=23338502&revisedVersion=10&originalVersion=9">View
Changes</a>
            </div>
</div>
</div>
</div>
</div>
</body>
</html>

Mime
View raw message