Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.


{span:style=
Span
Wiki Markup
style
font-size:2em;font-weight:bold
} JAX-RS Filters {span} {toc} h1. Filters Often Filters

 

 

Table of Contents

Filters

Often it's

...

necessary

...

to

...

pre-

...

or

...

post-process

...

some

...

requests

...

according

...

to

...

a

...

number

...

of

...

requirements.

...


For

...

example,

...

a

...

request

...

like

...

GET

...

/resource?_type=xml

...

is

...

supported

...

by

...

a

...

CXF specific RequestPreprocessor code which modifies an input message
by updating one of its headers.

A standard mechanism for updating the request or response properties is to use JAX-RS 2.0 ContainerRequestFilter or ContainerResponseFilter.

ContainerRequestFilters with a @PreMatching annotation are run before the JAX-RS resource selection process starts. PreMatching filters should be used to modify request URI or headers or input stream. Post-matching filters are run just before a selected resource method is executed.

Multiple ContainerRequestFilter and ContainerResponseFilter filters can be ordered using a @Priority annotation.

 

The implementations can be registered like any other type of providers :

Code Block
xml
xml
<beans>
     specific RequestHandler filter which modifies the CXF input Message 
by updating one of its headers.

In some cases users can use the existing filter technologies such as Servler filters or Spring AOP proxies. In other cases, it can be handy
to write a CXF filter which will introspect the resource class, input or output message, the operation which was invoked and modify the request or response accordingly. 

Here are the interface definitions : 

{code:java}
public interface RequestHandler {
    
    Response handleRequest(Message inputMessage, 
                           ClassResourceInfo resourceClass);

}
{code}

The request handler implementation can either modify the input Message and let the request to proceed or block the request by returning a non-null Response. 

A response filter implementation can get an access to OperationResourceInfo object representing a method to be invoked on a resource class :

{code:java}
OperationResourceInfo ori = exchange.get(OperationResourceInfo.class);
{code}  

Use OperationResourceInfo in your filter with care. In principle a given request chain may have filters which may want to  overwrite Accept or ContentType message headers which might lead to another method be selected. However if you know no such filters (will) exist in your application then you might want to check an OperationResourceInfo instance as part of your filter logic. 

When modifying an input message, one would typically want to replace a message input stream or one of its headers, such as ContentType :
{code:java}
InputStream is = message.getContent(InputStream.class);
message.setContent(new MyFilterInputStream(is));
message.put(Message.ACCEPT_CONTENT_TYPE, "custom/media"); 
{code}

{code:java}
public interface ResponseHandler {
    
    Response handleResponse(Message outputMessage,
                           OperationResourceInfo invokedOperation, 
                           Response response);

}
{code}

The response handler implementation can optionally overwrite or modify the application Response or modify the output message. When modifying an output message, one may want to either replace an output stream before message body providers attempt to write to it or replace the actual response object :
{code:java}
// replace an output stream
OutputStream os = message.getContent(OutputStream.class);
message.setContent(new MyFilterOutputStream(os));

// replace an actual object
response.setEntity(new MyWrapper(response.getEntity()))
// or using a low-level Message api if needed
MessageContentsList objs = MessageContentsList.getContentsList(message);
if (objs !== null && objs.size() == 1) {
    Object responseObj = objs.remove(0);
    obj.add(new MyWrapper(responseObj));
}
{code}

