Advertisment

Web Flow with Decorator Pattern

author-image
PCQ Bureau
New Update

Last month, we saw the power of Servlet filters to pre-process and

post-process the request/response flow in Java EE Web applications. Introduced

in Servlet API v2.3, filters are pluggable Web components that allow us to

intercept client request. While filters scale well to intercept incoming HTTP

request, intercepting the HTTP response can be problematic once the response is

flushed from a JSP view. In this article, we'll introduce another design pattern

called Decorator, which allows us to design custom response objects.

Advertisment

Decorator pattern



Decorator, a structural design pattern, helps to add behavior or
responsibilities to an existing object. The decorator pattern works by wrapping

the new 'decorator' object around the original object, which is typically

achieved by passing the original object as a parameter to the constructor of the

decorator, with the decorator implementing the new functionality.

Direct Hit!

Applies To: Java SE/EE developers



USP: Improve performance in Java EE Web applications by
compression response



Primary Link:
http://tinyurl.com/2gljfv




Google Keywords: Java Decorator Design Pattern

Whenever a client requests for a servlet/JSP file, the servlet container

creates two objects-HttpServletRequest and HttpServletResponse. These objects

are then passed to the doGet() or doPost() method, depending on the request

method. In this article, we'll decorate the HTTP Response object and route the

same to the client. The following figure depicts a wrapped version of the

container-generated HttpServletResponse type.

Advertisment

Design Response Wrappers



With wrappers, you can change the behavior or extend functionality of a class by
extending it. Wrapper classes in the Servlet API provide a customized

implementation of request and response interfaces. All you need to do for

implementing your own customized request or response objects is just to extend

from any of the following four wrapper classes:

  • ServletRequestWrapper

  • HttpServletRequestWrapper

  • ServletResponseWrapper

  • HttpServletResponseWrapper

Advertisment

The wrapper classes provide convenient implementations of the

HttpServletRequest and HttpServletResponse interfaces that can be sub-classed by

developers wishing to adapt the request and response from a Servlet. This

relieves you from the pain of providing blank implementations for unwanted

methods. Prior to wrapper classes, the only way to customize the request and

response objects was to provide implementations for each method of

ServletRequest and/or ServletResponse interface. Here, we'll implement our own

response object and send the same back to the client, as shown in the diagram on

the next page.

The filter at the end of the request processing chain has access to the

customized response object and can call the additional methods defined by the

wrapper class. This gives the filter an opportunity to perform any post

processing logic (such as compression) on the response object.

Advertisment

Filtering HTTP response



We'll leverage from the built-in wrapper classes to design our own customized
response wrapper. To improve performance and response time of our Web

application, we'll design a compression filter, which will zip the flushed

output from JSP pages before sending it to the clients. The first step in this

direction is to define a response wrapper class, as shown in the following code

fragment.

package com.pcquest.medtracker.compression;

import java.util.zip.GZIPOutputStream;



//other necessary imports

Advertisment

class PCQCompressionResponseWrapper extends

HttpServletResponseWrapper {



//helper class for the servlet response


private GZIPServletOutputStream servletGzipOS = null;


private PrintWriter pw = null;


private Object streamUsed = null;


CompressionResponseWrapper(HttpServletResponse resp) {


super(resp);


}





// Override HttpServletResponse methods to

use our stream objects

public ServletOutputStream getOutputStream()

throws IOException {



// Allow the servlet to access a servlet output stream (SOS)


// only if the servlet has not already accessed the print writer.


if ( (streamUsed != null) && (streamUsed != servletGzipOS) ) {


throw new IllegalStateException();


}


// Wrap the original servlet output stream with our compression SOS.


if ( servletGzipOS == null ) {


servletGzipOS


= new GZIPServletOutputStream(getResponse()


.getOutputStream());


streamUsed = servletGzipOS;


}


return servletGzipOS;


}


//similarly implement the getWriter() method


...


}















Advertisment

The next step is to pass the wrapper as an argument to the

FilterChaindo.Filter() method for further processing. The following code

fragment defines a filter implementation class, which passes out own custom

designed HTTP response object to the next entity in the request processing

chain. For the complete source code, watch out for the developer thread on

forums.pcquest. com.

package com.pcquest.medtracker.compression;

Advertisment

import java.util.zip.GZIPOutputStream;



//other necessary imports


class PCQCompressionFilter implements Filter {

//override init()

public void doFilter(ServletRequest req,



ServletResponse resp,


FilterChain fc)


throws IOException, ServletException {


HttpServletRequest request = (HttpServletRequest) req;


HttpServletResponse response = (HttpServletResponse) resp;



// Dose the client accept GZIP compression?



String valid_encodings = request.getHeader("Accept-Encoding");


if ( (valid_encodings != null) && (valid_encodings.indexOf("gzip") > -1) ) {


// Then wrap the response object with a compression wrapper


PCQCompressionResponseWrapper wrappedResp


= new PCQCompressionResponseWrapper(response);



// Declare that the response content is being GZIP

encoded.


wrappedResp.setHeader("Content-Encoding", "gzip");

// Chain to the next component (thus processing the

request)



fc.doFilter(request, wrappedResp);


// A GZIP compression stream must be "finished"


GZIPOutputStream gzos = wrappedResp.getGZIPOutputStream();


gzos.finish();


// The container handles the rest of the work.


ctx.log(cfg.getFilterName() + ": finished the request.");




} else {



fc.doFilter(request, response);


ctx.log(cfg.getFilterName() + ": no encoding performed.");


}


}


//override destroy() method


}




Rolling Compression Filter



After wrapping a customized response around the standard HTTP response object,
you need to configure the deployment descriptor file for your customized wrapper

filter to start intercepting outgoing response. The Web deployment plan is shown

here.

<filter>



CompressionFilter


com.pcquest.medtracker.compression.PCQCompressionFilter













CompressionFilter


/compress/*.jsp



>





After configuring the Web application, any request for URI matching

>/compress/*.jsp pattern will run through the compression filter.

Conclusion



The Decorator design pattern provides a scalable and easy customizable solution
to common business problems. Decorator adds power to simple inheritance through

delegation and run-time dispatching. Decorator is much powerful than simple

subclassing. With subclassing, you work with the class, whereas in the Decorator

pattern you modify objects dynamically. When you extend a class, the change you

make to the subclass will affect all instances of the child class. With the

Decorator pattern, though, you apply changes to each individual object you want

to.

Advertisment