Showing posts with label j2ee6. Show all posts
Showing posts with label j2ee6. Show all posts

Returning a binary file from REST service

You might want to return a binary file such as image or pdf from a REST service, if thats the case then JAX-RS provides you with 3 options. I wanted to try those options to i did create a sample application, that you can download from here. I did create a HelloBinaryService.java file which is a resource class that has 3 methods in each of these methods i am reading a static image file from c:/temp and returning it

package com.webspherenotes.rest;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.StreamingOutput;

@Path("/hellobinary")
public class HelloBinaryService {

  @GET
  @Path("/file")
  @Produces("image/png")
  public File getFile(){
    File samplePDF = new File("c:/temp/distributedmap.png");
    return samplePDF;
  }

  @GET
  @Path("/fileis")
  @Produces("image/png")
  public InputStream getFileInputStream()throws Exception{
    FileInputStream fileIs = new FileInputStream("c:/temp/distributedmap.png");
    return fileIs;
  }

  @GET
  @Path("/fileso")
  @Produces("image/png")
  public StreamingOutput getFileStreamingOutput() throws Exception{
    
    return new StreamingOutput() {
      
      @Override
      public void write(OutputStream outputStream) throws IOException,
          WebApplicationException {
        FileInputStream inputStream = new FileInputStream("c:/temp/distributedmap.png");
        int nextByte = 0;
        while((nextByte  = inputStream.read()) != -1 ){
          outputStream.write(nextByte);
        }
        outputStream.flush();
        outputStream.close();
        inputStream.close();
      }
    };
  }
  
}
The first and easiest option would be to return a object of java.io.File directly and the JAX-RS will figure out how to read the file and return binary content of the file, but you cannot use this option if your returning a file that is not stored on the file system. Second option would be to return object of InputStream, in that case the InputStream could be pointing to file on local system or file stored in database or something like that, in this case JAX-RS container will figure out how to return bytes from InputStream and return it The last option would be to return object of StreamingOutput, this gives you most flexibility in this case JAX-RS container will give you control at the time of writing body of the message, this is little more work for you since you have to take care of reading the bytes from InputStream and write into output stream but then you get chance to compress the content,....

Createing Hello JAXRS service for deployment using Sun Jersey

If you want to build a REST service and deploy it in one of the Java EE 5 compliant containers for example WebSphere APplication Server 7.0, then you will have to use one of the external JAXRS containers such as Jersey, which is very popular among REST service developers.

