Development tools : XUI editor : Editing an XUI page : Editing the properties of the XUI widgets : Binding data to the XUI widgets : Binding data to widgets : Binding data to a fileUpload widget
  
Binding data to a fileUpload widget
This section provides an example of how to bind data to a fileUpload widget.
To define data structure
1 Prepare runtime environment.
Copy commons-fileupload-1.2.2.jar from ${WAS home}\optionalLibraries\Apache\Struts\ to your runtime library and also copy commons-io-1.4.jar to your runtime library.
Make sure following fileHandlers are defined in your btt.xml between tag <kColl id="ajax"></kColl>:
<kColl id="fileHandlers">
  <kColl id="sampleFileHandler">
    <field id="implClass" value="com.ibm.btt.sample.SampleFileHandler" />
    <field id="timeout" value="20000" />
    <field id="maxSize" value="62914560" />
    <field id="cachePath" value="c:\temp\fileupload\cache" />
    <field id="filepath" value="c:\temp\fileupload\upload" />
    <field id="memCacheSize" value="4096" />
  </kColl>
</kColl>
Following source file SampleFileHandler.java is a sample code for your reference; make sure it is ready in package: com.ibm.btt.sample:
package com.ibm.btt.sample;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadBase.SizeLimitExceededException;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import com.ibm.btt.base.BTTLog;
import com.ibm.btt.base.BTTLogFactory;
import com.ibm.btt.base.Context;
import com.ibm.btt.base.DSEException;
import com.ibm.btt.base.DSEInvalidArgumentException;
import com.ibm.btt.base.DSEObjectNotFoundException;
import com.ibm.btt.base.KeyedCollection;
import com.ibm.btt.cs.ajax.fileupload.AbstractFileHandler;
import com.ibm.btt.cs.ajax.fileupload.FileUploadUtil;
import com.ibm.btt.sm.BTTSMException;
/**
*
* This class extends HttpServlet class used to handle file updload scenario.
* It will save the uploaded file in file system or configured DB
public class SampleFileHandler extends AbstractFileHandler{

private static final BTTLog LOG = BTTLogFactory.getLog(SampleFileHandler.class.getName());

/**
* name of paramters that will be configured in btt.xml file for this file handler
* make sure the name are exactly the same with the ones in btt.xml file
*/
public static final String PARAM_CACHE_PATH ="cachePath";
public static final String PARAM_FILE_PATH = "filepath";
public static final String PARAM_MEM_CACHE = "memCacheSize";
public static final String PARAM_TIME_OUT = "timeout";
public static final String PARAM_MAX_SIZE = "maxSize";

