Develop an Ajax-based file upload portlet using DWR

        File upload is a basic function of today's Web portals. In this article, authors Xiaobo Yang and Rob Allan describe how to develop an Ajax-based file upload JSR 168-compliant portlet using DWR (Direct Web Remoting). DWR is an ideal Ajax framework for Java™ developers that dynamically generates JavaScript based on server-side deployed Java classes. You will learn how you can use DWR to retrieve file upload progress from the portal server.

Introduction

Web portals provide users a central gateway for accessing various resources and services. At the same time, they provide users a platform for contributing resources to be shared with other users. Users might share anything from photos to audio and video files to scientific datasets for research use. Therefore, file upload is a basic and necessary function of Web portals.

Today's Web portals are heavily based on Java portlet technology. While progress bars for file upload have been described by various developers using Ajax, we have yet to discover one that is portlet based. This article shows how to develop an Ajax-based file upload portlet that displays a progress bar during the file upload process. This portlet is particularly useful for those who need to share large audio, video, and scientific files.

To follow this article, you should be familiar with Web development using Java Servlets and JavaServer Pages (JSPs). Also, it is essential that you understand portal and portlet technology development. However, if you are not proficient with portlet technology, don't abandon the article now because you'll find a brief introduction to portlet technology as well as useful resources you can use to help you get up to speed.

 

Consider experimenting with one of the JSR 168-compliant portal frameworks, such as IBM® WebSphere® Portal Server, Apache Pluto, eXo platform, or Liferay Portal before testing the file upload portlet described in this article. We used Apache Pluto 1.0.1, the JDK 5.0 Update 10, and Apache Ant Version 1.6.5 during the process of developing this article.

Basic concepts of portlets

In general, portlets can be treated as Web components. Portlets are similar to servlets, but they focus on the presentation layer of your application. Typical output of a portlet is HTML fragments that can then be assembled by a Web portal. Portlets themselves are managed by a portlet container. The main features of portlets include:

  • Multiple modes: A portlet can have different views under different modes. For example, besides the view mode, a portlet can support the edit mode so that users can set their own preferences.
  • Multiple window states: A portlet can be minimized, maximized, and so on.
  • Customizable parameters: A portlet can define parameters, which are customizable by users.

To get more detailed information on portlets, refer to the Java Portlet Specification 1.0, JSR 168. (JSR 286, the successor to JSR 168, is due to be released in late 2007, with improvements such as inter-portlet communication and a portlet filter.) See Resources for links to this information.

Steps to get started with the file upload portlet

The cornerstone of your file upload portlet is the Apache Commons FileUpload package (also referred to as FileUpload in this article). In addition to file upload support in a servlet, the Apache Commons FileUpload Version 1.1 package supports file upload in a portlet as well. This article uses Apache Commons FileUpload Version 1.2.

Basically, you need to perform two steps to develop a file upload progress bar:

  1. Server side retrieval of file upload progress
  2. Client side retrieval and display of the upload progress from the portal server

 

Server side retrieval of file upload progress

The FileUpload package supports using a listener to retrieve file upload progress. In the doUpload() method of the file upload portlet (named uk.ac.dl.esc.gtg.myportlets.fileupload.FileUploadPortlet in the source files included in the Download area of this article), we set such a progress listener for PortletFileUpload by calling the setProgressListener() method as shown in Listing 1:


Listing 1. Set a progress listener for the file upload package

                
DiskFileItemFactory factory = new DiskFileItemFactory();
PortletFileUpload pfu = new PortletFileUpload(factory);
pfu.setSizeMax(uploadMaxSize); // Maximum upload size
pfu.setProgressListener(new FileUploadProgressListener());
            

FileUploadProgressListener (see Listing 2) is a listener that implements the org.apache.commons.fileupload.ProgressListener interface. The update() method is called automatically by the FileUpload package to refresh the latest information about how many bytes are transferred. In this article's implementation, progress is updated when every 10KB of data are transferred. This prevents progress updates from occurring too frequently. The getFileUploadStatus() method is used to calculate the current file upload progress, which will be called by the client using DWR (to be discussed in the next section).


Listing 2. File upload listener for retrieving file upload progress

                
package uk.ac.dl.esc.gtg.myportlets.fileupload;

import java.text.NumberFormat;