I wanted to try this option out so i built a HelloJersey application that you can download from here. I followed these steps for building my sample application

  • First create a Dynamic Web APplication project called HelloJersey

  • Download following .jar files and add it to the WEB-INF/lib folder of your web application

    1. asm-3.1.jar

    2. jersey-core-1.5.jar

    3. jersey-server-1.5.jar

    4. jsr311-api-1.1.1.jar




  • Next create a HelloJerseyRESTService.java file like this

    package com.webspherenotes.rest;

    import javax.ws.rs.GET;
    import javax.ws.rs.Path;
    import javax.ws.rs.Produces;
    import javax.ws.rs.QueryParam;
    import javax.ws.rs.core.MediaType;

    @Path("/hellojersey")
    public class HelloJerseyRESTService {

    @GET
    @Produces(MediaType.TEXT_HTML)
    public String sayHello(@QueryParam("name") String name ){
    return "Hello " + name;
    }
    }

    The HelloJerseyRESTService only handles GET request and returns HTML markup


  • Next declare the Jersey servlet in the web.xml and create servlet mapping

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app id="WebApp_ID" version="2.5"
    xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
    <display-name>DynaCacheSample1</display-name>
    <servlet>
    <servlet-name>Jersey REST Service</servlet-name>
    <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
    <init-param>
    <param-name>com.sun.jersey.config.property.packages</param-name>
    <param-value>com.webspherenotes.rest</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
    <servlet-name>Jersey REST Service</servlet-name>
    <url-pattern>/rest/*</url-pattern>
    </servlet-mapping>
    <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.htm</welcome-file>
    <welcome-file>default.jsp</welcome-file>
    </welcome-file-list>
    </web-app>



  • After you deploy the application in container you should see that when the server is starting it will scan all the resource and in our case it should find only com.webspherenotes.rest.HelloJerseyRESTService

    [10/16/11 17:17:47:250 PDT] 0000000e ApplicationMg I WSVR0228I: User initiated module stop operation request completed on Module, HelloJersey.war, of application, DynaCacheSample1EAR
    [10/16/11 17:17:49:932 PDT] 0000000e ApplicationMg I WSVR0225I: User initiated module start operation requested on Module, HelloJersey.war, of application, DynaCacheSample1EAR
    [10/16/11 17:17:50:466 PDT] 0000000e webapp I com.ibm.ws.webcontainer.webapp.WebGroupImpl WebGroup SRVE0169I: Loading Web Module: HelloJersey.
    [10/16/11 17:17:50:521 PDT] 0000000e WASSessionCor I SessionContextRegistry getSessionContext SESN0176I: Will create a new session context for application key default_host/HelloJersey

    [10/16/11 17:17:50:602 PDT] 0000000e PackagesResou I Scanning for root resource and provider classes in the packages:
    com.webspherenotes.rest
    [10/16/11 17:17:50:666 PDT] 0000000e ScanningResou I Root resource classes found:
    class com.webspherenotes.rest.HelloJerseyRESTService

    [10/16/11 17:17:50:667 PDT] 0000000e ScanningResou I No provider classes found.
    [10/16/11 17:17:50:850 PDT] 0000000e WebApplicatio I Initiating Jersey application, version 'Jersey: 1.5 01/14/2011 12:36 PM'
    [10/16/11 17:17:51:816 PDT] 0000000e servlet I com.ibm.ws.webcontainer.servlet.ServletWrapper init SRVE0242I: [DynaCacheSample1EAR] [/HelloJersey] [Jersey REST Service]: Initialization successful.
    [10/16/11 17:17:51:817 PDT] 0000000e webcontainer I com.ibm.ws.wswebcontainer.VirtualHost addWebApplication SRVE0250I: Web Module HelloJersey has been bound to default_host[*:9080,*:80,*:9443,*:5060,*:5061,*:443].
    [10/16/11 17:17:51:824 PDT] 0000000e ApplicationMg I WSVR0226I: User initiated module start operation request completed on Module, HelloJersey.war, of application, DynaCacheSample1EAR
    [10/16/11 17:17:51:825 PDT] 0000000e AppBinaryProc I ADMA7021I: Distribution of application DynaCacheSample1EAR completed successfully.




You can test the service by either directly going to the http://localhost:9080/HelloJersey/rest/hellojersey?name=sunil URL or using the REST client

Create Hello JAX-RS service in WAS 8.0

The WAS 8.0 is Java EE 6.0 compliant that means it allows you to deploy JAX-RS compliant service and you dont have to go through painful steps for setting up external JAXRS container such as Jersey in your web application

I wanted to figure out what it takes to create HelloREST application in WAS 8.0 so i followed this steps to create Hello JAX-RS service. You can download the source code for sample from here


  • First i used RAD 8.0 to create Servlet Technology 3.0 compliant web application( Which means no need for web.xml or no need of declaring servlets)


  • Next create a HelloRestService class that is basically a REST service and is available at /hellorest url


    package com.webspherenotes.rest;

    import javax.ws.rs.GET;
    import javax.ws.rs.Path;
    import javax.ws.rs.Produces;
    import javax.ws.rs.QueryParam;

    @Path("/hellorest")
    public class HelloRESTService {

    @GET
    @Produces("text/html")
    public String sayHello(@QueryParam("name") String name){
    return "Hello " + name;
    }

    }




  • Next create HelloApplication class which is basically a REST servlet class like this.

    package com.webspherenotes.rest;

    import java.util.HashSet;
    import java.util.Set;

    import javax.ws.rs.ApplicationPath;
    import javax.ws.rs.core.Application;

    @ApplicationPath("/rest/")
    public class HelloApplication extends Application{

    @Override
    public Set<Class<?>> getClasses() {
    Set<Class<?>> s = new HashSet<Class<?>>();
    s.add(HelloRESTService.class);
    return s;
    }

    }

    The HelloApplication class extends javax.ws.rs.core.Application which helps you to declare the JAX-RS application, in this class i am overriding the getClasses() method which returns set of JAX-RS classes that act as JAX-RS service. In my case i do have only one HelloRESTService class so i am only adding that

  • Now deploy the application on your WAS 8.0 server, if you try accessing it by sending GET request to http://localhost:9080/HelloRESTService/rest/hellorest?name=Sunil URL and you should get Hello Sunil as response

Uploading file to particular directory

You can configure the File Upload support in servlet specification 3.0 so that it uploads files to particular directory on your server.


package com.webspherenotes.j2ee6.servlet;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Collection;
import java.util.Iterator;

import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;

/**
* Servlet implementation class HelloFileUploadAnnotationServlet
*/
@WebServlet("/hellofileupload")
@MultipartConfig(location="c:/temp/upload")
public class HelloFileUploadAnnotationServlet extends HttpServlet {
private static final long serialVersionUID = 1L;


protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("Entering HelloFileUploadAnnotationServlet.doPost()");
response.setContentType("text/html");
response.getWriter().println("Hello from FileUploadServlet");
Collection fileParts = request.getParts();
Iterator filePartIt = fileParts.iterator();
while(filePartIt.hasNext()){
Part filePart = filePartIt.next();
System.out.println("File Name " + filePart.getName());
System.out.println("File Size " + filePart.getSize());

System.out.println("File Content ");
BufferedReader fileReader =
new BufferedReader(new InputStreamReader(filePart.getInputStream()));
String line = null;
while(( line = fileReader.readLine()) != null){
System.out.println(line);
}
}
System.out.println("Exiting HelloFileUploadAnnotationServlet.doPost()");
}

}


