Wednesday, September 10, 2014

How to Upload and Serve files using Java Servlets on OpenShift (With FIXES)

This is a modified version of the code in this post  How-To: Upload and Serve files using Java Servlets on OpenShift. The original post was written by Corey, Red Hat, Inc. OpenShift (PaaS) Senior Product Marketing Manager @ Red Hat.

When I ran Corey's code, I came across few issues. So below code includes some fixes for those issues.

Issues:

1. Corey's code has issues on local server (Local Tomcat 7 running on Windows in my case)

2. Files with space in the file name fails to be served.

Fix:

First of all, open you windows environment variables window and add a new variable for OPENSHIFT_DATA_DIR





As you can see, I've created a folder D:\openshift\uploads\ and added it to the windows environment variable OPENSHIFT_DATA_DIR. You can use any folder of your choice. Just make sure that the folder is outside your project folder and git.

Now, change Corey's version of Uploads.java to look like below. Changes are highlighted in bold letters.


 import java.io.File;  
 import java.io.FileInputStream;  
 import java.io.FileOutputStream;  
 import java.io.IOException;  
 import java.io.InputStream;  
 import java.io.OutputStream;  
 import java.io.PrintWriter;  
 import java.net.URLDecoder;  
 import javax.activation.MimetypesFileTypeMap;  
 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;  
 @WebServlet(name = "uploads", urlPatterns = { "/uploads/*" })  
 @MultipartConfig  
 public class Uploads extends HttpServlet {  
      private static final long serialVersionUID = 2857847752169838915L;  
      int BUFFER_LENGTH = 4096;  
      protected void doPost(HttpServletRequest request,  
                HttpServletResponse response) throws ServletException, IOException {  
           PrintWriter out = response.getWriter();  
           for (Part part : request.getParts()) {  
                InputStream is = request.getPart(part.getName()).getInputStream();  
                String fileName = getFileName(part);  
                FileOutputStream os = new FileOutputStream(  
                          System.getenv("OPENSHIFT_DATA_DIR") + fileName);  
                byte[] bytes = new byte[BUFFER_LENGTH];  
                int read = 0;  
                while ((read = is.read(bytes, 0, BUFFER_LENGTH)) != -1) {  
                     os.write(bytes, 0, read);  
                }  
                os.flush();  
                is.close();  
                os.close();  
                out.println(fileName + " was uploaded to "  
                          + System.getenv("OPENSHIFT_DATA_DIR"));  
           }  
      }  
      protected void doGet(HttpServletRequest request,  
                HttpServletResponse response) throws ServletException, IOException {  
           //Remove extra context path which exists in local Tomcat applications.  
           String filePath = request.getRequestURI().substring(  
                     request.getContextPath().length());  
           //Decode url. Fixes issue with files having space within the file name  
           filePath = URLDecoder.decode(filePath, "UTF-8");  
           File file = new File(System.getenv("OPENSHIFT_DATA_DIR")  
                     + filePath.replace("/uploads/", ""));  
           InputStream input = new FileInputStream(file);  
           response.setContentLength((int) file.length());  
           response.setContentType(new MimetypesFileTypeMap().getContentType(file));  
           OutputStream output = response.getOutputStream();  
           byte[] bytes = new byte[BUFFER_LENGTH];  
           int read = 0;  
           while ((read = input.read(bytes, 0, BUFFER_LENGTH)) != -1) {  
                output.write(bytes, 0, read);  
                output.flush();  
           }  
           input.close();  
           output.close();  
      }  
      private String getFileName(Part part) {  
           for (String cd : part.getHeader("content-disposition").split(";")) {  
                if (cd.trim().startsWith("filename")) {  
                     String filename = cd.substring(cd.indexOf('=') + 1);  
                     //remove extra file path in windows local machine  
                     return filename.substring(filename.lastIndexOf("\\") + 1)  
                               .trim().replace("\"", "");  
                }  
           }  
           return null;  
      }  
 }  

I've kept the above Uploads.java file in src/main/java. Here java folder is the source folder and the Uploads.java file is in the default package.

Folder structure (application created with OpenShift plugin on Eclipse):



Rest of the code and instructions are the same as in Corey's post How-To: Upload and Serve files using Java Servlets on OpenShift.

Hope this helps. Thanks Corey for your post, which gave the basic understanding of how upload works on OpenShift. Let me know if anyone needs help.

Have a great day!

4 comments:

  1. Hi, may i know how you create the servlet class (Uploads.java)?
    I was unable to create servlet class in my cloud application project until i checked it as web console module then only i can created the servlet class successfully.However, i got the HTTP Status 404 error. Can you please help me?

    Thank in advance.

    ReplyDelete
  2. Thank you for your article Unfortunately, it doesn't work for me. If I omit adding servlet information from web.xml, I get a 404 error because the server cannot find /uploads. If I do, a 500 error appears:

    java.lang.ClassNotFoundException: main.java.Uploads

    the same holds if I enter the class in web.cml simply as Uploads. Seemingly, the system only entered once into the servlet and complained about wrong path, an erratic behaviour often cited for Tomcat. In remote, the system works perfectly.

    I use regularly openshift domains opened created as DIY with Netbeans which contain servlets. I would like to try the more standard jboss-ews cartridge with Eclipse (although I do prefer Netbeans), but to no avail yet, at least as servlet are concerned.

    Best regards,

    Giuliano

    ReplyDelete
  3. Solved! For some reasons, the local server expected a call to /appname/uploads instead than /uploads, which would not work in the remote server. However, uploads without a slash worked like a charm!

    ReplyDelete
  4. You have posted very useful hint.

    I would like to try this upload example using my openshift account. But the original post written by Corey is no longer exist. Do you have the step by step instruction from his original post?


    It will be very helpful to me. Thanks a lot.

    Karen Cheng

    ReplyDelete