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 Client API
Date Wed, 06 Apr 2011 16:17: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+Client+API">JAX-RS
Client API</a></h2>
    <h4>Page <b>edited</b> by             <a href="https://cwiki.apache.org/confluence/display/~mazzag">Glen
Mazza</a>
    </h4>
        <div id="versionComment">
        <b>Comment:</b>
        API correction<br />
    </div>
        <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" > <br>String authorizationHeader
= &quot;Basic &quot;  <br></td></tr>
            <tr><td class="diff-changed-lines" >+ <span class="diff-changed-words">org.apache.cxf.common.util.Base64Utility<span
class="diff-added-chars"style="background-color: #dfd;">.encode</span>(&quot;user:password&quot;.getBytes());</span>
<br></td></tr>
            <tr><td class="diff-unchanged" > <br>// proxies <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 : Client API </span></p>

<div>
<ul>
    <li><a href='#JAX-RSClientAPI-ProxybasedAPI'>Proxy-based API</a></li>
<ul>
    <li><a href='#JAX-RSClientAPI-Customizingproxies'>Customizing proxies</a></li>
    <li><a href='#JAX-RSClientAPI-ConvertingproxiestoWebClientsandviceversa'>Converting
proxies to Web Clients and vice versa</a></li>
    <li><a href='#JAX-RSClientAPI-Handlingexceptions'>Handling exceptions</a></li>
    <li><a href='#JAX-RSClientAPI-ConfiguringproxiesinSpring'>Configuring proxies
in Spring</a></li>
    <li><a href='#JAX-RSClientAPI-Injectingproxies'>Injecting proxies</a></li>
    <li><a href='#JAX-RSClientAPI-Limitations'>Limitations</a></li>
    <li><a href='#JAX-RSClientAPI-Workingwithusermodels'>Working with user models</a></li>
</ul>
    <li><a href='#JAX-RSClientAPI-HTTPcentricclients'>HTTP-centric clients</a></li>
<ul>
    <li><a href='#JAX-RSClientAPI-Workingwithexplicitcollections'>Working with
explicit collections</a></li>
    <li><a href='#JAX-RSClientAPI-Handlingexceptions'>Handling exceptions</a></li>
    <li><a href='#JAX-RSClientAPI-ConfiguringHTTPclientsinSpring'>Configuring
HTTP clients in Spring</a></li>
</ul>
    <li><a href='#JAX-RSClientAPI-XMLcentricclients'>XML-centric clients</a></li>
    <li><a href='#JAX-RSClientAPI-ThreadSafety'>Thread Safety</a></li>
    <li><a href='#JAX-RSClientAPI-ConfiguringClientsatRuntime'>Configuring Clients
at Runtime</a></li>
    <li><a href='#JAX-RSClientAPI-CreatingclientsprogrammaticallywithnoSpringdependencies'>Creating
clients programmatically with no Spring dependencies</a></li>
    <li><a href='#JAX-RSClientAPI-ConfiguringanHTTPConduitfromSpring'>Configuring
an HTTP Conduit from Spring</a></li>
    <li><a href='#JAX-RSClientAPI-ClientsandAuthentication'>Clients and Authentication</a></li>
</ul></div>

<h1><a name="JAX-RSClientAPI-ProxybasedAPI"></a>Proxy-based API</h1>

<p>With the proxy-based API, one can reuse on the client side the interfaces or even
the resource classes which have already been designed for processing the HTTP requests on
the server side (note that a <a href="http://cglib.sourceforge.net/" class="external-link"
rel="nofollow">cglib</a>-nodeps dependency will need to be available on the classpath
for proxies created from concrete classes). When reused on the client side, they simply act
as remote proxies.</p>

<p><a href="http://svn.apache.org/repos/asf/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/JAXRSClientFactory.java"
class="external-link" rel="nofollow">JAXRSClientFactory</a> is a utility class which
wraps <a href="http://svn.apache.org/repos/asf/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/JAXRSClientFactoryBean.java"
class="external-link" rel="nofollow">JAXRSClientFactoryBean</a>. JAXRSClientFactory
offers a number of utility methods but JAXRSClientFactoryBean can also be used directly if
desired.</p>

