<chapter id="Interceptors">
    <title>Interceptors</title>
    <para>Resteasy has the capability to intercept JAX-RS invocations and route them through listener-like objects
    called interceptors.  There are 4 different interception points on the serverside: wrapping around
    MessageBodyWriter invocations, wrapping around MessageBodyReader invocations, pre-processors the intercept
    the incoming request before anything is unmarshalled, and post processors which are invoked right
    after the JAX-RS method is finished.  On the client side you can also intercept MessageBodyReader and Writer
    as well as the remote invocation to the server.</para>
    <sect1 id="MessageBodyInterceptors">
       <title>MessageBodyReader/Writer Interceptors</title>
        <para>MessageBodyReader and Writer interceptors work off of the same principles.  They wrap around the
        invocation of MessageBodyReader.readFrom() or MessageBodyWriter.writeTo().  You can use them to
        wrap the Output or InputStream.  For example, the Resteasy GZIP support has interceptors that create
        and override the default Output and InputStream with a GzipOutpuStream or GzipInputStream so that
        gzip encoding can work.  You could use them to append headers to the response (or on the client side,
            the outgoing request).</para>
        <para>To implement one you implement the org.jbos.resteasy.spi.interception.MessageBodyReaderInterceptor or
        MessageBodyWriterInterceptor</para>
<programlisting>
<![CDATA[
public interface MessageBodyReaderInterceptor
{
   Object read(MessageBodyReaderContext context) throws IOException, WebApplicationException;

}

public interface MessageBodyWriterInterceptor
{
   void write(MessageBodyWriterContext context) throws IOException, WebApplicationException;

}

        ]]>    
</programlisting>
        <para>
            Interceptors are driven by the MessageBodyWriterContext or MessageBodyReaderContext.  The interceptors
            and the MessageBodyReader or Writer is invoked in one big Java call stack.  You must call
            MessageBodyReaderContext.proceed() or MessageBodyWriterContext.proceed() to go to the next interceptor
            or, if there are no more interceptors to invoke, the readFrom() or writeTo() method of the MessageBodyReader
            or MessageBodyWriter.  This wrapping allows you to modify things before they get to the Reader or Writer
            then clean up after proceed() returns.  The Context objects also have methods to modify the parameters
            going to the Reader or Writer.
        </para>
<programlisting>
<![CDATA[
public interface MessageBodyReaderContext
{
   Class getType();

   void setType(Class type);

   Type getGenericType();

   void setGenericType(Type genericType);

   Annotation[] getAnnotations();

   void setAnnotations(Annotation[] annotations);

   MediaType getMediaType();

   void setMediaType(MediaType mediaType);

   MultivaluedMap<String, String> getHeaders();

   InputStream getInputStream();

   void setInputStream(InputStream is);

   Object proceed() throws IOException, WebApplicationException;
}

public interface MessageBodyWriterContext
{
   Object getEntity();

   void setEntity(Object entity);

   Class getType();

   void setType(Class type);

   Type getGenericType();

   void setGenericType(Type genericType);

   Annotation[] getAnnotations();

   void setAnnotations(Annotation[] annotations);

   MediaType getMediaType();

   void setMediaType(MediaType mediaType);

   MultivaluedMap<String, Object> getHeaders();

   OutputStream getOutputStream();

   public void setOutputStream(OutputStream os);

   void proceed() throws IOException, WebApplicationException;
}
]]>
</programlisting>
        <para>
            MessageBodyReaderInterceptors and MessageBodyWriterInterceptors can be used on the serverside or client side.
            They must be annotated with @org.jboss.resteasy.annotations.interception.ServerInterceptor or
            @org.jboss.resteasy.annotations.interception.ClientInterceptor so that resteasy knows whether or not
            to add them to the interceptor list.  If you do not annotate your interceptor classes with one or both
            of these annotations, you will receive a deployment error.  They also
            should be annotated with @Provider.  Lets look at an example:
        </para>
<programlisting>
@Provider
@ServerInterceptor
public class MyHeaderDecorator implements MessageBodyWriterInterceptor {

    public void write(MessageBodyWriterContext context) throws IOException, WebApplicationException
    {
       context.getHeaders().add("My-Header", "custom");
       context.proceed();
    }
}
</programlisting>
        <para>Here we have a server side interceptor that adds a header value to the
            response.  You see that it is annotated with @Provider and @ServerInterceptor.
        It must modify the header before calling context.proceed() as the response may
        be committed after the MessageBodyReader runs.  Remember, you MUST call context.proceed().  If
        you don't, your invocation will not happen.</para>
    </sect1>
    <sect1 id="PreProcessInterceptors">
        <title>PreProcessInterceptor</title>
        <para>The org.jboss.resteasy.spi.interception.PreProcessInterceptor runs after a JAX-RS resource
        method is found to invoke on, but before the actual invocation happens.  They are only usable on the
            server, but still must be annotated with @ServerInterceptor.  They can be used to implement security features or
        can preempt the Java request.  The Resteasy security implementation uses this type of interceptor to abort
        requests before the actually happen if the user does not pass authorization.  The Resteasy caching
        framework also uses this to return cached responses to avoid invoking methods again.   Here's what
        the interceptor interface looks like:</para>
