cxf-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From conflue...@apache.org
Subject [CONF] Apache CXF Documentation > JAX-RS Filters
Date Mon, 21 Mar 2011 15:11:00 GMT
<html>
<head>
    <base href="https://cwiki.apache.org/confluence">
            <link rel="stylesheet" href="/confluence/s/2042/9/1/_/styles/combined.css?spaceKey=CXF20DOC&amp;forWysiwyg=true"
type="text/css">
    </head>
<body style="background: white;" bgcolor="white" class="email-body">
<div id="pageContent">
<div id="notificationFormat">
<div class="wiki-content">
<div class="email">
    <h2><a href="https://cwiki.apache.org/confluence/display/CXF20DOC/JAX-RS+Filters">JAX-RS
Filters</a></h2>
    <h4>Page <b>edited</b> by             <a href="https://cwiki.apache.org/confluence/display/~sergey_beryozkin">Sergey
Beryozkin</a>
    </h4>
        <br/>
                         <h4>Changes (1)</h4>
                                 
    
<div id="page-diffs">
                    <table class="diff" cellpadding="0" cellspacing="0">
    
            <tr><td class="diff-snipped" >...<br></td></tr>
            <tr><td class="diff-unchanged" >    public void handleMessage(Message
outMessage) { <br>        Map&lt;String, List&lt;String&gt;&gt; headers
= (Map&lt;String, List&lt;String&gt;&gt;)outMessage.get(Message.PROTOCOL_HEADERS);
<br></td></tr>
            <tr><td class="diff-added-lines" style="background-color: #dfd;">
       if (headers == null) { <br>            headers = new HashMap&lt;String, List&lt;String&gt;&gt;();
<br>            message.put(Message.PROTOCOL_HEADERS, headers); <br>        }
<br></td></tr>
            <tr><td class="diff-unchanged" >        // modify headers   <br>
   }     <br></td></tr>
            <tr><td class="diff-snipped" >...<br></td></tr>
    
            </table>
    </div>                            <h4>Full Content</h4>
                    <div class="notificationGreySide">
        <p><span style="font-size:2em;font-weight:bold"> JAX-RS Filters </span></p>

<div>
<ul>
    <li><a href='#JAX-RSFilters-Filters'>Filters</a></li>
<ul>
    <li><a href='#JAX-RSFilters-DifferencebetweenJAXRSfiltersandCXFinterceptors'>Difference
between JAXRS filters and CXF interceptors</a></li>
</ul>
    <li><a href='#JAX-RSFilters-Overridingrequestandresponseproperties'>Overriding
request and response properties</a></li>
<ul>
    <li><a href='#JAX-RSFilters-OverridingHTTPmethod'>Overriding HTTP method</a></li>
    <li><a href='#JAX-RSFilters-OverridingrequestURI%2Cqueryandheaders'>Overriding
request URI, query and headers</a></li>
    <li><a href='#JAX-RSFilters-Overridingresponsestatuscodeandheaders'>Overriding
response status code and headers</a></li>
</ul>
    <li><a href='#JAX-RSFilters-IgnoringJAXRSMessageBodyWriters'>Ignoring JAXRS
MessageBodyWriters</a></li>
    <li><a href='#JAX-RSFilters-Custominvokers'>Custom invokers</a></li>
</ul></div>

<h1><a name="JAX-RSFilters-Filters"></a>Filters</h1>

<p>Often it's necessary to pre- or post-process some requests according to a number
of requirements.<br/>
For example, a request like </p>

<p>GET /resource?_type=xml is supported by a CXF specific RequestHandler filter which
modifies the CXF input Message <br/>
by updating one of its headers.</p>

<p>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<br/>
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. </p>

<p>Here are the interface definitions : </p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
<span class="code-keyword">public</span> <span class="code-keyword">interface</span>
RequestHandler {
    
    Response handleRequest(Message inputMessage, 
                           ClassResourceInfo resourceClass);

}
</pre>
</div></div>

<p>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. </p>

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

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
OperationResourceInfo ori = exchange.get(OperationResourceInfo.class);
</pre>
</div></div>  

<p>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. </p>

<p>When modifying an input message, one would typically want to replace a message input
stream or one of its headers, such as ContentType :</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
InputStream is = message.getContent(InputStream.class);
message.setContent(<span class="code-keyword">new</span> MyFilterInputStream(is));
message.put(Message.ACCEPT_CONTENT_TYPE, <span class="code-quote">"custom/media"</span>);

</pre>
</div></div>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
<span class="code-keyword">public</span> <span class="code-keyword">interface</span>
ResponseHandler {
    
    Response handleResponse(Message outputMessage,
                           OperationResourceInfo invokedOperation, 
                           Response response);

}
</pre>
</div></div>

