Pages

Friday, 13 February 2015

Decoding GZIP compressed data using Interceptors & Filters in Jersey 2.x clients

Usecase:

Previously, we created a service that handles gzip encoding of data. Refer this for details. In this blogpost, I will show you how you can decode the gzip encoded data. Be sure to use Jersey 2.x. Details on interceptors and filters can be found here.

Pre-requisites:

JDeveloper 12.1.3.0.0

Steps:
Create a new custom application and invoke the RESTful Client and Proxy wizard. Supply the WADL URL for the previously created service and generate a client.
To decode the gzip encoded data, at the client end, we need to use a 'ReaderInterceptor'.
Let us first create a class 'GZipReaderInterceptor' which implements 'ReaderInterceptor'. In this class, write the below code. Notice the @Provider annotation at the class level.

package project1;

import java.io.IOException;
import java.io.InputStream;
import java.util.zip.GZIPInputStream;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.ext.Provider;
import javax.ws.rs.ext.ReaderInterceptor;
import javax.ws.rs.ext.ReaderInterceptorContext;
@Provider
public class GZipReaderInterceptor implements ReaderInterceptor {
    public GZipReaderInterceptor() {
        super();
    }

    @Override
    public Object aroundReadFrom(ReaderInterceptorContext readerInterceptorContext) throws IOException,WebApplicationException {
        // TODO Implement this method
        final InputStream originalInputStream = readerInterceptorContext.getInputStream();
        readerInterceptorContext.setInputStream(new GZIPInputStream(originalInputStream));
        return readerInterceptorContext.proceed();
    }
}

In the main client class, write the code to invoke the service, something like below in my case:

public class empClientClient {
    public static void main(String[] args) {
        Client client = empClient.createClient();
        empClient.Project1 empclientproject1 = empClient.project1(client);
        // add your code here
        System.out.println(empclientproject1.getAsXml(String.class));
    }
}
Also, in the auto generated code for you (on creating the client), go to the class which contains all the logic to invoke service operations. Find the method 'customizeClientConfiguration'. Add the below line in this method:

    private static void customizeClientConfiguration(Configurable cc) {
        cc.register(GZipReaderInterceptor.class);
    }
At this point, if you run the client, you will end up with below exception:

  Exception in thread "main" javax.ws.rs.ProcessingException: Error reading entity from input stream.
 at org.glassfish.jersey.message.internal.InboundMessageContext.readEntity(InboundMessageContext.java:868)
 at org.glassfish.jersey.message.internal.InboundMessageContext.readEntity(InboundMessageContext.java:785)
 at org.glassfish.jersey.client.ClientResponse.readEntity(ClientResponse.java:267)
 at org.glassfish.jersey.client.InboundJaxrsResponse$1.call(InboundJaxrsResponse.java:111)
 at org.glassfish.jersey.internal.Errors.process(Errors.java:315)
 at org.glassfish.jersey.internal.Errors.process(Errors.java:297)
 at org.glassfish.jersey.internal.Errors.process(Errors.java:228)
 at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:397)
 at org.glassfish.jersey.client.InboundJaxrsResponse.readEntity(InboundJaxrsResponse.java:108)
 at project1.empClient$Project1.getAsXml(empClient.java:295)
 at project1.empClientClient.main(empClientClient.java:15)
Caused by: java.util.zip.ZipException: Not in GZIP format
 at java.util.zip.GZIPInputStream.readHeader(GZIPInputStream.java:164)
 at java.util.zip.GZIPInputStream.<init>(GZIPInputStream.java:78)
 at java.util.zip.GZIPInputStream.<init>(GZIPInputStream.java:90)
 at project1.GZipReaderInterceptor.aroundReadFrom(GZipReaderInterceptor.java:24)
 

This is because the service expects the client to send a header 'Accept-Encoding'. So, let us add this header to the client requests. This header needs to be added before the request is sent to the server. For this, we will use a Pre Matching Filter. Create a new java class which implements 'ClientRequestFilter'. Add the below code into it. Notice that we have added the annotation @PreMatching.

package project1;

import java.io.IOException;
import javax.ws.rs.client.ClientRequestContext;
import javax.ws.rs.client.ClientRequestFilter;
import javax.ws.rs.container.PreMatching;

@PreMatching
public class PreRequestFilter implements ClientRequestFilter {
    public PreRequestFilter() {
        super();
    }

    public void filter(ClientRequestContext requestContext) throws IOException {
        requestContext.getHeaders().add("Accept-Encoding", "gzip");
            }
}

Also, go back to the method 'customizeClientConfiguration' and add another line in it to register this filter. The modified method now looks as below:
 private static void customizeClientConfiguration(Configurable cc) {
        cc.register(PreRequestFilter.class);
        cc.register(GZipReaderInterceptor.class);
    }
Now, run the client. You should be able to see the decoded response in the console.



If you see the corresponding request in analyzer, you should be able to see the header 'Accept-Encoding' as well as the response.



No comments:

Post a Comment