/**
* cache size, if file is bigger than the size, it will be saved in file system
* or else if will be hold in memory.
*/
protected int memCacheSize = 1024 * 4;
/**
* real system cache folder path
*/
protected String cachePath = null;
/**
* real system upload file folder
*/
protected String filePath = null;
/**
* maximum allowed size of a file
*/
protected long maxSize = 1024 * 1024 * 4;
/**
* fileId maybe a encryped, meaning-less string, maybe a key to
* real file system path of the uploaded file or a key by which the file
* can be accessed from DB.
* In this sample, it just use the file fullpath as the id
*/
private String fileId = null;
/**
* record the current tmp file, it will be used to remove the tmp file
* if the session expired.
*/
private FileItem tmpfile = null;
/**
* name of the file with ext.
*/
private String filename = null;
/**
* initial parameters, this method should be customized based on the handler's implementaion
*
*/
@Override
public void initConfig(KeyedCollection config) throws DSEException {
Enumeration keys = config.getElements().keys();
while(keys.hasMoreElements()){
String key = (String)keys.nextElement();
Object value = config.getValueAt(key);
if(PARAM_CACHE_PATH.equals(key)){
cachePath = value.toString();
}else if(PARAM_FILE_PATH.equals(key)){
filePath = value.toString();
}else if(PARAM_MEM_CACHE.equals(key)){
memCacheSize = Integer.parseInt(value.toString());
}else if(PARAM_TIME_OUT.equals(key)){
this.setTimeout(Long.parseLong(value.toString()));
}else if(PARAM_MAX_SIZE.equals(key)){
maxSize = Long.parseLong(value.toString());
maxSize = maxSize<0 ? -1 : maxSize ;
}
}
// formate file path based on OS, DOS or unix.
this.cachePath = formatFilePath(this.cachePath);
this.filePath = formatFilePath(this.filePath);

StringBuilder sb = new StringBuilder();
if(cachePath==null || cachePath.trim().length()<1){
sb.append("SampleFileHandler : Error, cachePath is null. \n");
}
if(filePath==null || filePath.trim().length()<1){
sb.append("SampleFileHandler : Error, filePath is null. \n");
}
if(memCacheSize<0){
sb.append("SampleFileHandler : Error, memory cache size must bigger than 0 \n");
}
if(getTimeout()<0){
sb.append("SampleFileHandler : Error, timeout value must bigger than 0 \n");
}
if(sb.length()>0){
throw new DSEException(sb.toString());
}
// create relative folders if not existed
initFolders();
}
/**
* Just handle one file upload in this handler, developer can extend to support
* multi-files upload
*/
@Override
public int saveFile(HttpServletRequest request) {
int code = SAVE_FAILED ;

boolean isMultipart = ServletFileUpload.isMultipartContent(request);
if (isMultipart) {
DiskFileItemFactory factory = new DiskFileItemFactory();
//config the memory cache, if above the cache, the file data will be
// saved on cache folder
factory.setSizeThreshold(memCacheSize);
// set up cache folder, when uploading, the tmp file
// will be saved in cache folder with a internal managed name.
factory.setRepository(new File(cachePath));

ServletFileUpload upload = new ServletFileUpload(factory);
// max size of a file
upload.setSizeMax(maxSize);
System.out.println("000maxSize:"+maxSize);

try {
if(isExpired()){
System.out.println("1111timeout!");
return REQ_TIMEOUT ;
}
List<fileItem>fileItems = upload.parseRequest(request);
// save file from request
code = uploadFilesFromReq(request, fileItems);
}catch(SizeLimitExceededException e){
code = FILE_SIZE_EXCEED ;
System.out.println("2222 size exceed!");
} catch (FileUploadException e) {
if(LOG.doDebug()){
LOG.debug("SampleFileHandler:saveFile() -- upload file stream was been cancelled", e);
}
}
}
return code;
}
/**
*
* @param request
* @param fileItems
* @throws IOException
*/
private int uploadFilesFromReq(HttpServletRequest request,
List<FileItem> fileItems){
int code = SAVE_FAILED ;
// get the first file item
FileItem fileItem = getTheFileItem(request,fileItems);
this.tmpfile = fileItem ;
String sessionId = request.getParameter("sessionId");
if(fileItem == null || sessionId == null){
return SAVE_FAILED ;
}
// save file and remove the temp file in cache folder
try {
code = writeFiles(fileItem, request,sessionId);

// remove temp file
fileItem.delete();
this.tmpfile = null;
} catch (IOException e) {
return SAVE_FAILED ;
}
// NOTES: just handle the firest file in the request, and save the first file
// in the file system. developer can extend to support multi-files upload
return code;
}
/**
* NOTES: In this sample, we just handle the first file item in the upload request.
*
* @param request
* @param fileItems upload file items
* @return the first file item or null if errors
*/
private FileItem getTheFileItem(HttpServletRequest request,List<FileItem> fileItems) {
String name="";
for (FileItem fileItem : fileItems) {
//common form item name
name = fileItem.getFieldName();
if (fileItem.isFormField()) {
// common form item value
String value = fileItem.getString();
if(LOG.doDebug()){
LOG.debug(new StringBuilder().append("Request item -- ").append(name).append(": ").append(value).toString());
}
} else {
if (name == null || "".equals(name.trim())) {
continue;
}
return fileItem ;
}
}
return null;
}
/**
* write the files into file sytem. upload files are seperated by sessionId on the
* server side.
* notes that for performance, here we do not use the FileItem.get() method.
*
* @param fileItem
* @param request
* @param sessionId
* @return whether save file success.
* @throws IOException
*/
private int writeFiles(FileItem fileItem, HttpServletRequest request,String sessionId)
throws IOException {
// get the target file folder where to save the uploaded file
// Here use the sessionId to seperate each request files.
StringBuilder spath = new StringBuilder();
spath.append(filePath).append("\\").append(sessionId);
File sFolder = new File(spath.toString());

if (!sFolder.isDirectory()) {
boolean r1 = sFolder.mkdir();
if(r1==false && LOG.doError()){
LOG.error(new StringBuilder().append("Create folder error: ").append(spath).toString());
throw new IOException(new StringBuilder().append("FileUploadServelet: session folder create error").toString());
}
}

// handle the file path for various browsers
String fileNameString = fileItem.getName();
int start = fileNameString.lastIndexOf("\\");
this.filename = fileNameString.substring(start + 1);
// save file
File file = new File(spath.toString(), filename);
byte[] buffer = new byte[1024];
int length = 0;
InputStream is = fileItem.getInputStream();
FileOutputStream fos = new FileOutputStream(file);
while ((length = is.read(buffer)) > 0 && !isExpired()) {
fos.write(buffer, 0, length);
}
// colse stream
fos.close();
is.close();

// remove file if request expired.
if(isExpired() ){
if(file.exists()){
file.delete();
}
return REQ_TIMEOUT ;
}
return SAVE_SUCCESS ;
}
@Override
public int deleteFile(String fileId) {
if(fileId==null || fileId.length()==0){
return DELETE_SUCCESS ;
}
if(isExpired()){
return REQ_TIMEOUT ;
}
File file = retrieveFile(fileId);
boolean r = false;
if(file!=null && file.exists()){
r = file.delete();
this.filename = null ;
}
// clean file Id
this.fileId = null ;

return r ? DELETE_SUCCESS: DELETE_FAILED;
}
@Override
public File retrieveFile(String fileId) {
if(fileId==null || fileId.length()==0 || isExpired()){
return null ;
}
File folder = new File(filePath+"\\"+getSessionId());
if(folder.exists() && folder.isDirectory()){
int value = Integer.parseInt(fileId);
File[] files = folder.listFiles();
for(int i=0; i<files.length; i++){
File file = files[i];
if(value==file.getName().hashCode()){
return file ;
}
}
}
return null;
}
@Override
public String getFileId() {
if(fileId==null && filename!=null){
fileId = new Integer(filename.hashCode()).toString();
}

return fileId ;
}
@Override
public String getFileName(String fileId) {
return this.filename;
}
@Override
public int upldateContext(String fileId) {
if(isExpired()){
return REQ_TIMEOUT ;
}
Context ctx = null;
try {
ctx = FileUploadUtil.getProperContext(getSessionId(), getProcessorId(),getDataname());
} catch (BTTSMException e) {
if(LOG.doError()){
LOG.error("SampleFileHandler : updateContext() -- ", e);
}
}
return doUpdateContext(ctx,fileId);
}