<programlisting>
    public interface PreProcessInterceptor
    {
       ServerResponse preProcess(HttpRequest request, ResourceMethod method) throws Failure, WebApplicationException;
    }

</programlisting>
        <para>PreProcessInterceptors run in sequence and
        do not wrap the actual JAX-RS invocation.  Here's some pseudo code that illustrates how they work:</para>
<programlisting>
    for (PreProcessInterceptor interceptor : preProcessInterceptors) {
       ServerResponse response = interceptor.preProcess(request, method);
       if (response != null) return response;
    }
    executeJaxrsMethod(...);
</programlisting>
        <para>If the preProcess() method returns a ServerResponse then the underlying JAX-RS method will not get
        invoked and the runtime will process the response and return to the client.</para>
    </sect1>
    <sect1 id="PostProcessInterceptors">
        <title>PostProcessInterceptors</title>
        <para>
          The org.jboss.resteasy.spi.interception.PostProcessInterceptor runs after the JAX-RS method was invoked
            but before MessageBodyWriters are invoked.  They can only be used on the server side.  Use them
            if you need to set a response header when there might not
            be any MessageBodyWriter invoked.  They are there for symmetry with PreProcessInterceptor.  They do not wrap anything and
            are invoked in order like PreProcessInterceptors are.
        </para>
<programlisting>
    public interface PostProcessInterceptor
    {
       void postProcess(ServerResponse response);
    }
    
</programlisting>

    </sect1>
    <sect1 id="ClientExecutionInterceptors">
        <title>ClientExecutionInterceptors</title>
        <para>org.jboss.resteasy.spi.interception.ClientExecutionInterceptor classes only are usable on the client
        side.  They run after the MessageBodyWriter and after the ClientRequest has been totally built on the client side.
        They wrap around the actually HTTP invocation that goes to the server.  Resteasy GZIP support uses them
        to set the Accept header to contain "gzip, deflate" before the request goes out.  The Resteasy client cache
        uses it to check to see if its cache contains the resource before going over the wire.  These interceptors
        must be annotated with @ClientInterceptor and @Provider.</para>
<programlisting>
    public interface ClientExecutionInterceptor
    {
       ClientResponse execute(ClientExecutionContext ctx) throws Exception;
    }

    public interface ClientExecutionContext
    {
       ClientRequest getRequest();

       ClientResponse proceed() throws Exception;
    }
    
</programlisting>
        <para>The work work in the same pattern as MessageBodyReader/WriterInterceptors in that you must call
        proceed() unless you want to abort the invocation.</para>
    </sect1>
    <sect1 id="BindingInterceptors">
        <title>Binding Interceptors</title>
        <para>By default, any registered interceptor will be invoked for any request you do.  By default, every
        request will use your interceptors.  You can fine tune this by having your interceptors implement the
        org.jboss.resteasy.spi.AcceptedByMethod interface:</para>
<programlisting>
    public interface AcceptedByMethod
    {
       public boolean accept(Class declaring, Method method);
    }

</programlisting>
        <para>If your interceptor implements this interface, Resteasy will invoke the accept() method.  If this
        method returns true, Resteasy will add that interceptor to the JAX-RS method's call chain.  If it returns
        false then it won't be added to the call chain.  For example:</para>
<programlisting>
@Provider
@ServerInterceptor
public class MyHeaderDecorator implements MessageBodyWriterInterceptor, AcceptedByMethod {

    public boolean accept(Class declaring, Method method) {
       return method.isAnnotationPresent(GET.class);
    }

   public void write(MessageBodyWriterContext context) throws IOException, WebApplicationException
   {
      context.getHeaders().add("My-Header", "custom");
      context.proceed();
   }
}
        </programlisting>
        <para>In this example, our accept() method checks to see if the @GET annotation is present on our
        JAX-RS method.  If it is, then this interceptor will be applied to that method's call chain.</para>

    </sect1>
    <sect1 id="registering">
         <title>Registering Interceptors</title>
        <para>Registering interceptors is easy.  Since they are a @Provider, (you remembered to annotate it right?)
        they can be listed in the resteasy.providers context-param in web.xml or returned as a class or object in the
        Application.getClasses() or Application.getSingletons() method.</para>
    </sect1>
    <sect1 id="interceptorPrecedence">
        <title>Interceptor Ordering and Precedence</title>
        <para>Some interceptors are very sensitive in which order they are invoked.  For example, you always want your
        security interceptor invoked first.  Other interceptor's behavior might be triggered by a different interceptor
        that adds a header.  By default, you have no control over the order in which registered interceptors are invoked.
        There is a way to specify interceptor precedence though.</para>
        <para>You do not specify interceptor precedence by listing interceptor classes.  Instead, there are precedence
        families and a particular interceptor class is associated with a family via the @org.jboss.resteasy.annotations.interception.Precedence annotation.
        We did this because some of the built in interceptors included with Resteasy are very sensitive to ordering.  By specifying
        precedence through a family structure, we can protect these built in interceptors.  An advantage to this approach
        is that configuration is also a lot easier too for you.</para>
        <para>These are the families and the order in which they are executed:</para>