Please see [this blog entry|http://sberyozkin.blogspot.com/2008/07/rest-and-soap-united-in-cxf.html] for another example of when response filters can be useful.

Multiple request and response handlers are supported.

The implementations can be registered like any other types of providers :

{code:xml}

<beans>
<jaxrs:server id="customerService" address="/">
        <jaxrs:serviceBeans>
            <bean class="org.CustomerService" />
        </jaxrs:serviceBeans>

        <jaxrs:providers>
            <ref bean="authorizationFilter" />
        </jaxrs:providers>
        <bean id="authorizationFilter" class="com.bar.providers.AuthorizationRequestHandlerAuthorizationContainerRequestFilter">
            <!-- authorization bean properties -->
        </bean>
    </jaxrs:server>
</beans>
{code}

h2. Difference between JAXRS filters and CXF interceptors

JAXRS runtime flow is mainly implemented by a pair of 'classical' CXF interceptors. JAXRSInInterceptor is currently at Phase.PRE_STREAM phase while JAXRSOutInterceptor is currently at Phase.MARSHAL phase.

JAXRS filters can be thought of as additional handlers. JAXRSInInterceptor deals with a chain of RequestHandlers, just before the invocation. JAXRSOutInterceptor deals with a chain of ResponseHandlers, just after the invocation but before message body writers get their chance.

Sometimes you may want to use CXF interceptors rather than writing JAXRS filters. For example, suppose you combine JAXWS and JAXRS and you need to log only inbound or outbound messages. You can reuse the existing CXF interceptors :

{code:xml}
<beans>

Difference between JAXRS filters and CXF interceptors

JAXRS runtime flow is mainly implemented by a pair of 'classical' CXF interceptors. JAXRSInInterceptor is currently at Phase.UNMARSHAL (was at Phase.PRE_STREAM before CXF 2.2.2) phase while JAXRSOutInterceptor is currently at Phase.MARSHAL phase.

JAXRS filters can be thought of as additional handlers. JAXRSInInterceptor deals with a chain of Pre and Post Match ContainerRequestFilters, just before the invocation. JAXRSOutInterceptor deals with a chain of ContainerResponseFilters, just after the invocation but before message body writers get their chance.

Sometimes you may want to use CXF interceptors rather than writing JAXRS filters. For example, suppose you combine JAXWS and JAXRS and you need to log only inbound or outbound messages. You can reuse the existing CXF interceptors :

Code Block
xml
xml
<beans>
    <bean id="logInbound" class="org.apache.cxf.interceptor.LoggingInInterceptor"/>
    <bean id="logOutbound" class="org.apache.cxf.interceptor.LoggingOutInterceptor"/>

    <jaxrs:server> 
        <jaxrs:inInterceptors>
            <ref bean="logInbound"/>
        </jaxrs:inInterceptors>
        <jaxrs:outInterceptors>
            <ref bean="logOutbound"/>
        </jaxrs:outInterceptors>
    </jaxrs:server>

    <jaxws:endpoint>
        <jaxws:inInterceptors>
            <ref bean="logInbound"/>
        </jaxws:inInterceptors>
        <jaxws:outInterceptors>
            <ref bean="logOutbound"/>
        </jaxws:outInterceptors>
    </jaxws:endpoint>

</beans>
{code} 

Reusing other CXF 

Reusing other CXF interceptors/features

...

such

...

as

...

GZIP

...

handlers

...

can

...

be

...

useful

...

too.

...

Overriding

...

request

...

and

...

response

...

properties

...

Now

...

and

...

then

...

one

...

needs

...

to

...

overwrite

...

various

...

request

...

and

...

response

...

properties

...

like

...

HTTP

...

method

...

or

...

request

...

URI,

...


response

...

headers

...

or

...

status

...

codes

...

and

...

even

...

the

...

request

...

or

...

response

...

body.

...

JAX-RS

...

Response

...

may

...

be

...

used

...

to

...

specify

...

custom

...

status

...

and

...

response

...

headers

...

but

...

it

...

might

...

be

...

intrusive

...

to

...

add

...

it

...

to

...

method

...

signatures.

...

Using

...

filters

...

and

...

interceptors

...

makes

...

it

...

possible

...

to

...

override

...

all

...

the

...

needed

...

request/response

...

properties.

...

Overriding HTTP method

Use @PreMatching ContainerRequestFilter or register a custom CXF in intrerceptor filter which will replace the current method value keyed by
Message.HTTP_REQUEST_METHOD

...

in

...

a

...

given

...

Message.

...

Overriding request URI,

...

query

...

and

...

headers

...

One

...

can

...

do

...

it

...

either

...

from @PreMatching ContainerRequestFilter or CXF input interceptor (registered at the early phase like USER_STREAM)

...

,

...

for

...

example

...

:

Code Block
java
java


{code:java}
String s = m.get(Message.REQUEST_URI);
s += "/data/";
m.put(Message.REQUEST_URI, s);
{code} 

If the updated Request URI has a new query string, then you also need to update a 

If the updated Request URI has a new query string, then you also need to update a Message.QUERY_STRING

...

property.

...

Similarly,

...

one

...

can

...

update

...

request

...

HTTP

...

headers,

...

by

...

modifying

...

a

...

Message.REQUEST_HEADERS

...

Message

...

object

...

which

...

is

...

a

...

Map

...

containing

...

String

...

and

...

List

...

of

...

Strings

...

entries.

...

Overriding

...

response

...

status

...

code

...

and

...

headers

...

It

...

is

...

assumed

...

here

...

a

...

user

...

prefers

...

not

...

to

...

use

...

explicit

...

Response

...

objects

...

in

...

the

...

application

...

code.

...


This

...

can

...

be

...

done

...

either

...

from

...

ContainerResponseFilter or CXF

...

output

...

interceptor

...

(phase

...

like

...

MARSHALL

...

will

...

do)

...

,

...

for

...

example

...

this

...

code

...

will

...

work for both JAXRS and JAXWS :

Code Block
java
java
import java.util.Map;
import java.util.TreeMap;

import org.apache.cxf.message.Message;
import org.apache.cxf.phase.AbstractPhaseInterceptor;
import org.apache.cxf.phase.Phase;

 for both JAXRS and JAXWS :

{code:java}
public class CustomOutInterceptor extends AbstractOutDatabindingInterceptor {
    
    public CustomOutInterceptor() {
        super(Phase.MARSHAL);
    }

    public void handleMessage(Message outMessage) {
        Map<String, List<String>> headers = (Map<String, List<String>>)outMessage.get(Message.PROTOCOL_HEADERS);
        if (headers == null) {
            headers = new HashMap<StringTreeMap<String, List<String>>(String.CASE_INSENSITIVE_ORDER);
            message.put(Message.PROTOCOL_HEADERS, headers);
        }
        // modify headers  
    }    
{code}  

At the moment it is not possible to override a response status code from a CXF interceptor running before JAXRSOutInterceptor, like CustomOutInterceptor above, which will be fixed.
The only option at the moment is to use a custom ResponseHandler which will replace the current Response object with another one containing the required status. 

h1. Ignoring JAXRS MessageBodyWriters

In some cases you may want to have a JAXRS Response entity which a given RequestHandler or ResponseHandler has produced to be directly written to the output stream. For example, a CXF JAXRS WADLGenerator RequestHandler produces an XML content which does not have to be serialized by JAXRS MessageBodyWriters. If you do need to have the writers ignored then set the following property on the current exchange in the custom handler :

{code:java}

At the moment it is not possible to override a response status code from a CXF interceptor running before JAXRSOutInterceptor, like CustomOutInterceptor above, which will be fixed.
The only option at the moment is to use a custom ResponseHandler which will replace the current Response object with another one containing the required status.

Ignoring JAXRS MessageBodyWriters

In some cases you may want to have a JAXRS Response entity which a given filter has produced to be directly written to the output stream. For example, a CXF JAXRS WADLGenerator filter produces an XML content which does not have to be serialized by JAXRS MessageBodyWriters. If you do need to have the writers ignored then set the following property on the current exchange in the custom handler :

Code Block
java
java
message.getExchange().put("ignore.responsemessage.writers", true);
{code}

h1. Custom invokers

*Note* This feature is available starting from CXF 

Custom invokers

Note This feature is available starting from CXF 2.2.2

...

Using

...

custom

...

JAXR-RS

...

invokers

...

is

...

yet

...

another

...

way

...

to

...

pre

...

or

...

post

...

process

...

a

...

given

...

invocation.

...

For

...

example,

...

this

...

invoker

...

does

...

a

...

security

...

check

...

before

...

delegating

...

to

...

the

...

default

...

JAXRS

...

invoker.

...

A

...

custom

...

invoker,

...

like

...

a

...

request

...

filter,

...

has

...

the

...

access

...

to

...

all

...

the

...

information

...

accumulated

...

during

...

the

...

processing

...

of

...

a

...

given

...

call,

...

but

...

additionally,

...

it

...

can

...

also

...

check

...

the

...

actual

...

method

...

parameter

...

values.

...

Custom

...

invokers

...

can

...

be

...

registered

...

like

...

this

...

:

Code Block
xml
xml


{code:xml}
<beans>

    <jaxrs:server address="/"> 
        <jaxrs:invoker>
            <bean class="org.apache.cxf.systest.jaxrs.CustomJAXRSInvoker"/>
        </jaxrs:invoker>
    </jaxrs:server>

</beans>
{code}