Modified: websites/production/tapestry/content/tapestry-ioc-overview.html
==============================================================================
--- websites/production/tapestry/content/tapestry-ioc-overview.html (original)
+++ websites/production/tapestry/content/tapestry-ioc-overview.html Sun Feb 18 
19:21:00 2018
@@ -75,7 +75,7 @@
       </div>
 
       <div id="content">
-                <div id="ConfluenceContent"><p>Even today, with the 
overwhelming success of <a  class="external-link" 
href="http://www.springframework.org"; rel="nofollow">Spring</a> and the rise of 
smaller, simpler approaches to building applications (in contrast to the 
heavyweight EJB 2.0 approach), many people still have trouble wrapping their 
heads around Inversion of Control.</p><p>Really understanding IoC is a new step 
for many developers. If you can remember back to when you made the transition 
from procedural programming (in C, or BASIC) to object oriented programming, 
you might remember the point where you "got it". The point where it made sense 
to have methods on objects, and data inside objects.</p><p>Inversion of Control 
builds upon those ideas. The goal is to make code more robust (that is, with 
fewer errors), more reusable and much easier to test.</p><p>Prior to IoC 
approaches, most developers were used to a more <em>monolithic</em> design, 
with a few core objects and a
  <code>main()</code> method somewhere that starts the ball rolling. 
<code>main()</code> instantiates the first couple of classes, and those classes 
end up instantiating and using all the other classes in the 
system.</p><p>That's an <em>unmanaged</em> system. Most desktop applications 
are unmanaged, so it's a very familiar pattern, and easy to get your head 
around.</p><p>By contrast, web applications are a <em>managed</em> environment. 
You don't write a main(), you don't control startup. You <em>configure</em> the 
Servlet API to tell it about your servlet classes to be instantiated, and their 
life cycle is totally controlled by the servlet container.</p><p>Inversion of 
Control is just a more general application of this approach. The container is 
ultimately responsible for instantiating and configuring the objects you tell 
it about, and running their entire life cycle of those objects.</p><p>Web 
applications are more complicated to write than monolithic applications, 
largely because o
 f <em>multithreading</em>. Your code will be servicing many different users 
simultaneously across many different threads. This tends to complicate the code 
you write, since some fundamental aspects of object oriented development get 
called into question: in particular, the use of <em>internal state</em> (values 
stored inside instance variables), since in a multithreaded environment, that's 
no longer the safe place it is in traditional development. Shared objects plus 
internal state plus multiple threads equals an broken, unpredictable 
application.</p><p>Frameworks such as Tapestry &#8211; both the IoC container, 
and the web framework itself &#8211; exist to help.</p><p>When thinking in 
terms of IoC, <strong>small is beautiful</strong>. What does that mean? It 
means small classes and small methods are easier to code than large ones. At 
one extreme, we have servlets circa 1997 (and Visual Basic before that) with 
methods a thousand lines long, and no distinction between business logic 
 and view logic. Everything mixed together into an untestable jumble.</p><p>At 
the other extreme is IoC: small objects, each with a specific purpose, 
collaborating with other small objects.</p><p>Using unit tests, in 
collaboration with tools such as <a  class="external-link" 
href="http://easymock.org/"; rel="nofollow">EasyMock</a>, you can have a code 
base that is easy to maintain, easy to extend, and easy to test. And by 
factoring out a lot of <em>plumbing</em> code, your code base will not only be 
easier to work with, it will be smaller.</p><h2 
id="TapestryIoCOverview-LivingontheFrontier">Living on the 
Frontier</h2><p>Coding applications the traditional way is like being a 
homesteader on the American frontier in the 1800's. You're responsible for 
every aspect of your house: every board, every nail, every stick of furniture 
is something you personally created. There <em>is</em> a great comfort in total 
self reliance. Even if your house is small, the windows are a bit drafty or the 
fl
 oorboards creak a little, you know exactly <em>why</em> things are not-quite 