import org.apache.commons.fileupload.ProgressListener;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class FileUploadProgressListener implements ProgressListener {
	private static Log log = LogFactory.getLog(FileUploadProgressListener.class);

	private static long bytesTransferred = 0;

	private static long fileSize = -100;

	private long tenKBRead = -1;

	public FileUploadProgressListener() {
	}

	public String getFileUploadStatus() {
		// per looks like 0% - 100%, remove % before submission
		String per = NumberFormat.getPercentInstance().format(
				(double) bytesTransferred / (double) fileSize);
		return per.substring(0, per.length() - 1);
	}

	public void update(long bytesRead, long contentLength, int items) {
		// update bytesTransferred and fileSize (if required) every 10 KB is
		// read
		long tenKB = bytesRead / 10240;
		if (tenKBRead == tenKB)
			return;
		tenKBRead = tenKB;

		bytesTransferred = bytesRead;
		if (fileSize != contentLength)
			fileSize = contentLength;
	}

}
      

Client-side retrieval of file upload progress

Communication between the server and the client on file upload progress is realized using Ajax. We chose Direct Web Remoting (DWR) to provide Ajax support in our portlet. DWR is an ideal framework for Java developers to use to bring Ajax into the Web development processes because it allows JavaScript in a browser to interact with server-side Java objects. To use DWR in our portlet, the following steps are required (for more information about how to configure DWR, see Resources):

 

  • Configure DwrServlet through WEB-INF/web.xml (see Listing 3).
  • Define one or more server-side objects in WEB-INF/dwr.xml for the client to communicate. In Listing 4, FileUploadProgressListener is defined for DWR so that the client can call this auto-generated JavaScript. Also, only the getFileUploadStatus method is allowed to be called by the client. The other public method, update, is not allowed to be accessed (see Listing 2).
  • Include DWR-related JavaScript code in fileupload-view.jsp (see Listing 5).
  • Include the DWR library in our portlet application.


Listing 3. Configuration of DwrServlet in WEB-INF/web.xml

                
<!-- DWR servlet -->
  <servlet>
    <servlet-name>dwr-invoker</servlet-name>
    <display-name>DWR Servlet</display-name>
    <servlet-class>org.directwebremoting.servlet.DwrServlet</servlet-class>
    <init-param>
      <param-name>debug</param-name>
      <param-value>false</param-value>
    </init-param>
  </servlet>

