To enable data to be submitted to a server from the user interface and to enable data to be displayed on the user interface, you must bind your XUI files to the UDTT data model. This topic describes how to bind an XUI file to the UDTT data model.
To bind an XUI file to the UDTT data model, you must specify a context for the XUI file. A context is an object that is used to define and encapsulate data. For example, when a customer enters their name and account number into a banking application, the information is sent to and stored in a context. For more information on contexts, see Contexts.
There are two different types of contexts:
Global context
A global context defines and encapsulates data that can be shared across several application pages. For example, a session context can be used across many pages because it is a common function and not specific to a particular function.
Self-defined context
A self-defined context defines and encapsulates data that cannot be shared across application pages. For example, if there is a deposit page for a banking application, you must create a self-defined context that is related to this page only.
To specify a context for an XUI file
1 In the XUI editor area, click outside the root container.
2 In the Properties view for the XUI editor, click Select context.
The Please select a context window is opens.
3 In the Please select a context window, select the context that you want to bind to the XUI file. Click OK.
This topic describes general steps to bind data to widgets and gives some specific examples, such as select, combo, tree, table, and fileUpload widget.
This section provides an example of how to bind data to a select widget.
To define data structure
1 If you get data from context:
You need to specify data structure as following, an IndexedCollection data which includes a KeyedCollection Data, then there are two fields, field labelselect is for lable of select widget, field valueselect is for value of select widget.
Every IndexedCollection data must have at least one kColl data type as a root data container.
Specify the submitted data for the select widget. For example, it can be selectData.selectName.
2 If you get data from list files: You need to create a new javascript file in your project directory /WebContent/listFiles, for example: normal.js, the content is like:
3 Specify properties for select widget. To get data from list files, specify a value for urlForList; to get data from context data, specify a value for dataNameForList, labelField and valueField. Specify dataName for either of the two modes, which is the submitted value for select widget.
This section provides an example of how to bind data to a Combo widget.
If you get data from context
1 Define Data Structure:
Define an IndexedCollection data to define the data structure of comboBox as following, label is the data to specify combo label.
Every IndexedCollection data must have at least one kColl data type as a root data container.
Specify the submitted data for the comboBox. For example, it can be comboData.comboName.
2 Assign values to dataNameForList and labelField. You need to specify dataName for either of the two modes, which is the submitted value for combo widget.
If you get data from list files
1 Prepare a JavaScript file with proper data structure.
For example: /WebContent/listFiles/normal.js is like:Data in the first column is label field and the second column is value field.
2 Specify the JavaScript file path as the value of urlForList.
In this case, you do not need to edit labelField and valueField since they are defined in the JavaScript file.
This section provides an example of how to bind data to a tree widget.
To bind data to a tree widget
1 Define data structure. Make sure there is “treeModel” definition in btt.xml between <kColl id="classTable"></KColl> in data section.
<field id="treeModel" value="com.ibm.btt.dojo.model.TreeModel" description="A treeModel is used and only used to present tree item including label, value, etc, should not be used as generic collection." />
Then you need to define the tree structure model and submit data in operation or flow transaction. For example: add a treeModel type data Tree1RootModel as dataName for Tree content, add a simple filed data Tree1SubmitData as submit dataName for Tree.
Make sure you also define value for label and value for treeModel Tree1RootModel:
After you define treeModel, you need to initialize the treeModel in operation. For example:
public class InitContextOp extends BTTServerOperation { /** * <!-- begin-user-doc --> * <!-- end-user-doc --> */ public void execute() throws Exception { TreeModel root = (TreeModel) getElementAt("Tree1RootModel"); TreeModel level1_1 = new TreeModel("level1-1", "002", "%nls.bttsample/Level1"); TreeModel level2_1 = new TreeModel("level2-1", "005", "Level2"); level1_1.addChild(level2_1);
TreeModel level1_2 = new TreeModel("level1-2", "003", "Level1"); TreeModel level2_2 = new TreeModel("level2-2", "006", "Level2"); level1_2.addChild(level2_2);
TreeModel level1_3 = new TreeModel("level1-3", "004", "Level1"); TreeModel level2_3 = new TreeModel("level2-3", "007", "%nls.bttsample/Level2"); level1_3.addChild(level2_3);
This section provides an example of how to bind data to a table widget.
To bind data to a table widget
1 Define the data structure.
▪ Define the table column information in a KColl data tableRow, it can be used as submit dataName for single selection mode.
▪ Besides typed data, you could also define a KColl data ColumnData as a child to submit column dataName. Be cautious: This KColl cannot contain any IColl.
▪ Define the list data tableRowIColl which refer to the KeyedCollection data tableRow, it can be used as submit dataname for multiple selection mode.
▪ Define the list data tableData which refer to the KeyedCollection data tableRow, it is the data structure of the whole table data. You can initialize or change the table data in the operation.
Note You could also define a new KColl with the same name and children data as tableRow. Especially, when there is a KColl as child data, this KColl should contain the same children data, too.
2 Specify tableData as dataNameForList.
▪ If selectionMode is single, select tableData as dataName.
▪ If selectionMode is multiple, select tableRowIColl as dataName.
3 Specify Data binding for the column.
▪ Specify ColumnData as Data Name
▪ Advanced data binding properties for the column. According to Editable or not, there are different widgets for selection. You need to specify the related properties for selected 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>:
▪ 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());
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 ;