perfect.</p><p>Flash forward to modern cities or modern suburbia and it's a 
whole different story. Houses are built to specification from design plans, 
made from common materials, by many specializing tradespeople. Construction 
codes dictate how plumbing, wiring and framing should be performed. A 
home-owner may not even know how to drive a nail, but can still take comfort in 
draft-free windows, solid floors and working plumbing.</p><p>To extend the 
metaphor, a house in a town is not alone and self-reliant the way a frontier 
house is. The town house is situated on a street, in a neighborhood, within a 
town. The town provides services (utilities, police, fire control, streets and 
sewers) to houses in a uniform way. Each house just needs to connect up to 
those services.</p><h2 id="TapestryIoCOverview-TheWorldoftheContainer">The 
World of the Container</h2><p>So the IoC container is the "town" and in the 
world o
 f the IoC container, everything has a name, a place, and a relationship to 
everything else in the container. Tapestry calls this world "The 
Registry".</p><p><span class="confluence-embedded-file-wrapper"><img 
class="confluence-embedded-image confluence-external-resource" 
src="https://cwiki-test.apache.org/confluence/download/attachments/23338486/ioc-overview.png?version=1&amp;modificationDate=1290980234000&amp;api=v2";
 
data-image-src="https://cwiki-test.apache.org/confluence/download/attachments/23338486/ioc-overview.png?version=1&amp;modificationDate=1290980234000&amp;api=v2";></span></p><p>Here
 we're seeing a few services from the built-in Tapestry IoC module, and a few 
of the services from the Tapestry web framework module. In fact, there are over 
100 services, all interrelated, in the Registry ... and that's before you add 
your own to the mix. The IoC Registry treats all the services uniformly, 
regardless of whether they are part of Tapestry, or part of your application, 
or part o
 f an add-on library.</p><p>Tapestry IoC's job is to make all of these services 
available to each other, and to the outside world. The outside world could be a 
standalone application, or it could be an application built on top of the 
Tapestry web framework.</p><h2 
id="TapestryIoCOverview-ServiceLifeCycle">Service Life Cycle</h2><p>Tapestry 
services are <em>lazy</em>, which means they are not fully instantiated until 
they are absolutely needed. Often, what looks like a service is really a proxy 
object ... the first time any method of the proxy is invoked, the actual 
service is instantiated and initialized (Tapestry uses the term 
<em>realized</em> for this process). Of course, this is all absolutely 
thread-safe.</p><p>Initially a service is <em>defined</em>, meaning some module 
has defined the service. Later, the service will be <em>virtual</em>, meaning a 
proxy has been created. This occurs most often because some other service 
<em>depends</em> on it, but hasn't gotten around to invok
 ing methods on it. Finally, a service that is ready to use is 
<em>realized</em>. What's nice is that your code neither knows nor cares about 
the life cycle of the service, because of the magic of the proxy.</p><p>In 
fact, when a Tapestry web application starts up, before it services its first 
request, only about 20% of the services have been realized; the remainder are 
defined or virtual.</p><h2 id="TapestryIoCOverview-Classvs.Service">Class vs. 
Service</h2><p>A Tapestry service is more than just a class. First of all, it 
is a combination of an <em>interface</em> that defines the operations of the 
service, and an <em>implementation class</em> that implements the 
interface.</p><p>Why this extra division? Having a service interface is what 
lets Tapestry create proxies and perform other operations. It's also a very 
good practice to code to an interface, rather than a specific implementation. 
You'll often be surprised at the kinds of things you can accomplish by 
substituting one impleme
 ntation for another.</p><p>Tapestry is also very aware that a service will 
