Folks,

did I miss something or did we forget to link to the IoC cookbook? I couldn't find a starting point in any of the exported pages.

Uli

On 08.12.2010 02:39, [email protected] wrote:

    IoC cookbook - patterns
    
<https://cwiki.apache.org/confluence/display/TAPESTRY/IoC+cookbook+-+patterns>


        Page *edited* by Bob Harner 
<https://cwiki.apache.org/confluence/display/~bobharner>

*Comment:* Added scrollbar at top & bottom, fixed broken link


        Changes (3)

{scrollbar}
h1. Using Patterns

Tapestry IoC has support for implementing several of the [Gang Of Four Design
Patterns|http://en.wikipedia.org/wiki/Design_pattern_(computer_science)]. In 
fact, the IoC container
itself is a pumped up version of the Factory pattern.

The basis for these patterns is often the use of _service builder methods_, 
where a
[configuration|#servconf.html] [configuration|IoC cookbook - servconf] for the 
service is combined
with a factory to produce the service implementation on the fly.

{anchor:chainofcommand}
...

Reducing the chain to a single object vastly simplifies the code: we&apos;ve 
_factored out_ the loop
implicit in the chain of command. That eliminates a lot of code, and 
that&apos;s less code to test,
and fewer paths through InjectWorker, which lowers its complexity further. We 
don&apos;t have to
test the cases where the list of injection providers is empty, or consists of 
only a single object,
or where it&apos;s the third object in that returns true: it looks like a 
single object, it acts
like a single object ... but its implementation uses many objects.

{scrollbar}


        Full Content

</confluence/display/TAPESTRY/IoC+cookbook+-+override>    IoC cookbook - 
override
</confluence/display/TAPESTRY/IoC+cookbook+-+override>    
^</confluence/display/TAPESTRY/IoC+cookbook>
IoC cookbook </confluence/display/TAPESTRY/IoC+cookbook>  IoC cookbook - 
servconf
</confluence/display/TAPESTRY/IoC+cookbook+-+servconf>
</confluence/display/TAPESTRY/IoC+cookbook+-+servconf>


  Using Patterns

Tapestry IoC has support for implementing several of the Gang Of Four Design 
Patterns
<http://en.wikipedia.org/wiki/Design_pattern_(computer_science)>. In fact, the 
IoC container itself
is a pumped up version of the Factory pattern.

The basis for these patterns is often the use of /service builder methods/, 
where a configuration
</confluence/display/TAPESTRY/IoC+cookbook+-+servconf> for the service is 
combined with a factory to
produce the service implementation on the fly.


  Chain of Command Pattern

Main Article: Chain of Command </confluence/display/TAPESTRY/IoC+-+command>

Let's look at another example, again from the Tapestry code base. The 
InjectProvider
<http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/InjectionProvider.html>
interface is used to process the @Inject annotation on the fields of a Tapestry 
page or component.
Many different instances are combined together to form a /chain of command/.

The interface has only a single method (this is far from uncommon):

public  interface  InjectionProvider
{
   boolean  provideInjection(String  fieldName,Class  fieldType, ObjectLocator 
locator,
       ClassTransformation transformation, MutableComponentModel 
componentModel);
}

The return type indicates whether the provider was able to do something. For 
example, the
AssetInjectionProvider checks to see if there's an @Path annotation on the 
field, and if so,
converts the path to an asset, works with the ClassTransformation object to 
implement injection, and
returns true to indicate success. Returns true terminates the chain early, and 
that true value is
ultimately returned to the caller.

In other cases, it returns false and the chain of command continues down to the 
next provider. If no
provider is capable of handling the injection, then the value false is 
ultimately returned.

The InjectionProvider service is built up via contributions. These are the 
contributions from the
TapestryModule:

public  static  void contributeInjectionProvider(
     OrderedConfiguration&lt;InjectionProvider&gt; configuration,
     MasterObjectProvider masterObjectProvider,
     ObjectLocator locator,
     SymbolSource symbolSource,
     AssetSource assetSource)
{
   configuration.add(&quot;Default&quot;,new  
DefaultInjectionProvider(masterObjectProvider, locator));

   configuration.add(&quot;ComponentResources&quot;,new  
ComponentResourcesInjectionProvider());

   configuration.add(
       &quot;CommonResources&quot;,
       new  CommonResourcesInjectionProvider(),
       &quot;after:Default&quot;);

   configuration.add(
       &quot;Asset&quot;,
       new  AssetInjectionProvider(symbolSource, assetSource),
       &quot;before:Default&quot;);

   configuration.add(&quot;Block&quot;,new  
BlockInjectionProvider(),&quot;before:Default&quot;);
   configuration.add(&quot;Service&quot;,new  
ServiceInjectionProvider(locator),&quot;after:*&quot;);
}

And, of course, other contributions could be made in other modules ... if you 
wanted to add in your
own form of injection.

The configuration is converted into a service via a service builder method:

   public  InjectionProvider build(List&lt;InjectionProvider&gt; configuration, 
ChainBuilder chainBuilder)
   {
     return  chainBuilder.build(InjectionProvider.class, configuration);
   }

Now, let's see how this is used. The InjectWorker class looks for fields with 
the InjectAnnotation,
and uses the chain of command to inject the appropriate value. However, to 
InjectWorker, there is no
chain ... just a /single/ object that implements the InjectionProvider 
interface.

public  class InjectWorkerimplements  ComponentClassTransformWorker
{
   private  final  ObjectLocator locator;

   // Really, a chain of command

   private  final  InjectionProvider injectionProvider;

   public  InjectWorker(ObjectLocator locator, InjectionProvider 
injectionProvider)
   {
     this.locator = locator;
     this.injectionProvider = injectionProvider;
   }

   public  final  void transform(ClassTransformation transformation, 
MutableComponentModel model)
   {
     for  (String  fieldName : 
transformation.findFieldsWithAnnotation(Inject.class))
     {
       Inject annotation = transformation.getFieldAnnotation(fieldName, 
Inject.class);

       try
       {
         String  fieldType = transformation.getFieldType(fieldName);

         Class  type = transformation.toClass(fieldType);

         boolean  success = injectionProvider.provideInjection(
             fieldName,
             type,
             locator,
             transformation,
             model);

         if  (success) transformation.claimField(fieldName, annotation);
       }
       catch  (RuntimeException ex)
       {
         throw  new  
RuntimeException(ServicesMessages.fieldInjectionError(transformation
             .getClassName(), fieldName, ex), ex);
       }

     }
   }
}

Reducing the chain to a single object vastly simplifies the code: we've 
/factored out/ the loop
implicit in the chain of command. That eliminates a lot of code, and that's 
less code to test, and
fewer paths through InjectWorker, which lowers its complexity further. We don't 
have to test the
cases where the list of injection providers is empty, or consists of only a 
single object, or where
it's the third object in that returns true: it looks like a single object, it 
acts like a single
object ... but its implementation uses many objects.

</confluence/display/TAPESTRY/IoC+cookbook+-+override>    IoC cookbook - 
override
</confluence/display/TAPESTRY/IoC+cookbook+-+override>    
^</confluence/display/TAPESTRY/IoC+cookbook>
IoC cookbook </confluence/display/TAPESTRY/IoC+cookbook>  IoC cookbook - 
servconf
</confluence/display/TAPESTRY/IoC+cookbook+-+servconf>
</confluence/display/TAPESTRY/IoC+cookbook+-+servconf>

Change Notification Preferences 
<https://cwiki.apache.org/confluence/users/viewnotifications.action>
View Online 
<https://cwiki.apache.org/confluence/display/TAPESTRY/IoC+cookbook+-+patterns> 
| View
Changes
<https://cwiki.apache.org/confluence/pages/diffpagesbyversion.action?pageId=23338499&revisedVersion=7&originalVersion=6>


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to