Tuesday Dec 18, 2012

What's new in Servlet 3.1 ? - Java EE 7 moving forward


Servlet 3.0 was released as part of Java EE 6 and made huge changes focused at ease-of-use. The idea was to leverage the latest language features such as annotations and generics and modernize how Servlets can be written. The web.xml was made as optional as possible. Servet 3.1 (JSR 340), scheduled to be part of Java EE 7, is an incremental release focusing on couple of key features and some clarifications in the specification.

The main features of Servlet 3.1 are explained below:
  • Non-blocking I/O - Servlet 3.0 allowed asynchronous request processing but only traditional I/O was permitted. This can restrict scalability of your applications. Non-blocking I/O allow to build scalable applications. TOTD #188 provide more details about how non-blocking I/O can be done using Servlet 3.1.
  • HTTP protocol upgrade mechanism - Section 14.42 in the HTTP 1.1 specification (RFC 2616) defines an upgrade mechanism that allows to transition from HTTP 1.1 to some other, incompatible protocol. The capabilities and nature of the application-layer communication after the protocol change is entirely dependent upon the new protocol chosen. After an upgrade is negotiated between the client and the server, the subsequent requests use the new chosen protocol for message exchanges. A typical example is how WebSocket protocol is upgraded from HTTP as described in Opening Handshake section of RFC 6455.

    The decision to upgrade is made in Servlet.service method. This is achieved by adding a new method: HttpServletRequest.upgrade and two new interfaces: javax.servlet.http.HttpUpgradeHandler and javax.servlet.http.WebConnection.

    TyrusHttpUpgradeHandler shows how WebSocket protocol upgrade is done in Tyrus (Reference Implementation for Java API for WebSocket).
  • Security enhancements
    • Applying run-as security roles to #init and #destroy methods
    • Session fixation attack by adding HttpServletRequest.changeSessionId and a new interface HttpSessionIdListener. You can listen for any session id changes using these methods.
    • Default security semantic for non-specified HTTP method in <security-constraint>
    • Clarifying the semantics if a parameter is specified in the URI and payload
  • Miscellaneous
    • ServletResponse.reset clears any data that exists in the buffer as well as the status code, headers. In addition, Servlet 3.1 will also clears the state of calling getServletOutputStream or getWriter.
    • ServletResponse.setCharacterEncoding: Sets the character encoding (MIME charset) of the response being sent to the client, for example, to UTF-8.
    • Relative protocol URL can be specified in HttpServletResponse.sendRedirect. This will allow a URL to be specified without a scheme. That means instead of specifying "http://anotherhost.com/foo/bar.jsp" as a redirect address, "//anotherhost.com/foo/bar.jsp" can be specified. In this case the scheme of the corresponding request will be used.
    • Clarification in HttpServletRequest.getPart and .getParts without multipart configuration.
    • Clarification that ServletContainerInitializer is independent of metadata-complete and is instantiated per web application.

A complete replay of What's New in Servlet 3.1: An Overview from JavaOne 2012 can be seen here (click on CON6793_mp4_6793_001 in Media).

Each feature will be added to the JSR subject to EG approval. You can share your feedback to users@servlet-spec.java.net.

Here are some more references for you:

Several features have already been integrated in GlassFish 4 Promoted Builds. Have you tried any of them ?

Here are some other Java EE 7 primers published so far:


And of course, more on their way! Do you want to see any particular one first ?

Tuesday Nov 27, 2012

Non-blocking I/O using Servlet 3.1: Scalable applications using Java EE 7 (TOTD #188)


Servlet 3.0 allowed asynchronous request processing but only traditional I/O was permitted. This can restrict scalability of your applications. In a typical application, ServletInputStream is read in a while loop.
public class TestServlet extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
         throws IOException, ServletException {    
ServletInputStream input = request.getInputStream();
       byte[] b = new byte[1024];
       int len = -1;
       while ((len = input.read(b)) != -1) {
          . . .
       }
   }
}
If the incoming data is blocking or streamed slower than the server can read then the server thread is waiting for that data. The same can happen if the data is written to ServletOutputStream.

This is resolved in Servet 3.1 (JSR 340, to be released as part Java EE 7) by adding event listeners - ReadListener and WriteListener interfaces. These are then registered using ServletInputStream.setReadListener and ServletOutputStream.setWriteListener. The listeners have callback methods that are invoked when the content is available to be read or can be written without blocking.

The updated doGet in our case will look like:

AsyncContext context = request.startAsync();
ServletInputStream input = request.getInputStream();
input.setReadListener(new MyReadListener(input, context));

Invoking setXXXListener methods indicate that non-blocking I/O is used instead of the traditional I/O. At most one ReadListener can be registered on ServletIntputStream and similarly at most one WriteListener can be registered on ServletOutputStream. ServletInputStream.isReady and ServletInputStream.isFinished are new methods to check the status of non-blocking I/O read. ServletOutputStream.canWrite is a new method to check if data can be written without blocking.

 MyReadListener implementation looks like:

@Override
public void onDataAvailable() {
try {
StringBuilder sb = new StringBuilder();
int len = -1;
byte b[] = new byte[1024];
while (input.isReady()
&& (len = input.read(b)) != -1) {
String data = new String(b, 0, len);
System.out.println("--> " + data);
}
} catch (IOException ex) {
Logger.getLogger(MyReadListener.class.getName()).log(Level.SEVERE, null, ex);
}
}

@Override
public void onAllDataRead() {
System.out.println("onAllDataRead");
context.complete();
}

@Override
public void onError(Throwable t) {
t.printStackTrace();
context.complete();
}

This implementation has three callbacks:
  • onDataAvailable callback method is called whenever data can be read without blocking
  • onAllDataRead callback method is invoked data for the current request is completely read.
  • onError callback is invoked if there is an error processing the request.
Notice, context.complete() is called in onAllDataRead and onError to signal the completion of data read.

For now, the first chunk of available data need to be read in the doGet or service method of the Servlet. Rest of the data can be read in a non-blocking way using ReadListener after that. This is going to get cleaned up where all data read can happen in ReadListener only.

The sample explained above can be downloaded from here and works with GlassFish 4.0 build 64 and onwards.

The slides and a complete re-run of What's new in Servlet 3.1: An Overview session at JavaOne is available here.

Here are some more references for you:

About

profile image
Arun Gupta is a technology enthusiast, a passionate runner, author, and a community guy who works for Oracle Corp.


Java EE 7 Samples

Stay Connected

Search

Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today