have dependencies on other services. It may also have other needs ... for 
example, in Tapestry IoC, the container provides services with access to 
Loggers.</p><p>Tapestry IoC also has support for other configuration that may 
be provided to services when they are realized.</p><h2 
id="TapestryIoCOverview-DependencyInjection">Dependency Injection</h2><p>Main 
Article: <a  href="tapestry-ioc-overview.html">Tapestry IoC 
Overview</a></p><div class="aui-label" style="float:right" title="Related 
Articles">
+                <div id="ConfluenceContent"><p>Even today, with the 
overwhelming success of <a  class="external-link" 
href="http://www.springframework.org"; rel="nofollow">Spring</a> and the rise of 
smaller, simpler approaches to building applications (in contrast to the 
heavyweight EJB 2.0 approach), many people still have trouble wrapping their 
heads around Inversion of Control.</p><p>Really understanding IoC is a new step 
for many developers. If you can remember back to when you made the transition 
from procedural programming (in C, or BASIC) to object oriented programming, 
you might remember the point where you "got it". The point where it made sense 
to have methods on objects, and data inside objects.</p><p>Inversion of Control 
builds upon those ideas. The goal is to make code more robust (that is, with 
fewer errors), more reusable and much easier to test.</p><p>Prior to IoC 
approaches, most developers were used to a more <em>monolithic</em> design, 
with a few core objects and a
  <code>main()</code> method somewhere that starts the ball rolling. 
<code>main()</code> instantiates the first couple of classes, and those classes 
end up instantiating and using all the other classes in the 
system.</p><p>That's an <em>unmanaged</em> system. Most desktop applications 
are unmanaged, so it's a very familiar pattern, and easy to get your head 
around.</p><p>By contrast, web applications are a <em>managed</em> environment. 
You don't write a main(), you don't control startup. You <em>configure</em> the 
Servlet API to tell it about your servlet classes to be instantiated, and their 
life cycle is totally controlled by the servlet container.</p><p>Inversion of 
Control is just a more general application of this approach. The container is 
ultimately responsible for instantiating and configuring the objects you tell 
it about, and running their entire life cycle of those objects.</p><p>Web 
applications are more complicated to write than monolithic applications, 
largely because o
 f <em>multithreading</em>. Your code will be servicing many different users 
simultaneously across many different threads. This tends to complicate the code 
you write, since some fundamental aspects of object oriented development get 
called into question: in particular, the use of <em>internal state</em> (values 
stored inside instance variables), since in a multithreaded environment, that's 
no longer the safe place it is in traditional development. Shared objects plus 
internal state plus multiple threads equals an broken, unpredictable 
application.</p><p>Frameworks such as Tapestry &#8211; both the IoC container, 
and the web framework itself &#8211; exist to help.</p><p>When thinking in 
terms of IoC, <strong>small is beautiful</strong>. What does that mean? It 
means small classes and small methods are easier to code than large ones. At 
one extreme, we have servlets circa 1997 (and Visual Basic before that) with 
methods a thousand lines long, and no distinction between business logic 
 and view logic. Everything mixed together into an untestable jumble.</p><p>At 
the other extreme is IoC: small objects, each with a specific purpose, 
collaborating with other small objects.</p><p>Using unit tests, in 
collaboration with tools such as <a  class="external-link" 
href="http://easymock.org/"; rel="nofollow">EasyMock</a>, you can have a code 
base that is easy to maintain, easy to extend, and easy to test. And by 
factoring out a lot of <em>plumbing</em> code, your code base will not only be 
easier to work with, it will be smaller.</p><h2 
id="TapestryIoCOverview-LivingontheFrontier">Living on the 
Frontier</h2><p>Coding applications the traditional way is like being a 
homesteader on the American frontier in the 1800's. You're responsible for 
every aspect of your house: every board, every nail, every stick of furniture 
is something you personally created. There <em>is</em> a great comfort in total 
self reliance. Even if your house is small, the windows are a bit drafty or the 
fl
 oorboards creak a little, you know exactly <em>why</em> things are not-quite 