<programlisting>
    SECURITY
    HEADER_DECORATOR
    ENCODER
    REDIRECT
    DECODER
</programlisting>
        <para>Any interceptor not associated with a precedence family will be invoked last.  SECURITY usually involves
        PreProcessInterceptors.  They should be invoked first because you want to do as little as possible before
        your invocation is authorized.  HEADER_DECORATORs are interceptors that add headers to a response or
        an outgoing request.  They need to come next because these added headers may effect the behavior of other
        interceptors.  ENCODER interceptors change the OutputStream.  For example, the GZIP interceptor
            creates a GZIPOutputStream to wrap the real OutputStream for compression.
            REDIRECT interceptors usually are used in PreProcessInterceptors as they may reroute the request
        and totally bypas the JAX-RS method.  DECODER interceptors wrap the InputStream.  For example, the
        GZIP interceptor decoder wraps the InputStream in a GzipInputStream instance.</para>
        <para>To marry your custom interceptors to a particular family you annotate it with the
            @org.jboss.resteasy.annotations.interception.Precendence annotation.</para>
<programlisting>
@Provider
@ServerInterceptor
@ClientInterceptor
@Precedence("ENCODER")
public class MyCompressionInterceptor implements MessageBodyWriterInterceptor {...}
</programlisting>
        <para>For complete type safety, there are convenience annotations in the org.jbos.resteasy.annotations.interception
        package:  @DecoredPrecedence, @EncoderPrecedence, @HeaderDecoratorPrecedence, @RedirectPrecedence,
        @SecurityPrecedence.  Use these instead of the @Precedence annotation</para>
        <sect2 id="customprecedence">
            <title>Custom Precedence</title>
            <para>You can define your own precedence families.  Apply them using the @Precedence annotation.</para>
 <programlisting>
 @Provider
 @ServerInterceptor
 @Precedence("MY_CUSTOM_PRECEDENCE")
 public class MyCustomInterceptor implements MessageBodyWriterInterceptor {...}
            </programlisting>
            <para>You can create your own convenience annotation by using @Precedence as a meta-annotation</para>
<programlisting>
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Precedence("MY_CUSTOM_PRECEDENCE")
public @interface MyCustomPrecedence {}
</programlisting>
            <para>You must register your custom precedence.  Otherwise, Resteasy will give you an error at deployment
            time.  You do this with the context params:</para>
<programlisting>
resteasy.append.interceptor.precedence
resteasy.interceptor.before.precedence
resteasy.interceptor.after.precedence</programlisting>
            <para>resteasy.append.interceptor.precedence simply appends the precedence family to the list.
            resteasy.interceptor.before.precedence allows you to specify a family your new precedence comes before.
            resteasy.interceptor.after.precedence allows you to specify a family your new precedence comes after.
            For example:</para>
<programlisting>
<![CDATA[
web-app>
    <display-name>Archetype RestEasy Web Application</display-name>

    <!-- testing configuration -->
    <context-param>
        <param-name>resteasy.append.interceptor.precedence</param-name>
        <param-value>END</param-value>
    </context-param>
    <context-param>
        <param-name>resteasy.interceptor.before.precedence</param-name>
        <param-value>ENCODER : BEFORE_ENCODER</param-value>
    </context-param>

    <context-param>
        <param-name>resteasy.interceptor.after.precedence</param-name>
        <param-value>ENCODER : AFTER_ENCODER</param-value>
    </context-param>

    <context-param>
        <param-name>resteasy.servlet.mapping.prefix</param-name>
        <param-value>/test</param-value>
    </context-param>

    <listener>
        <listener-class>org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap</listener-class>
    </listener>

    <servlet>
        <servlet-name>Resteasy</servlet-name>
        <servlet-class>org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>Resteasy</servlet-name>
        <url-pattern>/test/*</url-pattern>
    </servlet-mapping>

</web-app>
        
]]>
</programlisting>
            <para>In this web.xml file, we've define 3 new precedence families: END, BEFORE_ENCODER, and AFTER_ENCODER.  Here's
            what the family order would look like with this configuration:</para>
<programlisting>
SECURITY
HEADER_DECORATOR
BEFORE_ENCODER
ENCODER
AFTER_ENCODER
REDIRECT
DECODER
END
            </programlisting>
        </sect2>
    </sect1>
</chapter>