...
The following section describes the Apache Wink Client and provides a detailed description of the Apache Wink Client component and its functionality.
This section contains the following:
- Main Features
- High Level Architecture Overview
- Configuration
...
Apache Wink Client Overview
The Apache Wink Client is an easy-to-use client, providing a high level Java API for writing clients that consume HTTP-based RESTful Web Services. The Apache Wink Client utilizes JAX-RS concepts, encapsulates Rest standards and protocols and maps Rest principles concepts to Java classes, which facilitates the development of clients for any HTTP-based Rest Web Services.
...
- Utilizes JAX-RS Providers for resource serialization and deserialization
- Provides Java object models , such as Atomfor Atom, Json, RSS, APP, CSV, Multipart and OpenSearch and Json along with providers to serialize and deserialize these models
- Uses the JDK HttpUrlConnection as the underlying Http transport
- Allows for the easy replacement of the underlying Http transport
- Provides a Handlers mechanism for manipulation of HTTP request and response messages.
Supports
- Http proxy
- SSL
Apache Wink High Level Client Architecture Overview
The following diagram illustrates the high-level architecture of the Apache Wink Client.
Apache Wink Client High-Level View
The RestClient class is the Apache Wink Client entry point and is responsible for holding different configuration options and the provider registry.
The RestClient is used to create instances of the Resource class. The Resource class represents a web resource associated with a specific URI and is used to perform uniform interface operations on the resource it represents. Every method invocation goes through a user defined handlers chain that enables for manipulation of the request and response.
Getting Started with the Apache Wink Client
The following section details the getting started examples that demonstrate how to write a simple client that consume RESTful Web Services with the Apache Wink Client.
GET Request
...
// create the rest client instance
1 RestClient client = new RestClient();
// create the resource instance to interact with
2 Resource resource = client.resource("http://services.com/HelloWorld");
// perform a GET on the resource. The resource will be returned as plain text
3 String response = resource.accept("text/plain").get(String.class);
Explanation
The RestClient is the entry point for building a RESTful Web Service client. I order to start working with the Symphony Client, a new instance of RestClient needs to be created, as the example shows in line 1 of the example. A new Resource is then created with the given URI, by calling the RestClient#resource() method as appears in line 2.
Finally, the Resource#get() method is invoked in order to issue an Http GET request as appears in line 3.
Once the Http response is returned, the client invokes the relevant provider to desterilizes the response in line 3.
POST Request
...
// create the rest client instance
1 RestClient client = new RestClient();
// create the resource instance to interact with
2 Resource resource = client.resource("http://services.co");
// issue the request
3 String response = resource.contentType("text/plain").accept("text/plain").post(String.class, "foo");
Explanation
The POST Request example demonstrates how to issue a simple Http POST request that sends and receives resources as strings.
First, a new instance of a Resource is created through the RestClient. The Http POST request is then issued by specifying the request and response media types and the response entity type (String.class).
POST Atom Request
...
// create the rest client instance
1 RestClient client = new RestClient();
// create the resource instance to interact with
2 Resource resource = client.resource("http://services.co");
3 AtomEntry request = getAtomEntry();
// issue the request
4 AtomEntry response = resource.contentType("application/atom+xml").accept("application/atom+xml").post(AtomEntry.class, request);
Explanation
The Apache Wink Client provides an object model for Atom (atom feed and atom entry), and supplies out- of - the -box providers that enable sending and receiving atom feeds and entries. The example demonstrates how to issue an Http POST request that sends and receives atom entries.
Using ClientResponse
...
// create the rest client instance
1 RestClient client = new RestClient();
// create the resource instance to interact with
2 Resource resource = client.resource("http://services.co");
// issue the request
3 ClientResponse response = resource.accept("text/plain").get();
// deserialize response
4 String responseAsString = response.getEntity(String.class);
Explanation
This example demonstrates how to use the ClientResponse object in order to deserialize the response entity. If the response entity type is not provided when invoking the Resource#get() method that appears in line 3, the response will be returned as the raw ClientResponse. In order to trigger the response deserialization mechanism, the ClientResponse#getEntity() method needs to be invoked as it appears in line 4 with the required response entity type.
Client Configuration
The RestClient configuration is performed by using the ClientConfig class. An instance of the configuration class is passed to the constructor of the RestClient when constructing a new RestClient.
The following options can be configured in the RestClient:
- Custom providers via JAX-RS Application
- Handler chain
- Proxy host & port
...
and
...
- Redirect
Handler Configuration
...
response
...
Explanation
This example demonstrates how to register a custom handler. First, a new instance of a ClientConfig is created as it appears in line 1. Then the new handler is added to the handlers chain by invoking the handlers() method on the ClientConfig instance as it appears in line 2. Finally, a new instance of a RestClient is created with this configuration as it appears in line 3.
Custom Provider Configuration
...
1 ClientConfig config = new ClientConfig();
// Create new JAX-RS Application
2 Application app = new Application() {
@Override
public Set<Class<?>> getClasses() {
HashSet<Class<?>> set = new HashSet<Class<?>>();
set.add(FooProvider.class);
return set;}};
3 conf.applications(app);
// create the rest client instance
4 RestClient client = new RestClient(config);
// create the resource instance to interact with
5 Resource resource = client.resource("http://services.com/HelloWorld");
// perform a GET on the resource. the resource will be returned as plain text
6 String response = resource.accept("text/plain").get(String.class);
Explanation
This example demonstrates how to register a custom entity provider. First, a new instance of ClientConfig is created as it appears in line 1. Then a new anonymous Application is instantiated and set on the ClientConfig as it appears in line 2 and 3. Finally, a new instance of a RestClient is created with this configuration as it appears in line 4.
Client Handlers
The Apache Wink Client provides a Handlers mechanism that intercepts Http requests and responses. This mechanism is used to manipulate the request and response headers and allows the manipulation of the input and output entity streams by use of adapters.
An application develops custom handlers by implementing the ClientHandler interface. Custom handlers are registered via the ClientConfig configuration object. All registered handlers are invoked for every issued request, according to their registration order.
Custom Handlers
A custom handler implements the ClientHandler interface. The entry point of the handler is the handle() method. It receives the ClientRequest instance that encapsulates request information and allows for request data manipulation. It also receives the HandlerContext instance that is used to pass control to the next handler on the chain and to set input and output stream adapters.
Handlers are responsible for the flow control. It is handler's responsibility to call the next handler on the chain by invoking the doChain() method on the HandlerContext instance.
Custom Handler Implementation
A typical implementation of the "handle" method appears as follows:
...
public class MyHandler implements ClientHandler {
public ClientResponse handle(ClientRequest rqs, HandlerContext ctx) {
// Do something before request is issued to the web resource
1 rqs.getHeaders().add("CUSTOM-REQUEST-HEADER", "Foo-Request");
2 ClientResponse resp = ctx.doChain(request);
// Do something before response is returned to the client
3 resp.getHeaders().add("CUSTOM-RESPONSE-HEADER", "Foo-Response");
4 return resp;
}
}
Explanation
This example illustrates a typical implementation of the custom handler. First, the handler adds a custom header to the request as it appears in line 1, then it calls the next handler on the chain by invoking the doChain() method (line 2), adds a custom header to a response as it appears in line 3 and finally returns the response as it appears in line 4.
Input and Output Stream Adapters
The Apache Wink Client provides the ability to manipulate raw Http input and output entity streams through the InputStreamAdapter and the OutputStreamAdapter interfaces. This is useful for modifying the input and output streams, regardless of the actual entity, for example when adding compression capabilities.
The adapt() method of the output stream adapter is called before the request headers are committed, in order to allow the adapter to manipulate them.
The adapt() method of the input stream adapter is called after the response status code and the headers are received in order to allow the adapter to behave accordingly.
Stream Adapters Example
The following example demonstrates how to implement input and output adapters.
Gzip Handler
...
public class GzipHandler implements ClientHandler {
public ClientResponse handle(ClientRequest request,
HandlerContext context) {
request.getHeaders().add("Accept-Encoding", "gzip");
context.addInputStreamAdapter(new GzipInputAdapter());
context.addOutputStreamAdapter(new GzipOutputAdapter());
return context.doChain(request);
}}
Gzip Input Stream Adapter
...
class GzipInputAdapter implements InputStreamAdapter{
public InputStream adapt(InputStream is,
ClientResponse response) {
String header = response.getHeaders().getFirst("Content-Encoding");
if (header != null && header.equalsIgnoreCase("gzip")) {
return new GZIPInputStream(is);
}
return is;
}}
Gzip Output Stream Adapter
...
class GzipOutputAdapter implements OutputStreamAdapter {
public OutputStream adapt(OutputStream os,
ClientRequest request) {
request.getHeaders().add("Content-Encoding", "gzip");
return new GZIPOutputStream(os);
}}
Explanation
The Gzip handler creates instances of the GzipInputAdapter and the GzipOutputAdapter and adds them to the stream adapters of the current request by invoking the addInputStreamAdapter() and addOutputStreamAdapter() on the HandlerContext instance.