perfect.</p><p>Flash forward to modern cities or modern suburbia and it's a 
whole different story. Houses are built to specification from design plans, 
made from common materials, by many specializing tradespeople. Construction 
codes dictate how plumbing, wiring and framing should be performed. A 
home-owner may not even know how to drive a nail, but can still take comfort in 
draft-free windows, solid floors and working plumbing.</p><p>To extend the 
metaphor, a house in a town is not alone and self-reliant the way a frontier 
house is. The town house is situated on a street, in a neighborhood, within a 
town. The town provides services (utilities, police, fire control, streets and 
sewers) to houses in a uniform way. Each house just needs to connect up to 
those services.</p><h2 id="TapestryIoCOverview-TheWorldoftheContainer">The 
World of the Container</h2><p>So the IoC container is the "town" and in the 
world o
 f the IoC container, everything has a name, a place, and a relationship to 
everything else in the container. Tapestry calls this world "The 
Registry".</p><p><span class="confluence-embedded-file-wrapper"><img 
class="confluence-embedded-image confluence-external-resource" 
src="https://cwiki-test.apache.org/confluence/download/attachments/23338486/ioc-overview.png?version=1&amp;modificationDate=1290980234000&amp;api=v2";
 
data-image-src="https://cwiki-test.apache.org/confluence/download/attachments/23338486/ioc-overview.png?version=1&amp;modificationDate=1290980234000&amp;api=v2";></span></p><p>Here
 we're seeing a few services from the built-in Tapestry IoC module, and a few 
of the services from the Tapestry web framework module. In fact, there are over 
100 services, all interrelated, in the Registry ... and that's before you add 
your own to the mix. The IoC Registry treats all the services uniformly, 
regardless of whether they are part of Tapestry, or part of your application, 
or part o
 f an add-on library.</p><p>Tapestry IoC's job is to make all of these services 
available to each other, and to the outside world. The outside world could be a 
standalone application, or it could be an application built on top of the 
Tapestry web framework.</p><h2 
id="TapestryIoCOverview-ServiceLifeCycle">Service Life Cycle</h2><p>Tapestry 
services are <em>lazy</em>, which means they are not fully instantiated until 
they are absolutely needed. Often, what looks like a service is really a proxy 
object ... the first time any method of the proxy is invoked, the actual 
service is instantiated and initialized (Tapestry uses the term 
<em>realized</em> for this process). Of course, this is all absolutely 
thread-safe.</p><p>Initially a service is <em>defined</em>, meaning some module 
has defined the service. Later, the service will be <em>virtual</em>, meaning a 
proxy has been created. This occurs most often because some other service 
<em>depends</em> on it, but hasn't gotten around to invok
 ing methods on it. Finally, a service that is ready to use is 
<em>realized</em>. What's nice is that your code neither knows nor cares about 
the life cycle of the service, because of the magic of the proxy.</p><p>In 
fact, when a Tapestry web application starts up, before it services its first 
request, only about 20% of the services have been realized; the remainder are 
defined or virtual.</p><h2 id="TapestryIoCOverview-Classvs.Service">Class vs. 
Service</h2><p>A Tapestry service is more than just a class. First of all, it 
is a combination of an <em>interface</em> that defines the operations of the 
service, and an <em>implementation class</em> that implements the 
interface.</p><p>Why this extra division? Having a service interface is what 
lets Tapestry create proxies and perform other operations. It's also a very 
good practice to code to an interface, rather than a specific implementation. 
You'll often be surprised at the kinds of things you can accomplish by 
substituting one impleme
 ntation for another.</p><p>Tapestry is also very aware that a service will 
have dependencies on other services. It may also have other needs ... for 
example, in Tapestry IoC, the container provides services with access to 
Loggers.</p><p>Tapestry IoC also has support for other configuration that may 
be provided to services when they are realized.</p><h2 
id="TapestryIoCOverview-DependencyInjection">Dependency Injection</h2><p>Main 
Article: <a  href="injection.html">Injection</a></p><div class="aui-label" 
style="float:right" title="Related Articles">
 
 
 
@@ -223,7 +223,7 @@
   }
 }
 </pre>