private int doUpdateContext(Context ctx, String fileId) {
int code = UPDATE_CTX_FAILED ;
if(ctx!=null){
try {
KeyedCollection kcoll = (KeyedCollection)ctx.tryGetElementAt(getDataname());
// note that the a kcoll with id=file is mandatory for file upload
//
KeyedCollection fkc = (KeyedCollection)kcoll.tryGetElementAt(FILE);
if(fkc!=null){
//upldated the new file info with the file kcoll.
fkc.setValueAt(FILE_ID, fileId);
fkc.setValueAt(FILE_NAME, this.filename);
File file = this.retrieveFile(fileId);
long size = file == null ? 0 : file.length();
fkc.setValueAt("size", size);

code = UPDATE_CTX_SUCCESS ;

//TODO this can be extend for multi-file upload scenario with a single fileupload
// widget.
// developer can add the existed file info into the iColl with
// id=receivedFiles. and then update the file kcoll with the latest
// uploaded file info
}
} catch (DSEInvalidArgumentException e) {
if(LOG.doError()){
LOG.error("SampleFileHandler: update context error",e);
}
} catch (DSEObjectNotFoundException e) {
if(LOG.doError()){
LOG.error("SampleFileHandler: update context error",e);
}
}
}
return code ;
}
@Override
public int cleanContext() {
return upldateContext("");
}
@Override
protected int doRequestValidation(HttpServletRequest request) {
int size = request.getContentLength();
System.out.println("file size validatoin : fsize = "+size+", max size = "+maxSize);
// notifiy the browser the file size is exceeded.
if(size>maxSize){
return FILE_SIZE_EXCEED ;
}
return REQ_VALID;
}
@Override
public String getFileInfo(int code){
StringBuilder sb = new StringBuilder();
String fId = getFileId();
fId = fId == null ? "": fId ;

String fname = getFileName(fId);
fname = fname == null ? "":fname ;

sb.append("{\"").append(FILE_NAME).append("\":\"")
.append(fname).append("\",\"")
.append(FILE_ID).append("\":\"").append(fId);
if(code!=UPDATE_CTX_SUCCESS){
sb.append("\",\"errorCode\":\"").append(code).append("\"}");
}else{
sb.append("\"}");
}
return sb.toString();
}
/**
* create cache file folders and real file folders
*
*/
private void initFolders() {
File fFolder = new File(filePath);
File tFolder = new File(cachePath);
boolean r1 = true ;
boolean r2 = true ;
if (!fFolder.isDirectory()) {
r1 = fFolder.mkdirs();
if(r1==false && LOG.doError()){
LOG.error(new StringBuilder().append("Create folder error: ").append(filePath).toString());
}
}
if(!tFolder.isDirectory()){
r2 = tFolder.mkdirs();
if(r2==false && LOG.doError()){
LOG.error(new StringBuilder().append("Create folder error: ").append(cachePath).toString());
}
}
}
/**
* format the file path associated with the OS
* @param path
* @return file path associated with the os
*/
private String formatFilePath(String path){
// We test if the entitiesPath is a complete adress for a directory (ex: "d:\er\wee" for DOS, or "/d/er/wee" for UNIX)
char sep = System.getProperty("file.separator").charAt(0);
String p = path.replace('/', sep);
p = path.replace('\\', sep);
if ((p.startsWith(System.getProperty("file.separator")))
|| ((p.length() > 1) && (p.charAt(1) == ':'))) {
return p ;
}
return null;
}
@Override
public AbstractFileHandler clone() {
AbstractFileHandler handler = new SampleFileHandler();
handler.setConfig(getConfig());
handler.setDataname(this.getDataname());
handler.setProcessorId(this.getProcessorId());
handler.setSessionId(this.getSessionId());
try {
handler.initConfig(this.getConfig());
} catch (DSEException e) {
return null ;
}
return handler;
}
/**
*
*/
@Override
public void onRequestExpired(String fileId) {
// delte tmp file if have
if(this.tmpfile!=null){
this.tmpfile.delete();
this.tmpfile = null;
}
// delete file if have
this.deleteFile(getFileId());
// clean ctx if have
this.cleanContext();
}
}
2 Define data structure.
Define following data structure in the transaction data definition, userFiles is the submitted dataname of fileupload widget.
This graphic is described in the surrounding text.
3 Specify properties for fileUpload widget.
Specify dataName as userFiles you defined, for example:
This graphic is described in the surrounding text.
Result
Data is bound to the fileUpload widget.
Go up to
Binding data to widgets