In my case i am setting value of location to c:/temp/upload and then i tried uploading couple of files and now i can see that every time i upload a file a .tmp file gets created in c:/temp/upload

Setting limit on filesize to be uploaded

When your handling the file upload you might want to set limit on the file size that can be uploaded you can do that by setting value of maxFileSize. The value of maxFileSize is in bytes,

@WebServlet("/hellofileupload")
@MultipartConfig(maxFileSize=1000 )
public class HelloFileUploadAnnotationServlet extends HttpServlet {
private static final long serialVersionUID = 1L;


protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("Entering HelloFileUploadAnnotationServlet.doPost()");
response.setContentType("text/html");
response.getWriter().println("Hello from FileUploadServlet");
Collection fileParts = request.getParts();
Iterator filePartIt = fileParts.iterator();
while(filePartIt.hasNext()){
Part filePart = filePartIt.next();
System.out.println("File Name " + filePart.getName());
System.out.println("File Size " + filePart.getSize());

System.out.println("File Content ");
BufferedReader fileReader =
new BufferedReader(new InputStreamReader(filePart.getInputStream()));
String line = null;
while(( line = fileReader.readLine()) != null){
System.out.println(line);
}
}
System.out.println("Exiting HelloFileUploadAnnotationServlet.doPost()");
}

}


So in my sample application if i try to upload a file bigger than 1000 bytes it will throw a java.lang.IllegalStateException exception like this

[12/19/10 20:24:23:765 PST] 00000019 servlet E com.ibm.ws.webcontainer.servlet.ServletWrapper service
SRVE0068E: An exception was thrown by one of the service methods of the servlet [com.webspherenotes.j2ee6.servlet.HelloFileUploadAnnotationServlet]
in application [HelloServletAnnotationEAR]. Exception created : [java.lang.IllegalStateException:
SRVE8021E: The file being uploaded is too large.
at com.ibm.ws.webcontainer.srt.SRTServletRequest.parseMultipart(SRTServletRequest.java:3504)
at com.ibm.ws.webcontainer.srt.SRTServletRequest.prepareMultipart(SRTServletRequest.java:3413)
at com.ibm.ws.webcontainer.srt.SRTServletRequest.getParts(SRTServletRequest.java:3394)
at com.webspherenotes.j2ee6.servlet.HelloFileUploadAnnotationServlet.doPost(HelloFileUploadAnnotationServlet.java:31)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:595)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:668)
at com.ibm.ws.webcontainer.servlet.ServletWrapper.service(ServletWrapper.java:1133)
at com.ibm.ws.webcontainer.servlet.ServletWrapper.handleRequest(ServletWrapper.java:708)
at com.ibm.ws.webcontainer.servlet.ServletWrapper.handleRequest(ServletWrapper.java:435)
at com.ibm.ws.webcontainer.servlet.ServletWrapperImpl.handleRequest(ServletWrapperImpl.java:178)
at com.ibm.ws.webcontainer.filter.WebAppFilterManager.invokeFilters(WebAppFilterManager.java:1012)
at com.ibm.ws.webcontainer.webapp.WebApp.handleRequest(WebApp.java:3598)
at com.ibm.ws.webcontainer.webapp.WebGroup.handleRequest(WebGroup.java:303)
at com.ibm.ws.webcontainer.WebContainer.handleRequest(WebContainer.java:950)
at com.ibm.ws.webcontainer.WSWebContainer.handleRequest(WSWebContainer.java:1624)
at com.ibm.ws.webcontainer.channel.WCChannelLink.ready(WCChannelLink.java:197)
at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.handleDiscrimination(HttpInboundLink.java:445)
at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.handleNewRequest(HttpInboundLink.java:504)
at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.processRequest(HttpInboundLink.java:301)
at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.ready(HttpInboundLink.java:275)
at com.ibm.ws.tcp.channel.impl.NewConnectionInitialReadCallback.sendToDiscriminators(NewConnectionInitialReadCallback.java:214)
at com.ibm.ws.tcp.channel.impl.NewConnectionInitialReadCallback.complete(NewConnectionInitialReadCallback.java:113)
at com.ibm.ws.tcp.channel.impl.AioReadCompletionListener.futureCompleted(AioReadCompletionListener.java:165)
at com.ibm.io.async.AbstractAsyncFuture.invokeCallback(AbstractAsyncFuture.java:217)
at com.ibm.io.async.AsyncChannelFuture.fireCompletionActions(AsyncChannelFuture.java:161)
at com.ibm.io.async.AsyncFuture.completed(AsyncFuture.java:138)
at com.ibm.io.async.ResultHandler.complete(ResultHandler.java:204)
at com.ibm.io.async.ResultHandler.runEventProcessingLoop(ResultHandler.java:775)
at com.ibm.io.async.ResultHandler$2.run(ResultHandler.java:905)
at com.ibm.ws.util.ThreadPool$Worker.run(ThreadPool.java:1618)
]