-</div></div><p>Again, we've omitted a few details related to the database the 
TableMetricProducer will point at (in fact, Tapestry IoC provides a lot of 
support for configuration of this type as well, which is yet another 
concern).</p><p>The MonitorModule class is a Tapestry IoC module: a class that 
defines and configures services.</p><p>The bind() method is the principle way 
that services are made known to the Registry: here we're binding a service 
interface to a service implementation. QueueWriter we've discussed already, and 
MetricScheduler is a service that is responsible for determining when 
MetricProducer instances run.</p><p>The contributeMetricScheduler() method 
allows the module to <em>contribute</em> into the MetricProducer service's 
<em>configuration</em>. More testability: the MetricProducer isn't tied to a 
pre-set list of producers, instead it will have a 
Collection&lt;MetricProducer&gt; injected into its constructor. Thus, when 
we're coding the MetricProducerImpl class
 , we can test it against mock implementations of MetricProducer.</p><p>The 
QueueWriter service is injected into the contributeMetricScheduler() method. 
Since there's only one QueueWriter service, Tapestry IoC is able to "find" the 
correct service based entirely on type. If, eventually, there's more than one 
QueueWriter service (perhaps pointing at different JMS queues), you would use 
an annotation on the parameter to help Tapestry connect the parameter to the 
appropriate service.</p><p>Presumably, there would be a couple of other 
parameters to the contributeMetricScheduler() method, to inject in a database 
URL or connection pool (that would, in turn, be passed to 
TableMetricProducer).</p><p>A new TableMetricProducer instance is created and 
contributed in. We could contribute as many producers as we like here. Other 
modules could also define a contributeMetricScheduler() method and contribute 
their own MetricProducer instances.</p><p>Meanwhile, the QueueWriterImpl class 
no longer nee
 ds the <code>instance</code> variable or getInstance() method, and the 
TableMetricProducer only needs a single constructor.</p><h2 
id="TapestryIoCOverview-AdvantagesofIoC:Summary">Advantages of IoC: 
Summary</h2><p>It would be ludicrous for us to claim that applications built 
without an IoC container are doomed to failure. There is overwhelming evidence 
that applications have been built without containers and have been perfectly 
successful.</p><p>What we are saying is that IoC techniques and discipline will 
lead to applications that are:</p><ul><li>More testable &#8211; smaller, 
simpler classes; coding to interfaces allows use of mock 
implementations</li><li>More robust &#8211; smaller, simpler classes; use of 
final variables; thread safety baked in</li><li>More scalable &#8211; thread 
safety baked in</li><li>Easier to maintain &#8211; less code, simpler 
classes</li><li>Easier to extend &#8211; new features are often additions (new 
services, new contributions) rather than changes to 
 existing classes</li></ul><p>What we're saying is that an IoC container allows 
you to work faster and smarter.</p><p>Many of these traits work together; for 
example, a more testable application is inherently more robust. Having a test 
suite makes it easier to maintain and extend your code, because its much easier 
to see if new features break existing ones. Simpler code plus tests also lowers 
the cost of entry for new developers coming on board, which allows for more 
developers to work efficiently on the same code base. The clean separation 
between interface and implementation also allows multiple developers to work on 
different aspects of the same code base with a lowered risk of interference and 
conflict.</p><p>By contrast, traditional applications, which we term 
<em>monolithic</em> applications, are often very difficult to test, because 
there are fewer classes, and each class has multiple concerns. A lack of tests 
makes it more difficult to add new features without breaking existi
 ng features. Further, the monolithic approach more often leads to 
implementations being linked to other implementations, yet another hurdle 
standing in the way of testing.</p><p>Let's end with a metaphor.</p><p>Over a 
decade ago, when Java first came on the scene, it was the first mainstream 
language to support garbage collection. This was very controversial: the 
garbage collector was seen as unnecessary, and a waste of resources. Among C 
and C++ developers, the attitude was "Why do I need a garbage collector? If I 
call malloc() I can call free()."</p><p>But now, most developers would never 
want to go back to a non-garbage collected environment. Having the GC around 
makes it much easier to code in a way we find natural: many small related 
objects working together. It turns out that knowing when to call free() is more 
difficult than it sounds. The Objective-C language tried to solve this with 
retain counts on objects and that still lead to memory leaks when it was 
applied to object <
 em>graphs</em> rather than object <em>trees</em>.</p><p>Roll the clock forward 