<!-- DWR servlet mapping -->
  <servlet-mapping>
    <servlet-name>dwr-invoker</servlet-name>
    <url-pattern>/dwr/*</url-patter>
  </servlet-mappin>
  


Listing 4. WEB-INF/dwr.xml
                
<!DOCTYPE dwr PUBLIC "-//GetAhead Limited//DTD Direct Web Remoting 2.0//EN"
                     "http://getahead.org/dwr//dwr20.dtd">

<dwr>
  <allow>
    <create creator="new" javascript="FileUploadProgressListener">
      <param name="class"
             value="uk.ac.dl.esc.gtg.myportlets.fileupload.FileUploadProgressListener"/>
      <include method="getFileUploadStatus"/>
    </create>
  </allow>
</dwr>
  

The JSP file, fileupload-view.jsp, is shown in Listing 5 to illustrate how DWR helps to retrieve file upload progress from the server side. Once a file is selected and the Upload button (see Figure 1) is clicked, the fileupload_ajax_query_upload_status() method is called after one second. This method then calls the getFileUploadStatus() method of FileUploadProgressListener (see Listing 2) in asynchronous mode. Herein lies the beauty of DWR: The client is communicating with the server-side Java object. Once a response is received, the fileupload_ajax_show_upload_status() method is called to refresh the progress. If the file upload is not accomplished, an updated progress is retrieved after two seconds.


Listing 5. File upload portlet JSP file -- fileupload-view.jsp

                
<%@ page session="false" %>
<%@ page contentType="text/html" %>
<%@ page import="javax.portlet.PortletURL" %>
<%@ taglib uri="http://java.sun.com/portlet" prefix="portlet" %>
<portlet:defineObjects/>

<script type="text/javascript"
        src='<%= renderResponse.encodeURL(renderRequest.getContextPath()
				+ "/dwr/interface/FileUploadProgressListener.js") %>'> 
</script>

<script type="text/javascript"
        src='<%= renderResponse.encodeURL(renderRequest.getContextPath()
				+ "/dwr/engine.js") %>'> 
</script>

<script type="text/javascript"
        src='<%= renderResponse.encodeURL(renderRequest.getContextPath()
				+ "/dwr/util.js") %>'> 
</script>

<script type="text/javascript">
  function fileupload_ajax_query_upload_status() {
    FileUploadProgressListener.getFileUploadStatus

                 (fileupload_ajax_show_upload_status);
    return true;
  }

  function fileupload_ajax_show_upload_status(status) {
    if (status == "100")
      document.getElementById("fileupload_progress").innerHTML
                                       ="File successfully uploaded";
    else {
      document.getElementById("progressBar").style.display = "block";
      document.getElementById("fileupload_progress").innerHTML=
                                       "Uploading file: " + status
                                       + "% completed, please wait...";
      document.getElementById("progressBarBoxContent").style.width =
                                       parseInt(status * 3.5) + "px";
      setTimeout(fileupload_ajax_query_upload_status, 2000);
    }

    return true;
  }
</script>

<style type="text/css">
  #progressBar {padding-top: 5px;}
  #progressBarBox {width: 350px; height: 20px; border: 1px insert; background: #eee;}
  #progressBarBoxContent {width: 0; height: 20px; border-right: 1px solid #444;
                                       background: #9ACB34;}
</style>

<h4>File Upload</h4>

<!-- the upload form -->
<% PortletURL pUrl = renderResponse.createActionURL();
 %>
<form action="<%= pUrl.toString() %>"
         enctype="multipart/form-data" method="post"
	 οnsubmit="setTimeout('fileupload_ajax_query_upload_status()', 1000)">
	 
  <input type="file" name="fileupload_upload" value="Upload File">
  <input type="submit" value="Upload">
</form>

<%-- file upload progress bar --%>
<div id="fileupload_progress"></div>
<div id="progressBar" style="display: none;">
  <div id="progressBarBoxContent"></div>
</div>
      

Deploy and test the file upload portlet with Apache Pluto

The next step in the process is to deploy and test the file upload portlet with Apache Pluto 1.0.1. (Note: The binary version was used in this article.)

Code compilation and deployment

An Ant script is provided within the downloadable portlet source code included with this article so that you can compile the portlet and build up the .war file for deployment. First, you must copy the following library files to the lib directory under the root of the source code:

  • commons-fileupload-1.2/commons-fileupload-1.2.jar
  • commons-io-1.3/commons-io-1.3.jar
  • commons-logging-1.0.4/commons-logging-1.0.4.jar
  • dwr-2.0.1/dwr.jar
  • portletapi-1.0/portlet.jar
  • servletapi-2.4/servletapi-2.4.jar

Now you're ready to run ant build and ant war to compile the code and build up the .war file for deployment accordingly. If everything goes as planned, you will find myportlets-fileupload.war under the dist directory. Follow these steps to deploy the portlet using Apache Pluto 1.0.1:

  1. Start Apache Tomcat and access http://localhost:8080/pluto/portal.
  2. Click the Admin link on the left side of the Pluto screen to deploy the portlet.
  3. Locate myportlets-fileupload.war and then click Submit.
  4. Define a portlet title, description, and layout, and then click Submit.
  5. Click Submit again on the page that is displayed.

You are now asked to either restart Tomcat or click the link Hot deploy myportlets-fileupload portlet application. We suggest you click the link Hot deploy myportlets-fileupload portlet application. The portlet is then loaded as shown in Figure 1:


Figure 1. File upload portlet running in Apache Pluto
FileUpload portlet

Test the file upload portlet

Once the portlet is deployed, you are ready to upload a file. To get the progress bar displayed, you should access the portlet from a computer other than your portal server. To upload a file, do the following:

  1. Click the Browse... button to select a file for uploading.
  2. Click the Upload button to upload the selected file. During file upload, the progress bar is displayed and updated (see Figure 2).

If you want to test the portlet from the same computer where Pluto is installed, you won't be able to see the progress bar because the maximum upload size is set to 20MB. You can change the upload size by altering fileupload_upload_maxsize within the WEB-INF/portlet.xml file.


Figure 2. A file being uploaded within the file upload portlet
File upload portlet uploading a file

In our portlet, the uploaded file is saved as a disk file under java.io.tmpdir -- for example, temp under $PLUTO_HOME or $CATALINA_HOME. Keep in mind that in actual Web applications, further processing might be required. For example, the uploaded file may be stored in a database for future usage; if it is an image file, it may be displayed in a Web browser.

 

Other applications for this technique

The technique in this article has been successfully applied to a file transfer portlet that makes use of the GridFTP protocol for managing large datasets between two third-party data grid nodes.

Summary

This article demonstrated how to use Ajax to develop a file upload portlet to display a progress bar. You learned about server side retrieval of file upload progress using a progress listener, client-side retrieval of file upload progress using DWR from the portal server, and rendering the progress bar to end users. This portlet is especially useful for sharing large datasets like audio and video files and scientific data. It has also demonstrated the ease of use of DWR to bring Ajax support to JSR 168 portlets.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值