blob: 9c30645535c9c19e7e0db25ca51329fc92c8e1ab [file] [log] [blame]
----
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.