a decade and the common consensus has shifted considerably. Objective-C 2.0 
features true garbage collection and GC libraries are available for C and C++. 
All scripting languages, including Ruby and Python, feature garbage collection 
as well. A new language <em>without</em> garbage collection is now considered 
an anomaly.</p><p>The point is, the life cycle of objects turns out to be far 
more complicated than it looks at first glance. We've come to accept that our 
own applications lack the ability to police their objects as they are no longer 
needed (they literally lack the ability to determine <em>when</em> an object is 
no longer needed) and the garbage collector, a kind of higher authority, takes 
over that job very effectively. The end result? Less code and fewer bugs. And a 
careful study shows that the Java memory allocator and garbage collector (the 
two are quite intimately tied together) is actually <
 strong>more</strong> efficient than malloc() and free().</p><p>So we've come 
to accept that the <em>death concern</em> is better handled outside of our own 
code. The use of Inversion of Control is simply the flip side of that: the 
<em>life cycle and construction concerns</em> are also better handled by an 
outside authority as well: the IoC container. These concerns govern when a 
service is <em>realized</em> and how its dependencies and configuration are 
injected. As with the garbage collector, ceding these chores to the container 
results in less code and fewer bugs, and lets you concentrate on the things 
that should matter to you: your business logic, your application &#8211; and 
not a whole bunch of boilerplate plumbing!</p><p>&#160;</p><p></p></div>
+</div></div><p>Again, we've omitted a few details related to the database the 
TableMetricProducer will point at (in fact, Tapestry IoC provides a lot of 
support for configuration of this type as well, which is yet another 
concern).</p><p>The MonitorModule class is a Tapestry IoC module: a class that 
defines and configures services.</p><p>The bind() method is the principle way 
that services are made known to the Registry: here we're binding a service 
interface to a service implementation. QueueWriter we've discussed already, and 
MetricScheduler is a service that is responsible for determining when 
MetricProducer instances run.</p><p>The contributeMetricScheduler() method 
allows the module to <em>contribute</em> into the MetricProducer service's 
<em>configuration</em>. More testability: the MetricProducer isn't tied to a 
pre-set list of producers, instead it will have a 
Collection&lt;MetricProducer&gt; injected into its constructor. Thus, when 
we're coding the MetricProducerImpl class
 , we can test it against mock implementations of MetricProducer.</p><p>The 
QueueWriter service is injected into the contributeMetricScheduler() method. 
Since there's only one QueueWriter service, Tapestry IoC is able to "find" the 
correct service based entirely on type. If, eventually, there's more than one 
QueueWriter service (perhaps pointing at different JMS queues), you would use 
an annotation on the parameter to help Tapestry connect the parameter to the 
appropriate service.</p><p>Presumably, there would be a couple of other 
parameters to the contributeMetricScheduler() method, to inject in a database 
URL or connection pool (that would, in turn, be passed to 
TableMetricProducer).</p><p>A new TableMetricProducer instance is created and 
contributed in. We could contribute as many producers as we like here. Other 
modules could also define a contributeMetricScheduler() method and contribute 
their own MetricProducer instances.</p><p>Meanwhile, the QueueWriterImpl class 
no longer nee
 ds the <code>instance</code> variable or getInstance() method, and the 
TableMetricProducer only needs a single constructor.</p><h2 
id="TapestryIoCOverview-AdvantagesofIoC:Summary">Advantages of IoC: 
Summary</h2><p>It would be ludicrous for us to claim that applications built 
without an IoC container are doomed to failure. There is overwhelming evidence 
that applications have been built without containers and have been perfectly 
successful.</p><p>What we are saying is that IoC techniques and discipline will 
lead to applications that are:</p><ul><li><strong>More testable</strong> 
&#8211; smaller, simpler classes; coding to interfaces allows use of mock 
implementations</li><li><strong>More robust</strong> &#8211; smaller, simpler 
classes; use of final variables; thread safety baked in</li><li><strong>More 
scalable</strong> &#8211; thread safety baked in</li><li><strong>Easier to 
maintain</strong> &#8211; less code, simpler classes</li><li><strong>Easier to 
extend</strong> &#8211; new f
 eatures are often additions (new services, new contributions) rather than 