<p>For example, given these class definitions:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
@Path(<span class="code-quote">"/bookstore"</span>)
<span class="code-keyword">public</span> <span class="code-keyword">interface</span>
BookStore {
   @GET
   Books getAllBooks();
   
   @Path(<span class="code-quote">"{id}"</span>)
   BookResource getBookSubresource(@PathParam(<span class="code-quote">"id"</span>)
<span class="code-object">long</span> id) <span class="code-keyword">throws</span>
NoBookFoundException;
}

<span class="code-keyword">public</span> class BookStoreImpl <span class="code-keyword">implements</span>
BookStore {
   <span class="code-keyword">public</span> Books getAllBooks() {}
   
   <span class="code-keyword">public</span> Book getBookSubresource(<span class="code-object">long</span>
id) <span class="code-keyword">throws</span> NoBookFoundException {}
}

<span class="code-keyword">public</span> <span class="code-keyword">interface</span>
BookResource {
   @GET
   Book getBook();
}

<span class="code-keyword">public</span> class BookResourceImpl <span class="code-keyword">implements</span>
BookResource {
   Book getBook() {}
}

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

<p>the following client code retrieves a Book with id '1' and a collection of books:
</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
BookStore store = JAXRSClientFactory.create(<span class="code-quote">"http:<span
class="code-comment">//bookstore.com"</span>, BookStore.class);
</span><span class="code-comment">// (1) remote GET call to http://bookstore.com/bookstore
</span>Books books = store.getAllBooks();
<span class="code-comment">// (2) no remote call
</span>BookResource subresource = store.getBookSubresource(1);
<span class="code-comment">// {3} remote GET call to http://bookstore.com/bookstore/1
</span>Book b = subresource.getBook();
</pre>
</div></div>     

<p>When proxies are created, initially or when subresource methods are invoked, the
current URI is updated with corresponding &#64;Path, &#64;PathParam, &#64;QueryParam
or @MatrixParam values, while &#64;HttpHeader and &#64;CookieParam values contribute
to the current set of HTTP headers. Same happens before the remote invocation is done. </p>

<p>It is important to understand that strictly speaking there is no direct relationship
between a given method on the client side and the same one on the server side. The job of
the proxy is to construct a correct URI according to given class and method specifications
- it may or may not be the same method on the corresponding server class that will be invoked
(provided of course that it is a JAX-RS annotated server resource class - but that may not
be the case!) More often than not, you will see a method foo() invoked on a server resource
class whenever the same method is invoked on the corresponding remote proxy - but in the presence
of &#64;Path annotations with arbitrary regular expressions this is not guaranteed, however
this doesn't matter, as the most important thing is that a proxy will produce a correct URI
and it will be matched as <b>expected</b> by a server class.   </p>

<p>Client-side MessageBodyReaders and MessageBodyWriters are used to process request
or response bodies just as they do on the server side. More specifically. method body writers
are invoked whenever a remote method parameter is assumed to be a request body (that is, it
has no JAX-RS annotations attached) or when a form submission is emulated with the help of
either &#64;FormParams or the JAX-RS MultivaluedMap. </p>

<p>You can make multiple remote invocations on the same proxy (initial or subresource),
the current URI and headers will be updated properly for each call. </p>

<p>If you would like to proxify concrete classes such as BookStoreImpl for example (say
you can not extract interfaces), then drop the cglib-nodeps.jar on a classpath. Such classes
must have a default constructor. All methods which have nothing to do with JAX-RS will simply
be ignored on the client side and marked as unsupported.</p>

<h2><a name="JAX-RSClientAPI-Customizingproxies"></a>Customizing proxies
</h2>

<p>Proxies end up implementing not only the interface requested at proxy creation time
but also a <a href="http://svn.apache.org/repos/asf/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/Client.java"
class="external-link" rel="nofollow">Client</a> interface. In many cases one does
not need to explicitly specify commonly used HTTP headers such as Content-Type or Accept as
this information will likely be available from &#64;Consumes or &#64;Produces annotations.
At the same time you may explicitly set either of these headers, or indeed some other header.
You can use a simple <a href="http://svn.apache.org/repos/asf/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/WebClient.java"
class="external-link" rel="nofollow">WebClient</a> utility method for converting
a proxy to a base client:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
BookStore proxy = JAXRSClientFactory.create(<span class="code-quote">"http:<span
class="code-comment">//books"</span>, BookStore.class);
</span>WebClient.client(proxy).accept(<span class="code-quote">"text/xml"</span>);
<span class="code-comment">// <span class="code-keyword">continue</span>
using the proxy    </span>
</pre>
</div></div>

<p>You can also check a current set of headers, current and base URIs and a client Response.</p>

<h2><a name="JAX-RSClientAPI-ConvertingproxiestoWebClientsandviceversa"></a>Converting
proxies to Web Clients and vice versa</h2>

<p>Using proxies is just one way to consume a service. Proxies hide away the details
of how URIs are being composed while HTTP-centric WebClients provide for an explicit URI creation.
Both proxies and http clients rely on the same base information such as headers and the current
URI so at any moment of time you can create a WebClient instance out of the existing proxy:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
BookStore proxy = JAXRSClientFactory.create(<span class="code-quote">"http:<span
class="code-comment">//books"</span>, BookStore.class);
</span>WebClient client = WebClient.create(proxy);
<span class="code-comment">// <span class="code-keyword">continue</span>
using the http client    </span>
</pre>
</div></div>

<p>At any moment of time you can convert an http client into a proxy too:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
BookStore proxy = JAXRSClientFactory.create(<span class="code-quote">"http:<span
class="code-comment">//books"</span>, BookStore.class);
</span>WebClient client = WebClient.create(proxy);
BookStore proxy = JAXRSClientFactory.fromClient(client, BookStore.class);
</pre>
</div></div>

<h2><a name="JAX-RSClientAPI-Handlingexceptions"></a>Handling exceptions</h2>

<p>There are a couple of ways you can handle remote exceptions with proxies.<br/>
One approach is to register a <a href="http://svn.apache.org/repos/asf/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/ResponseExceptionMapper.java"
class="external-link" rel="nofollow">ResponseExceptionMapper</a> as a provider either
from Spring using a jaxrs:client or using a corresponding JAXRSClientFactory utility method.
This way you can map remote error codes to expected checked exceptions or runtime exceptions
if needed.</p>

<p>If no ResponseExceptionMapper is available when a remote invocation failed then an
org.apache.cxf.jaxrs.client.ServerWebApplicationException (which is an instance of JAX-RS
WebApplication) will be thrown. At this point of time you can check the actual Response and
proceed from there:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
BookStore proxy = JAXRSClientFactory.create(<span class="code-quote">"http:<span
class="code-comment">//books"</span>, BookStore.class);
</span><span class="code-keyword">try</span> {
    proxy.getBook();
} <span class="code-keyword">catch</span>(ServerWebApplicationException ex) {
  Response r = ex.getResponse();
  <span class="code-object">String</span> message = ex.getMessage();
}
</pre>
</div></div>

<p>org.apache.cxf.jaxrs.client.ClientWebApplicationException will be thrown if the exception
has occurred for one of two reasons: </p>
<ul class="alternate" type="square">
	<li>the remote invocation succeeded but no proper MessageBodyReader has been found
on the client side; in this case the Response object representing the result of the invocation
will still be available</li>
	<li>the remote invocation has failed for whatever reasons on the client side, example,
no MessageBodyWriter is available.</li>
</ul>


<h2><a name="JAX-RSClientAPI-ConfiguringproxiesinSpring"></a>Configuring
proxies in Spring</h2>

<p>When creating a proxy with JAXRSClientFactory, you can pass a Spring configuration
location as one of the arguments. Or you can create a default bus using Spring configuration
and all proxies will pick it up:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
SpringBusFactory bf = <span class="code-keyword">new</span> SpringBusFactory();
Bus bus = bf.createBus(<span class="code-quote">"org/apache/cxf/systest/jaxrs/security/jaxrs-https.xml"</span>);
BusFactory.setDefaultBus(bus);
<span class="code-comment">// BookStore proxy will get the configuration from Spring
</span>BookStore proxy = JAXRSClientFactory.create(<span class="code-quote">"http:<span
class="code-comment">//books"</span>, BookStore.class);</span>
</pre>
</div></div> 

<h2><a name="JAX-RSClientAPI-Injectingproxies"></a>Injecting proxies</h2>

<p>For injecting proxies via a spring context, use the jaxrs:client element like:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-xml">
  &lt;jaxrs:client id=<span class="code-quote">"restClient"</span>
         address=<span class="code-quote">"http://localhost:${testutil.ports.BookServerRestSoap}/test/services/rest"</span>
         serviceClass=<span class="code-quote">"org.apache.cxf.systest.jaxrs.BookStoreJaxrsJaxws"</span>
         inheritHeaders=<span class="code-quote">"true"</span>&gt;
         <span class="code-tag">&lt;jaxrs:headers&gt;</span>
             <span class="code-tag">&lt;entry key=<span class="code-quote">"Accept"</span>
value=<span class="code-quote">"text/xml"</span>/&gt;</span>
         <span class="code-tag">&lt;/jaxrs:headers&gt;</span>
  <span class="code-tag">&lt;/jaxrs:client&gt;</span>  
</pre>
</div></div>

<p>See this <a href="http://svn.apache.org/repos/asf/cxf/trunk/systests/jaxrs/src/test/resources/jaxrs_soap_rest/WEB-INF/beans.xml"
class="external-link" rel="nofollow">bean</a> for a full example of how jaxrs:client
can be used to inject a proxy </p>

<h2><a name="JAX-RSClientAPI-Limitations"></a>Limitations</h2>

<p>Proxy methods can not have &#64;Context method parameters and subresource methods
returning Objects can not be invoked.  This is perhaps not much of a problem, as you can inject
contexts as field or bean properties and have subresource methods returning typed classes:
interfaces, abstract classes or concrete implementations. </p>

<p>When a proxy method returning a JAX-RS Response is invoked, the returned Response.getEntity()
will return a response InputStream by default. Starting with CXF 2.3.2 one can register an
org.apache.cxf.jaxrs.client.ResponseReader provider and cast the Response.getEntity() to more
specific application classes:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
ResponseReader reader = <span class="code-keyword">new</span> ResponseReader();
reader.setEntityClass(Book.class);
        
BookStore bs = JAXRSClientFactory.create(<span class="code-quote">"http:<span class="code-comment">//localhost:8080/books"</span>,
BookStore.class,
</span>                                         Collections.singletonList(reader));
Response r1 = bs.getBook(<span class="code-quote">"123"</span>);
Book book = (Book)r1.getEntity();

reader.setEntityClass(Author.class);
Response r2 = bs.getBookAuthor(<span class="code-quote">"123"</span>);
Author book = (Author)r2.getEntity();
</pre>
</div></div>

<h2><a name="JAX-RSClientAPI-Workingwithusermodels"></a>Working with user
models</h2>

<p>Proxies can be created with the external user model being applied to a proxy class,
for example:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
JAXRSClientFactory.createFromModel(<span class="code-quote">"http:<span class="code-comment">//books"</span>,
BookNoAnnotations.class, <span class="code-quote">"classpath:/resources/model.xml"</span>,
<span class="code-keyword">null</span>);</span>
</pre>
</div></div>

<p>BookNoAnnotations is either an interface or concrete class with no JAX-RS annotations.
Both client proxies and server endpoints can 'turn' it into a RESTful resource by applying
an external user model.</p>

<h1><a name="JAX-RSClientAPI-HTTPcentricclients"></a>HTTP-centric clients</h1>

<p>HTTP centric clients are <a href="http://svn.apache.org/repos/asf/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/WebClient.java"
class="external-link" rel="nofollow">WebClient</a> instances which also implement
the <a href="http://svn.apache.org/repos/asf/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/Client.java"
class="external-link" rel="nofollow">Client</a> interface. In addition to setting
various Client request properties, you can also make an explicit HTTP invocation with an HTTP
verb being the name of a given operation :</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
WebClient client = WebClient.create(<span class="code-quote">"http:<span class="code-comment">//books"</span>);
</span>Book book = client.path(<span class="code-quote">"bookstore/books"</span>).accept(<span
class="code-quote">"text/xml"</span>).get(Book.class);
</pre>
</div></div>

<p>You can choose to get an explicit JAX-RS Response instead and check the response
code, headers or entity body if any:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
WebClient client = WebClient.create(<span class="code-quote">"http:<span class="code-comment">//books"</span>);
</span>client.path(<span class="code-quote">"bookstore/books"</span>);
client.type(<span class="code-quote">"text/xml"</span>).accept(<span class="code-quote">"text/xml"</span>)
Response r = client.post(<span class="code-keyword">new</span> Book());
InputStream is = (InputStream)r.getEntity();
Book b = getFromInputStreamUsingJaxb(is);
</pre>
</div></div>

<p>org.apache.cxf.jaxrs.client.ResponseReader can be registered to make it possible
to cast Response.getEntity() to specific types.</p>

<p>WebClient lets you get back to a base URI or to a previous path segment and move
forward, it can be handy for getting a number of individual entries from a service with ids
embedded in path segments :</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
WebClient client = WebClient.create(<span class="code-quote">"http:<span class="code-comment">//books"</span>);
</span>List&lt;Book&gt; books = getBooks(client, 1L, 2L, 3L)

<span class="code-keyword">private</span> List&lt;Book&gt; getBooks(WebClient
client, <span class="code-object">Long</span> ...ids) {
   List&lt;Book&gt; books = <span class="code-keyword">new</span> ArrayList&lt;Book&gt;();

   <span class="code-keyword">for</span> (<span class="code-object">Long</span>
id : ids) {
       books.add(client.path(id).get(Book.class));
       client.back(); 
   } 
   <span class="code-keyword">return</span> books;
}
</pre>
</div></div>

<p>The above code will send requests like "GET <a href="http://books/1" class="external-link"
rel="nofollow">http://books/1</a>", "GET <a href="http://books/2" class="external-link"
rel="nofollow">http://books/2</a>", etc. </p>

<p>If the request URI can be parameterized then you may want to use the following code:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
Book book = WebClient.create(<span class="code-quote">"http:<span class="code-comment">//books"</span>).path(<span
class="code-quote">"{year}/{id}"</span>, 2010, 123).get(Book.class);
</span><span class="code-comment">// as opposed to
</span><span class="code-comment">// WebClient.create(<span class="code-quote">"http://books"</span>).path(2010).path(123).get(Book.class);</span>
</pre>
</div></div>


<p>When reusing the same WebClient instance for multiple invocations, one may want to
reset its state with the help of the reset() method, for example, when the Accept header value
needs to be changed and the current URI needs to be reset to the baseURI (as an alternative
to a back(true) call). The resetQuery() method may be used to reset the query values only.
Both options are available for proxies too.</p>

<h2><a name="JAX-RSClientAPI-Workingwithexplicitcollections"></a>Working
with explicit collections</h2>

<p>Example :</p>

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

Collection&lt;? <span class="code-keyword">extends</span> Book&gt; books
= WebClient.getCollection(Book.class);
Collection&lt;? <span class="code-keyword">extends</span> Book&gt; books
= WebClient.postAndGetCollection(<span class="code-keyword">new</span> ArrayList&lt;Book&gt;(),
Book.class);

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

<h2><a name="JAX-RSClientAPI-Handlingexceptions"></a>Handling exceptions</h2>


<p>You can handle remote exceptions by either explicitly getting a Response object as
shown above and handling error statuses as needed or you can catch either ServerWebApplicationException
or ClientWebApplicationException exceptions, the same way it can be done with proxies. </p>

<h2><a name="JAX-RSClientAPI-ConfiguringHTTPclientsinSpring"></a>Configuring
HTTP clients in Spring</h2>

<p>Like proxies, HTTP clients can be created using a number of WebClient static utility
methods: you can pass a location to a Spring configuration bean if needed or you can set up
a default bus as shown above. For example:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-xml">
&lt;bean id=<span class="code-quote">"myJsonProvider"</span> 
class=<span class="code-quote">"org.apache.cxf.jaxrs.provider.JSONProvider"</span>
&gt; 
        <span class="code-tag">&lt;property name=<span class="code-quote">"supportUnwrapped"</span>
value=<span class="code-quote">"true"</span> /&gt;</span> 
        <span class="code-tag">&lt;property name=<span class="code-quote">"wrapperName"</span>
value=<span class="code-quote">"nodeName"</span> /&gt;</span> 
    <span class="code-tag">&lt;/bean&gt;</span> 

<span class="code-tag">&lt;util:list id=<span class="code-quote">"webClientProviders"</span>&gt;</span>

    <span class="code-tag">&lt;ref bean=<span class="code-quote">"myJsonProvider"</span>/&gt;</span>

<span class="code-tag">&lt;/util:list&gt;</span> 

&lt;bean id=<span class="code-quote">"myWebClient"</span> class=<span class="code-quote">"org.apache.cxf.jaxrs.client.WebClient"</span>

factory-method=<span class="code-quote">"create"</span>&gt; 
        &lt;constructor-arg type=<span class="code-quote">"java.lang.String"</span>

value=<span class="code-quote">"http://some.base.url.that.responds/"</span> /&gt;

        <span class="code-tag">&lt;constructor-arg ref=<span class="code-quote">"webClientProviders"</span>
/&gt;</span> 
<span class="code-tag">&lt;/bean&gt;</span> 
</pre>
</div></div> 

<h1><a name="JAX-RSClientAPI-XMLcentricclients"></a>XML-centric clients</h1>

<p>XML-centric clients are WebClients using an <a href="http://svn.apache.org/repos/asf/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/xml/XMLSource.java"
class="external-link" rel="nofollow">XMLSource</a> utility class. XMLSource has a
number of methods facilitating the retrieval of JAXB beans, individual properties or links
with the help of XPath expressions. For example:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
WebClient wc = WebClient.create(<span class="code-quote">"http:<span class="code-comment">//aggregated/data"</span>);
</span>XMLSource source = wc.get(XMLSource.class);
source.setBuffering(<span class="code-keyword">true</span>);
Book b1 = source.getNode(<span class="code-quote">"/books/book[position() = 1]"</span>,
Book.class);
Book b2 = source.getNode(<span class="code-quote">"/books/book[position() = 2]"</span>,
Book.class);
</pre>
</div></div>

<p>Note that an XMLSource instance can be set to buffer the input stream thus allowing
for executing multiple XPath queries.<br/>
XMlSource can also help with getting the URIs representing the links or XML instances as Strings.</p>

<h1><a name="JAX-RSClientAPI-ThreadSafety"></a>Thread Safety</h1>

<p>Proxies and web clients (clients) are not thread safe by default. In some cases this
can be a limitation, especially when clients are injected; synchronizing on them can cause
performance side effects. </p>

<p>One way to 'make' clients thread-safe is to use WebClient.fromClient(Client) for
web clients or JAXRSClientFactoryBean.fromClient() factory methods which copy all the original
configuration properties and can be used to create new client instances per every request.</p>

<p>A single client doing multiple invocations without changing the current URI or headers
is thread-safe. The only limitation in this case applies to proxies, in that they can not
get "out of band" headers without synchronizing, ex :</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
<span class="code-comment">// get some response headers passed to us 'out of band',
which is not thread-safe <span class="code-keyword">for</span> a plain proxy:

</span><span class="code-object">String</span> bookHeader = WebClient.toClient(injectedBookStoreProxy).getHeaders().getFirst(<span
class="code-quote">"BookHeader"</span>); 
</pre>
</div></div>  

<p>Final option is to use a 'threadSafe' boolean property when creating proxies or web
clients (either from Spring or programmatically), see this <a href="http://svn.apache.org/repos/asf/cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSMultithreadedClientTest.java"
class="external-link" rel="nofollow">test</a> for more details. Thread-safe clients
created this way keep their state in a thread-local storage. </p>

<p>If a number of incoming threads is limited then one option is just do nothing, while
the other option is to reset the thread local state :</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
<span class="code-keyword">try</span> { 
   webClient.path(<span class="code-quote">"bar"</span>) 
   webClient.header(<span class="code-quote">"bar"</span>, baz); 
   webClient.invoke(...); 
} <span class="code-keyword">finally</span> { 
   <span class="code-comment">// <span class="code-keyword">if</span> using
a proxy: WebClient.client(proxy).reset(); 
</span>   webClient.reset(); 
} 
</pre>
</div></div>

<p>Yet another option is to use JAXRSClientFactoryBean and a 'secondsToKeepState' property
for creating thread-safe clients - this will instruct clients to clean-up the thread-local
state periodically.</p>


<h1><a name="JAX-RSClientAPI-ConfiguringClientsatRuntime"></a>Configuring
Clients at Runtime</h1>

<p>Proxy and http-centric clients are typically created by JAXRSClientFactory or WebClient
factory methods but <a href="http://svn.apache.org/repos/asf/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/JAXRSClientFactoryBean.java"
class="external-link" rel="nofollow">JAXRSClientFactoryBean</a> can also be used
for pre-configuring clients before they are created.</p>

<p>Sometimes, you may want to configure a client instance after it is been created.
For example, one may want to configure HTTPConduit programmatically, as opposed to setting
its properties using Spring. ClientConfiguration represents a client-specific configuration
state and can be accessed like this :</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
Book proxy = JAXRSClientFactory.create(<span class="code-quote">"http:<span class="code-comment">//books"</span>,
Book.class);
</span>ClientConfiguration config = WebClient.getConfig(proxy);
HTTPConduit conduit1 = (HTTPConduit)config.getConduit();

WebClient webclient = WebClient.create(<span class="code-quote">"http:<span class="code-comment">//books"</span>);
</span>HTTPConduit conduit2 = (HTTPConduit)WebClient.getConfig(webclient).getConduit();
</pre>
</div></div>


<h1><a name="JAX-RSClientAPI-CreatingclientsprogrammaticallywithnoSpringdependencies"></a>Creating
clients programmatically with no Spring dependencies</h1>

<p>Example :</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
JAXRSClientFactoryBean sf = <span class="code-keyword">new</span> JAXRSClientFactoryBean();
sf.setResourceClass(CustomerService.class);
sf.setAddress(<span class="code-quote">"http:<span class="code-comment">//localhost:9000/"</span>);
</span>BindingFactoryManager manager = sf.getBus().getExtension(BindingFactoryManager.class);
JAXRSBindingFactory factory = <span class="code-keyword">new</span> JAXRSBindingFactory();
factory.setBus(sf.getBus());
manager.registerBindingFactory(JAXRSBindingFactory.JAXRS_BINDING_ID, factory);
CustomerService service = sf.create(CustomerService.class);
WebClient wc = sf.createWebClient();
</pre>
</div></div> 


<h1><a name="JAX-RSClientAPI-ConfiguringanHTTPConduitfromSpring"></a>Configuring
an HTTP Conduit from Spring</h1>

<p>There's a number of ways to configure HTTPConduits for proxies and WebClients.</p>

<p>It is possible to have an HTTPConduit configuration which will apply to all clients
using different request URIs or only to those with using a specific URI. For example:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-xml">
<span class="code-tag">&lt;http:conduit name=<span class="code-quote">"http://books:9095/bookstore.*"</span>/&gt;</span>

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

<p>This configuration will affect all proxies and WebClients which have requestURIs
starting from 'http://books:9095/bookstore'. Note the trailing '.*' suffix in the name of
the http:conduit element.</p>

<p>Please see <a href="http://svn.apache.org/repos/asf/cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/security/jaxrs-https-url.xml"
class="external-link" rel="nofollow">this configuration file</a> for more examples.</p>

<p>Alternatively you can just do:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-xml">
<span class="code-tag">&lt;http:conduit name=<span class="code-quote">"*.http-conduit"</span>/&gt;</span>

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

<p>This configuration will affect all the clients, irrespective of the URIs being dealt
with.</p>

<p>If you work with proxies then you can have the proxy-specific configuration using
the expanded QName notation:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-xml">
<span class="code-tag">&lt;http:conduit name=<span class="code-quote">"{http://foo.bar}BookService.http-conduit"</span>/&gt;</span>

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

<p>In this example, 'foo.bar' is a reverse package name of the BookService proxy class.</p>

<p>Similarly, for WebClients you can do:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-xml">
<span class="code-tag">&lt;http:conduit name=<span class="code-quote">"{http://localhost:8080}WebClient.http-conduit"</span>/&gt;</span>

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

<p>In this example, 'http://localhost:8080' is the base service URI.</p>

<p>Please see <a href="http://svn.apache.org/repos/asf/cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/security/jaxrs-https.xml"
class="external-link" rel="nofollow">this configuration file</a> for more examples.</p>

<p>Also see <a href="/confluence/display/CXF20DOC/Client+HTTP+Transport+%28including+SSL+support%29"
title="Client HTTP Transport (including SSL support)">this wiki page</a> on how to
configure HTTPConduits.</p>

<h1><a name="JAX-RSClientAPI-ClientsandAuthentication"></a>Clients and Authentication</h1>

<p>Proxies and HTTP-centric clients can have the HTTP Authorization header set up explicitly:</p>

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

<span class="code-object">String</span> authorizationHeader = <span class="code-quote">"Basic
"</span> 
    + org.apache.cxf.common.util.Base64Utility.encode(<span class="code-quote">"user:password"</span>.getBytes());

<span class="code-comment">// proxies
</span>WebClient.client(proxy).header(<span class="code-quote">"Authorization"</span>,
authorizationHeader);

<span class="code-comment">// web clients
</span>webClient.header(<span class="code-quote">"Authorization"</span>,
authorizationHeader);

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

<p>or by providing a username and password pair at client creation time, for example:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
BookStore proxy = JAXRSClientFactory.create(<span class="code-quote">"http:books"</span>,
BookStore.class, <span class="code-quote">"username"</span>, <span class="code-quote">"password"</span>,
<span class="code-quote">"classpath:/config/https.xml"</span>);

WebClient client = WebClient.create(<span class="code-quote">"http:books"</span>,
<span class="code-quote">"username"</span>, <span class="code-quote">"password"</span>,
<span class="code-quote">"classpath:/config/https.xml"</span>);
</pre>
</div></div>

<p>When injecting clients from Spring, one can add 'username' and 'password' values
as attributes to jaxrs:client elements or add them to WebClient factory create methods.</p>
    </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+Client+API">View
Online</a>
        |
        <a href="https://cwiki.apache.org/confluence/pages/diffpagesbyversion.action?pageId=24190809&revisedVersion=10&originalVersion=9">View
Changes</a>
                |
        <a href="https://cwiki.apache.org/confluence/display/CXF20DOC/JAX-RS+Client+API?showComments=true&amp;showCommentArea=true#addcomment">Add
Comment</a>
            </div>
</div>
</div>
</div>
</div>
</body>
</html>

Mime
View raw message