I have a situation where the application developers and the framework provider are not the people. As a framework provider, I would like to be able to hand the developers what looks like a single Filter, but is in fact a chain of standard Filters (such as authentication, setting up invocation context, metrics, ++).
I don't seem to find this functionality in the standard library, but maybe there is an extension with it.
Instead of waiting for an answer, I went ahead with my own implementation and sharing here if some needs this.
/**
* Composes an array of Restlet Filters into a single Filter.
*/
public class ComposingFilter extends Filter
{
private final Filter first;
private final Filter last;
public ComposingFilter( Filter... composedOf )
{
Objects.requireNonNull( composedOf );
if( composedOf.length == 0 )
{
throw new IllegalArgumentException( "Filter chain can't be empty." );
}
first = composedOf[ 0 ];
Filter prev = first;
for( int i = 1; i < composedOf.length; i++ )
{
Filter next = composedOf[ i ];
prev.setNext( next );
prev = next;
}
last = composedOf[ composedOf.length - 1 ];
}
@Override
protected int doHandle( Request request, Response response )
{
if( first != null )
{
first.handle( request, response );
Response.setCurrent( response );
if( getContext() != null )
{
Context.setCurrent( getContext() );
}
}
else
{
response.setStatus( Status.SERVER_ERROR_INTERNAL );
getLogger().warning( "The filter " + getName() + " was executed without a next Restlet attached to it." );
}
return CONTINUE;
}
@Override
public synchronized void start()
throws Exception
{
if( isStopped() )
{
first.start();
super.start();
}
}
@Override
public synchronized void stop()
throws Exception
{
if( isStarted() )
{
super.stop();
first.stop();
}
}
@Override
public Restlet getNext()
{
return last.getNext();
}
@Override
public void setNext( Class<? extends ServerResource> targetClass )
{
last.setNext( targetClass );
}
@Override
public void setNext( Restlet next )
{
last.setNext( next );
}
}
NOTE: Not tested yet.