changes to existing classes</li></ul><p>What we're saying is that an IoC 
container allows you to work faster and smarter.</p><p>Many of these traits 
work together; for example, a more testable application is inherently more 
robust. Having a test suite makes it easier to maintain and extend your code, 
because its much easier to see if new features break existing ones. Simpler 
code plus tests also lowers the cost of entry for new developers coming on 
board, which allows for more developers to work efficiently on the same code 
base. The clean separation between interface and implementation also allows 
multiple developers to work on different aspects of the same code base with a 
lowered risk of interference and conflict.</p><p>By contrast, traditional 
applications, which we term <em>monolithic</em> applications, are often very 
difficult to test, because there are fewer classes, and each class has multiple 
concerns
 . A lack of tests makes it more difficult to add new features without breaking 
existing features. Further, the monolithic approach more often leads to 
implementations being linked to other implementations, yet another hurdle 
standing in the way of testing.</p><p>Let's end with a metaphor.</p><p>Over a 
decade ago, when Java first came on the scene, it was the first mainstream 
language to support garbage collection. This was very controversial: the 
garbage collector was seen as unnecessary, and a waste of resources. Among C 
and C++ developers, the attitude was "Why do I need a garbage collector? If I 
call malloc() I can call free()."</p><p>But now, most developers would never 
want to go back to a non-garbage collected environment. Having the GC around 
makes it much easier to code in a way we find natural: many small related 
objects working together. It turns out that knowing when to call free() is more 
difficult than it sounds. The Objective-C language tried to solve this with 
retain 
 counts on objects and that still lead to memory leaks when it was applied to 
object <em>graphs</em> rather than object <em>trees</em>.</p><p>Roll the clock 
forward a decade and the common consensus has shifted considerably. Objective-C 
2.0 features true garbage collection and GC libraries are available for C and 
C++. All scripting languages, including Ruby and Python, feature garbage 
collection as well. A new language <em>without</em> garbage collection is now 
considered an anomaly.</p><p>The point is, the life cycle of objects turns out 
to be far more complicated than it looks at first glance. We've come to accept 
that our own applications lack the ability to police their objects as they are 
no longer needed (they literally lack the ability to determine <em>when</em> an 
object is no longer needed) and the garbage collector, a kind of higher 
authority, takes over that job very effectively. The end result? Less code and 
fewer bugs. And a careful study shows that the Java memory alloc
 ator and garbage collector (the two are quite intimately tied together) is 
actually <strong>more</strong> efficient than malloc() and free().</p><p>So 
we've come to accept that the <em>death concern</em> is better handled outside 
of our own code. The use of Inversion of Control is simply the flip side of 
that: the <em>life cycle and construction concerns</em> are also better handled 
by an outside authority as well: the IoC container. These concerns govern when 
a service is <em>realized</em> and how its dependencies and configuration are 
injected. As with the garbage collector, ceding these chores to the container 
results in less code and fewer bugs, and lets you concentrate on the things 
that should matter to you: your business logic, your application &#8211; and 
not a whole bunch of boilerplate plumbing!</p><p>&#160;</p><p></p></div>
       </div>
 
       <div class="clearer"></div>

Modified: 
websites/production/tapestry/content/unit-testing-pages-or-components.html
==============================================================================
--- websites/production/tapestry/content/unit-testing-pages-or-components.html 
(original)
+++ websites/production/tapestry/content/unit-testing-pages-or-components.html 
Sun Feb 18 19:21:00 2018
@@ -108,7 +108,7 @@
 </div>
 
 
