The following example demonstrates how to build a simple Echo2-Application which makes use of the Echo2FileTransfer-Library to upload and download files.
You can download a complete .war-file with sources and current build of the Echo2FileTransfer-Library for direct deployment into your application server here:
http://jfix.org/echo/FileTransferDemo.war
First of all we need a simple WEB-INF/web.xml to get started. Just the usual stuff, nothing fancy to see.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<display-name>FileTransferDemo</display-name>
<servlet>
<servlet-name>FileTransferDemo</servlet-name>
<servlet-class>FileTransferDemoServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>FileTransferDemo</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
That was easy... next we have to create the default application-servlet. Just create a Java-file in the default-package as FileTransferDemoServlet.java.
import nextapp.echo2.app.ApplicationInstance;
import nextapp.echo2.webcontainer.WebContainerServlet;
public class FileTransferDemoServlet extends WebContainerServlet {
public ApplicationInstance newApplicationInstance() {
return new FileTransferDemo();
}
}
And now we can build the main-application. For keeping things simple, all required code is put into the file below. In a real application you would seperate concerns more carefully, but its good to keep things simple for educational purposes.
Besides a small init() which just creates a column to hold the components, there are three interesting parts:
- FileWrapper: Just a simple class which stores contents of a file to a tmp-directory on disk. You should change this implementation for your own purposes. This example should provide typical information needed to understand how to handle content.
- getUploadSelect(): Creates an UploadSelect-Field. You have to register an UploadListener, which handles the upload of a file.
- getDownloadButton(FileWrapper): Creates a Button which handles the download of provided FileWrapper when clicked. You'll need to setup, activate and enqueue a DownloadProvider which provides the appropriate content, size, etc.pp.
Please see comments below to see how to wire things up correctly.
Create a Java-file in the default-package as FileTransferDemo.java.
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.TooManyListenersException;
import nextapp.echo2.app.ApplicationInstance;
import nextapp.echo2.app.Button;
import nextapp.echo2.app.Column;
import nextapp.echo2.app.ContentPane;
import nextapp.echo2.app.Window;
import nextapp.echo2.app.event.ActionEvent;
import nextapp.echo2.app.event.ActionListener;
import nextapp.echo2.app.filetransfer.Download;
import nextapp.echo2.app.filetransfer.DownloadProvider;
import nextapp.echo2.app.filetransfer.UploadEvent;
import nextapp.echo2.app.filetransfer.UploadListener;
import nextapp.echo2.app.filetransfer.UploadSelect;
/**
* Simple demo which shows how to transfer files with Echo2.
*
* This demo allows every user to upload files to the system-wide tmp-directory
* and to download these files again within the session.
*
* This is just an simple example how to use the Echo2-FileTransfer-Library. It
* is not intended for production use in any way!
*
* Please take appropriate means to secure your application when allowing users
* to upload content to your server.
*
* @author Maik Jablonski
*/
public class FileTransferDemo extends ApplicationInstance {
/**
* Creates a column with an upload-selection.
*/
public Window init() {
Column column = new Column();
column.add(getUploadSelect());
ContentPane contentPane = new ContentPane();
contentPane.add(column);
Window window = new Window();
window.setContent(contentPane);
return window;
}
/**
* Delivers an upload-selection and creates a download-button for each uploaded
* file.
*/
private UploadSelect getUploadSelect() {
UploadSelect uploadSelect = new UploadSelect();
try {
uploadSelect.addUploadListener(new UploadListener() {
public void fileUpload(UploadEvent uploadEvent) {
try {
// Read out the content of the uploaded file.
byte[] b = new byte[uploadEvent.getSize()];
uploadEvent.getInputStream().read(b, 0,
uploadEvent.getSize());
// Save content to disk via a FileWrapper.
FileWrapper file = new FileWrapper();
file.setName(uploadEvent.getFileName());
file.setType(uploadEvent.getContentType());
file.setContent(b);
// Add a download-button for uploaded file
((UploadSelect) uploadEvent.getSource()).getParent()
.add(getDownloadButton(file));
} catch (IOException ioe) {
// Urgs... do something nicely to inform the user.
ioe.printStackTrace();
}
}
public void invalidFileUpload(UploadEvent uploadEvent) {
// Clean up if something went wrong...
}
});
} catch (TooManyListenersException e) {
// Don't register more than one listener...
}
return uploadSelect;
}
/**
* Delivers a simple Download-Button for a given FileWrapper.
*
* The Download-Button has an ActionListener, which handles the download of
* a file when clicked. Therefore a DownloadProvider must be created,
* activated and enqueued as command to the application.
*/
private Button getDownloadButton(final FileWrapper file) {
Button button = new Button(file.toString());
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
Download download = new Download();
download.setProvider(new DownloadProvider() {
public String getContentType() {
return file.getType();
}
public String getFileName() {
return file.getName();
}
public int getSize() {
return (int) file.getSize();
}
public void writeFile(OutputStream stream)
throws IOException {
stream.write(file.getContent());
}
});
download.setActive(true);
enqueueCommand(download);
}
});
return button;
}
}
/*
* FileWrapper which stores content in a tmp-file.
*
* This is just an example and should be replaced by your own implementation
* depending on your real-storage.
*/
class FileWrapper {
private String name;
private String type;
private String path;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
/**
* Retrieves content from tmp-file.
*/
public byte[] getContent() throws IOException {
File file = new File(path);
byte[] content = new byte[(int) file.length()];
FileInputStream inputStream = new FileInputStream(file);
inputStream.read(content);
inputStream.close();
return content;
}
/**
* Stores content in a tmp-file.
*
* The current milliseconds are used as a "semi-unique" prefix for
* the temporary file. This works usually fine for demonstration
* purposes without much concurrency. Please use a synchronized
* "real" unique sequence for production use.
*/
public void setContent(byte[] content) throws IOException {
File tmpFile = File.createTempFile(String.valueOf(System
.currentTimeMillis()), null);
// Play nicely and delete files when the application stops...
tmpFile.deleteOnExit();
path = tmpFile.getCanonicalPath();
FileOutputStream outputStream = new FileOutputStream(tmpFile);
outputStream.write(content);
outputStream.close();
}
public long getSize() {
return new File(path).length();
}
public String toString() {
return name + " (" + type + ")" + " [" + getSize() / 1024 + " KB]";
}
}
Now you'll can start your container and visit the page via http://localhost:8080/.