Handling file upload in Servlet 3.0

Ability to handle file upload is one of the common requirements for web application. Before Servlet Specification 3.0 if you wanted to handle file upload you would have to use external library such as Apache Commons File upload to handle the file upload.

But starting from Servlet Specification 3.0 you dont need external library instead there is a native support. I wanted to try this so i followed these steps


  1. First i did create a index.jsp file like this

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    <%@page
    language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
    <html>
    <head>
    <title>index</title>
    <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
    </head>
    <body>
    <form action="hellofileupload" method="post" enctype="multipart/form-data" >
    <table>
    <tr>
    <td>File</td>
    <td><input type="file" name="samplefile" /></td>
    </tr>
    <tr><td><input type="submit"></td></tr>
    </table>
    </form>

    </body>
    </html>


    If you want to upload a file to the server you will have to set form encoding type to multipart/form-data. The index.jsp will submit form to the hellofileupload url and thats where our HelloFileUploadAnnotationServlet will come in

  2. Next create a HelloFileUploadAnnotationServlet like this

    package com.webspherenotes.j2ee6.servlet;

    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.util.Collection;
    import java.util.Iterator;

    import javax.servlet.ServletException;
    import javax.servlet.annotation.MultipartConfig;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import javax.servlet.http.Part;

    /**
    * Servlet implementation class HelloFileUploadAnnotationServlet
    */
    @WebServlet("/hellofileupload")
    @MultipartConfig
    public class HelloFileUploadAnnotationServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;


    protected void doPost(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
    System.out.println("Entering HelloFileUploadAnnotationServlet.doPost()");
    response.setContentType("text/html");
    response.getWriter().println("Hello from FileUploadServlet");
    Collection fileParts = request.getParts();
    Iterator filePartIt = fileParts.iterator();
    while(filePartIt.hasNext()){
    Part filePart = filePartIt.next();
    System.out.println("File Name " + filePart.getName());
    System.out.println("File Size " + filePart.getSize());

    System.out.println("File Content ");
    BufferedReader fileReader =
    new BufferedReader(new InputStreamReader(filePart.getInputStream()));
    String line = null;
    while(( line = fileReader.readLine()) != null){
    System.out.println(line);
    }
    }

    System.out.println("Exiting HelloFileUploadAnnotationServlet.doPost()");
    }
    }

    In order to use the file upload first you will have to mark the Servlet using MultipartConfig annotation, indicating that instances of the Servlet expect requests that conform to the multipart/form-data MIME type.
    Then inside the doPost() method you can use the method of HttpServletRequest to get access to the uploaded file.

Whats new in Servlet Specification 3.0

The Servlet Specification 3.0 has lot of new features such as


  1. Annotations

  2. Web Fragments

  3. Defining new servlet/filter using ServletContext API

  4. Async Servlet support



I want to try some of the features and i am planning to blog about them