-<h2 id="Unittestingpagesorcomponents-Settingupadrivingenvironment">Setting up 
a driving environment</h2><p>In order to unit test a page, you'll need to 
create an instance of <a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/test/PageTester.html";>PageTester</a>.
 It acts as both the browser and the servlet container so that you can use it 
to drive your page.</p><p>The PageTester falls into a middle ground between 
pure unit testing and <a  
href="unit-testing-pages-or-components.html">full-scale integration 
testing</a>.</p><p>As the PageTester is not a real servlet container, you need 
to tell it the same information as you would in web.xml:</p><ol><li>Your 
application package.</li><li>Your filter name. This is used to load your 
Tapestry IoC module only. If you have none, you can pass an empty string or 
anything to it.</li><li>The folder acting as your context root. This is used to 
locate your templates (if they're put there).Here is an examp
 le (using TestNG, but you're free to use JUnit or anything 
else):</li></ol><div class="code panel pdl" style="border-width: 1px;"><div 
class="codeContent panelContent pdl">
+<h2 id="Unittestingpagesorcomponents-Settingupadrivingenvironment">Setting up 
a driving environment</h2><p>In order to unit test a page, you'll need to 
create an instance of <a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/test/PageTester.html";>PageTester</a>.
 It acts as both the browser and the servlet container so that you can use it 
to drive your page.</p><p>The PageTester falls into a middle ground between 
pure unit testing and <a  href="integration-testing.html">full-scale 
integration testing</a>.</p><p>As the PageTester is not a real servlet 
container, you need to tell it the same information as you would in 
web.xml:</p><ol><li>Your application package.</li><li>Your filter name. This is 
used to load your Tapestry IoC module only. If you have none, you can pass an 
empty string or anything to it.</li><li>The folder acting as your context root. 
This is used to locate your templates (if they're put there).Here is an example 
(using Tes
 tNG, but you're free to use JUnit or anything else):</li></ol><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 MyTest extends Assert
 {
     @Test
@@ -184,7 +184,7 @@
     }
 }
 </pre>
-</div></div><p>To submit a form by clicking a submit button, call the <a  
class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/test/PageTester.html#clickSubmit(org.apache.tapestry5.dom.Element,%20java.util.Map)">clickSubmit()</a>
 method instead.</p><h2 
id="Unittestingpagesorcomponents-Unittestingacomponent">Unit testing a 
component</h2><p>To unit test a component, just create a test page containing 
that component. Then unit test that page.</p><h2 
id="Unittestingpagesorcomponents-Third-partyTestingModules">Third-party Testing 
Modules</h2><ul><li><a  class="external-link" 
href="http://tapestrytestify.sourceforge.net/"; 
rel="nofollow">Tapestry-Testify</a> makes it easier to write page and component 
tests and run them efficiently.</li><li><a  class="external-link" 
href="http://tapestryxpath.sourceforge.net/"; rel="nofollow">Tapestry-XPath</a> 
allows you to use XPath expressions to query the Tapestry DOM (useful for 
simplifying page and component test
 s).</li></ul></div>
+</div></div><p>To submit a form by clicking a submit button, call the <a  
class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/test/PageTester.html#clickSubmit-org.apache.tapestry5.dom.Element-java.util.Map-";>clickSubmit()</a>
 method instead.</p><h2 
id="Unittestingpagesorcomponents-Unittestingacomponent">Unit testing a 
component</h2><p>To unit test a component, just create a test page containing 
that component. Then unit test that page.</p><h2 
id="Unittestingpagesorcomponents-Third-partyTestingModules">Third-party Testing 
Modules</h2><ul><li><a  class="external-link" 
href="http://tapestrytestify.sourceforge.net/"; 
rel="nofollow">Tapestry-Testify</a> makes it easier to write page and component 
tests and run them efficiently.</li><li><a  class="external-link" 
href="http://tapestryxpath.sourceforge.net/"; rel="nofollow">Tapestry-XPath</a> 
allows you to use XPath expressions to query the Tapestry DOM (useful for 
simplifying page and component tests).
 </li></ul></div>
       </div>
 
       <div class="clearer"></div>


Reply via email to