---- | |
Building Pipelines | |
---- | |
Building Pipelines | |
A common pattern within Tapestry is the use of filtering pipelines. Another name | |
for a pipeline is a <filter chain>; an example of this is the Filter and FilterChain | |
interfaces inside the Servlet API. | |
In this pattern, an existing service is decorated with a filter. | |
The filter will delegate to the service, but has the chance to | |
alter or replace parameters before invoking the method, and | |
can perform operations before returning. This is | |
similar to {{{command.html}chain of command}}, but differs in that | |
there are two interfaces (the service interface and the filter interface) | |
and that each filter invokes the next filter via the service interface. | |
In chain of command, the chain invokes each method, which must return | |
before the next command in the chain is invoked. | |
The service interface and the filter interface are closely related: | |
the filter interface must match the service interface method for method, | |
but each method of the filter interface must have an additional parameter | |
whose type is the service interface. For example, a pipeline | |
that performed string transformations might use the following interfaces: | |
+------+ | |
public interface StringTransformService | |
{ | |
String transform(String input); | |
} | |
public interface StringTransformFilter | |
{ | |
String transform(String input, StringTransformService delegate); | |
} | |
+-----+ | |
An implementation of the filter might look like: | |
+-----+ | |
public class UpcasePreFilter implements StringTransformFilter | |
{ | |
public String transform(String input, StringTransformService delegate) | |
{ | |
return delegate.transform(input.toUpperCase()); | |
} | |
} | |
+-----+ | |
Alternately, the filter could pass input to delegate unchanged, but invoke | |
toUpperCase() on the result: | |
+-----+ | |
public class UpcasePostFilter implements StringTransformFilter | |
{ | |
public String transform(String input, StringTransformService delegate) | |
{ | |
return delegate.transform(input).toUpperCase(); | |
} | |
} | |
+-----+ | |
The | |
{{{../apidocs/org/apache/tapestry5/ioc/services/PipelineBuilder.html}PipelineBuilder}} | |
service is useful for constructing pipelines. The service is often injected | |
into a service builder method, along with an ordered configuration of services. | |
What the builder accomplishes is to represent each <filter> in the pipeline as | |
an instance of the <service> interface. | |
[images/PipelineCallingSequence.png] Pipeline Calling Sequence | |
The bridges are created by the PipelineBuilder service. The terminator | |
must be provided. The bridges and the terminator implement the service interface. | |
+-----+ | |
public static StringTransformService build( | |
@InjectService("PipelineBuilder") | |
PipelineBuilder builder, | |
List<StringTransformFilter> configuration, | |
Log serviceLog) | |
{ | |
StringTransformService terminator = new StringTransformService() | |
{ | |
public String transform(String input) | |
{ | |
return input; | |
} | |
}; | |
return builder.build(log, | |
StringTransformService.class, StringTransformFilter.class, | |
configuration, | |
terminator); | |
} | |
+-----+ | |
Here, we create the terminator for the pipeline as an inner class instance, | |
and feed that into the builder. The result is a new service that encapsulates | |
the entire pipeline. When there are no filters, this is just the terminator. |