<p>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 :</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
<span class="code-comment">// replace an output stream
</span>OutputStream os = message.getContent(OutputStream.class);
message.setContent(<span class="code-keyword">new</span> MyFilterOutputStream(os));

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

<p>Please see <a href="http://sberyozkin.blogspot.com/2008/07/rest-and-soap-united-in-cxf.html"
class="external-link" rel="nofollow">this blog entry</a> for another example of when
response filters can be useful.</p>

<p>Multiple request and response handlers are supported.</p>

<p>The implementations can be registered like any other types of providers :</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-xml">

<span class="code-tag">&lt;beans&gt;</span>
<span class="code-tag">&lt;jaxrs:server id=<span class="code-quote">"customerService"</span>
address=<span class="code-quote">"/"</span>&gt;</span>
    <span class="code-tag">&lt;jaxrs:serviceBeans&gt;</span>
      <span class="code-tag">&lt;bean class=<span class="code-quote">"org.CustomerService"</span>
/&gt;</span>
    <span class="code-tag">&lt;/jaxrs:serviceBeans&gt;</span>

    <span class="code-tag">&lt;jaxrs:providers&gt;</span>
      <span class="code-tag">&lt;ref bean=<span class="code-quote">"authorizationFilter"</span>
/&gt;</span>
    <span class="code-tag">&lt;/jaxrs:providers&gt;</span>
    <span class="code-tag">&lt;bean id=<span class="code-quote">"authorizationFilter"</span>
class=<span class="code-quote">"com.bar.providers.AuthorizationRequestHandler"</span>&gt;</span>
        <span class="code-tag"><span class="code-comment">&lt;!-- authorization
bean properties --&gt;</span></span>
    <span class="code-tag">&lt;/bean&gt;</span>
<span class="code-tag">&lt;/jaxrs:server&gt;</span>
<span class="code-tag">&lt;/beans&gt;</span>
</pre>
</div></div>

<h2><a name="JAX-RSFilters-DifferencebetweenJAXRSfiltersandCXFinterceptors"></a>Difference
between JAXRS filters and CXF interceptors</h2>

<p>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.</p>

<p>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.</p>

<p>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 :</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-xml">
<span class="code-tag">&lt;beans&gt;</span>
<span class="code-tag">&lt;bean id=<span class="code-quote">"logInbound"</span>
class=<span class="code-quote">"org.apache.cxf.interceptor.LoggingInInterceptor"</span>/&gt;</span>
<span class="code-tag">&lt;bean id=<span class="code-quote">"logOutbound"</span>
class=<span class="code-quote">"org.apache.cxf.interceptor.LoggingOutInterceptor"</span>/&gt;</span>

<span class="code-tag">&lt;jaxrs:server&gt;</span> 
 <span class="code-tag">&lt;jaxrs:inInterceptors&gt;</span>
     <span class="code-tag">&lt;ref bean=<span class="code-quote">"logInbound"</span>/&gt;</span>
 <span class="code-tag">&lt;/jaxrs:inInterceptors&gt;</span>
 <span class="code-tag">&lt;jaxrs:outInterceptors&gt;</span>
    <span class="code-tag">&lt;ref bean=<span class="code-quote">"logOutbound"</span>/&gt;</span>
 <span class="code-tag">&lt;/jaxrs:outInterceptors&gt;</span>
<span class="code-tag">&lt;/jaxrs:server&gt;</span>

<span class="code-tag">&lt;jaxws:endpoint&gt;</span>
 <span class="code-tag">&lt;jaxws:inInterceptors&gt;</span>
     <span class="code-tag">&lt;ref bean=<span class="code-quote">"logInbound"</span>/&gt;</span>
 <span class="code-tag">&lt;/jaxws:inInterceptors&gt;</span>
 <span class="code-tag">&lt;jaxws:outInterceptors&gt;</span>
    <span class="code-tag">&lt;ref bean=<span class="code-quote">"logOutbound"</span>/&gt;</span>
 <span class="code-tag">&lt;/jaxws:outInterceptors&gt;</span>
<span class="code-tag">&lt;/jaxws:endpoint&gt;</span>

<span class="code-tag">&lt;/beans&gt;</span>
</pre>
</div></div> 

<p>Reusing other CXF interceptors/features such as GZIP handlers can be useful too.</p>

<h1><a name="JAX-RSFilters-Overridingrequestandresponseproperties"></a>Overriding
request and response properties</h1>

<p>Now and then one needs to overwrite various request and response properties like
HTTP method or request URI, <br/>
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.</p>

<p>Using filters and interceptors makes it possible to override all the needed request/response
properties. </p>

<h2><a name="JAX-RSFilters-OverridingHTTPmethod"></a>Overriding HTTP method</h2>

<p>Register a custom RequestHandler filter which will replace the current method value
keyed by <br/>
Message.HTTP_REQUEST_METHOD in a given Message.   </p>

<h2><a name="JAX-RSFilters-OverridingrequestURI%2Cqueryandheaders"></a>Overriding
request URI, query and headers</h2>

<p>One can do it either from a CXF input interceptor (registered at the early phase
like USER_STREAM) or from a RequestHandler filter, for example :</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
<span class="code-object">String</span> s = m.get(Message.REQUEST_URI);
s += <span class="code-quote">"/data/"</span>;
m.put(Message.REQUEST_URI, s);
</pre>
</div></div> 

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

<p>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.</p>

<h2><a name="JAX-RSFilters-Overridingresponsestatuscodeandheaders"></a>Overriding
response status code and headers</h2>

<p>It is assumed here a user prefers not to use explicit Response objects in the application
code.<br/>
This can be done either from a CXF output interceptor (phase like MARSHALL will do) or from
a ResponseHandler filter, for example this code will work for both JAXRS and JAXWS :</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
<span class="code-keyword">public</span> class CustomOutInterceptor <span class="code-keyword">extends</span>
AbstractOutDatabindingInterceptor {
    
    <span class="code-keyword">public</span> CustomOutInterceptor() {
        <span class="code-keyword">super</span>(Phase.MARSHAL);
    }

    <span class="code-keyword">public</span> void handleMessage(Message outMessage)
{
        Map&lt;<span class="code-object">String</span>, List&lt;<span
class="code-object">String</span>&gt;&gt; headers = (Map&lt;<span
class="code-object">String</span>, List&lt;<span class="code-object">String</span>&gt;&gt;)outMessage.get(Message.PROTOCOL_HEADERS);
        <span class="code-keyword">if</span> (headers == <span class="code-keyword">null</span>)
{
            headers = <span class="code-keyword">new</span> HashMap&lt;<span
class="code-object">String</span>, List&lt;<span class="code-object">String</span>&gt;&gt;();
            message.put(Message.PROTOCOL_HEADERS, headers);
        }
        <span class="code-comment">// modify headers  
</span>    }    
</pre>
</div></div>  

<p>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.<br/>
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. </p>

<h1><a name="JAX-RSFilters-IgnoringJAXRSMessageBodyWriters"></a>Ignoring
JAXRS MessageBodyWriters</h1>

<p>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 :</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
message.getExchange().put(<span class="code-quote">"ignore.response.writers"</span>,
<span class="code-keyword">true</span>);
</pre>
</div></div>

<h1><a name="JAX-RSFilters-Custominvokers"></a>Custom invokers</h1>

<p><b>Note</b> This feature is available starting from CXF 2.2.2 </p>

<p>Using custom JAXR-RS invokers is yet another way to pre or post process a given invocation.
For example, this <a href="http://svn.apache.org/repos/asf/cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/CustomJAXRSInvoker.java"
class="external-link" rel="nofollow">invoker</a> 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.</p>

<p>Custom invokers can be registered like this :</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-xml">
<span class="code-tag">&lt;beans&gt;</span>

<span class="code-tag">&lt;jaxrs:server address=<span class="code-quote">"/"</span>&gt;</span>

 <span class="code-tag">&lt;jaxrs:invoker&gt;</span>
   <span class="code-tag">&lt;bean class=<span class="code-quote">"org.apache.cxf.systest.jaxrs.CustomJAXRSInvoker"</span>/&gt;</span>
 <span class="code-tag">&lt;/jaxrs:invoker&gt;</span>
<span class="code-tag">&lt;/jaxrs:server&gt;</span>

<span class="code-tag">&lt;/beans&gt;</span>
</pre>
</div></div> 
    </div>
        <div id="commentsSection" class="wiki-content pageSection">
        <div style="float: right;">
            <a href="https://cwiki.apache.org/confluence/users/viewnotifications.action"
class="grey">Change Notification Preferences</a>
        </div>
        <a href="https://cwiki.apache.org/confluence/display/CXF20DOC/JAX-RS+Filters">View
Online</a>
        |
        <a href="https://cwiki.apache.org/confluence/pages/diffpagesbyversion.action?pageId=24190937&revisedVersion=3&originalVersion=2">View
Changes</a>
                |
        <a href="https://cwiki.apache.org/confluence/display/CXF20DOC/JAX-RS+Filters?showComments=true&amp;showCommentArea=true#addcomment">Add
Comment</a>
            </div>
</div>
</div>
</div>
</div>
</body>
</html>

Mime
View raw message