I am trying to use the ice:inputFile component with a few issues.
I use :
icefaces 1.8.2
jboss 4.2.3
seam 2.2.0.
I started from a basic empty seam-gen project and imported code from the seam-comp-showcase src files.
My results are:
- File gets uploaded OK
- Response from FileUploadServlet is always empty so the upload form disappears after first upload. I need to reload the page for the form to comeback.
- None of the listeners are called. Either the upload listener or the progress listener.
Here is my view:
Code:
<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:s="http://jboss.com/products/seam/taglib"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ice="http://www.icesoft.com/icefaces/component"
template="layout/template.xhtml">
<ui:define name="body">
<ice:panelGrid id="homePanelGrid" columns="2" columnClasses="leftMenu,leftMenu">
<img src="img/ICEfaces-logo.gif" alt="Icefaces and Seam: framework demo"/>
<ice:panelGroup id="homePanelGroup">
<form>
<ice:inputFile
id="inputFileName"
progressRender="true"
submitOnUpload="postUpload"
progressListener="#{inputFileController.fileUploadProgress}"
actionListener="#{inputFileController.uploadFile}"
/>
<ice:outputProgress
value="#{inputFileController.fileProgress}"
styleClass="uploadProgressBar"
/>
<h:messages layout="table"
globalOnly="false"
showDetail="true"
showSummary="false"/>
</form>
</ice:panelGroup>
</ice:panelGrid>
</ui:define>
</ui:composition>
Here is my controller:
Code:
package com.mydomain.testupload.action;
import java.io.File;
import java.io.FileFilter;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.EventObject;
import java.util.List;
import java.util.Map;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.Logger;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.log.Log;
import com.icesoft.faces.component.inputfile.InputFile;
@Scope(ScopeType.SESSION)
@Name("inputFileController")
public class SeamInputFileController implements Serializable{
@Logger Log log;
// File sizes used to generate formatted label
public static final long MEGABYTE_LENGTH_BYTES = 1048000l;
public static final long KILOBYTE_LENGTH_BYTES = 1024l;
// files associated with the current user
private final List<InputFileData> fileList =
Collections.synchronizedList(new ArrayList<InputFileData>());
// latest file uploaded by client
private InputFileData currentFile;
// file upload completed percent (Progress)
private int fileProgress = 10;
private String parentDirectory="";
/**
* <p>Action event method which is triggered when a user clicks on the
* upload file button. Uploaded files are added to a list so that user have
* the option to delete them programatically. Any errors that occurs
* during the file uploaded are added the messages output.</p>
*
* @param event jsf action event.
*/
public void uploadFile(ActionEvent event) {
log.info("SeamInputFileController.uploadFile");
InputFile inputFile = (InputFile) event.getSource();
if (inputFile.getStatus() == InputFile.SAVED) {
if (this.parentDirectory.equals("")){
this.parentDirectory = inputFile.getFile().getParent();
}
// reference our newly updated file for display purposes and
// added it to our history file list.
currentFile = new InputFileData(inputFile.getFileInfo());
synchronized (fileList) {
if (!listContains(currentFile.getFile().getName())){
//only add the file to the list if it isn't already there
//fileupload will just update a more recent version of the file
fileList.add(currentFile);
}
}
}
}
protected boolean listContains(String fileNm){
for (InputFileData ifd: this.fileList){
if (ifd.getFileInfo().getFileName().trim().equals(fileNm.trim())){
return true;
}
}
return false;
}
/**
* <p>This method is bound to the inputFile component and is executed
* multiple times during the file upload process. Every call allows
* the user to finds out what percentage of the file has been uploaded.
* This progress information can then be used with a progressBar component
* for user feedback on the file upload progress. </p>
*
* @param event holds a InputFile object in its source which can be probed
* for the file upload percentage complete.
*/
public void fileUploadProgress(EventObject event) {
log.info("SeamInputFileController.fileUploadProgress");
InputFile ifile = (InputFile) event.getSource();
fileProgress = ifile.getFileInfo().getPercent();
}
/**
* <p>Allows a user to remove a file from a list of uploaded files. This
* methods assumes that a request param "fileName" has been set to a valid
* file name that the user wishes to remove or delete</p>
*
* @param event jsf action event
*/
public void removeUploadedFile(ActionEvent event) {
// Get the inventory item ID from the context.
FacesContext context = FacesContext.getCurrentInstance();
Map map = context.getExternalContext().getRequestParameterMap();
String fileName = (String) map.get("fileName");
synchronized (fileList) {
InputFileData inputFileData;
for (int i = 0; i < fileList.size(); i++) {
inputFileData = (InputFileData)fileList.get(i);
// remove our file
if (inputFileData.getFileInfo().getFileName().equals(fileName)) {
//first remove it from the server
File f = new File(inputFileData.getFile().getAbsolutePath());
if (f.exists()) {
f.delete();
if (log.isDebugEnabled())log.debug("File "+f.getName()+" is deleted");
}
//then remove it from the list
fileList.remove(i);
break;
}
}
}
}
public InputFileData getCurrentFile() {
return currentFile;
}
public int getFileProgress() {
return fileProgress;
}
public List getFileList() {
return fileList;
}
public void destroy(){
log.info("destroying InputfileController");
try{
if (this.parentDirectory!=null){
/* remove the files that have been uploaded during this session */
File[] files = null;
File dir = new File(parentDirectory);
/* use a FileFilter to only get files & not directories */
if (dir!=null){
FileFilter fileFilter = new FileFilter(){
public boolean accept(File file){
return !file.isDirectory();
}
};
files = dir.listFiles(fileFilter);
}
if (files!=null){
for (int i=0; i< files.length; i++){
File f = (File)files[i];
String fname=f.getName();
if (f.exists()){
f.delete();
log.info("\t\tfile: "+fname+" deleted");
if (log.isDebugEnabled())log.debug("file: "+fname+" deleted");
}
}
}
}
} catch(Exception ex) {
/* no files to delete */
log.info("uploadDirectory is not set--no files to delete! exception");
ex.printStackTrace();
}
}
}
My web.xml:
Code:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<!-- Seam (using Icefaces) generated project-->
<!-- listeners required for this application -->
<listener>
<listener-class>org.jboss.seam.servlet.SeamListener</listener-class>
</listener>
<listener>
<listener-class>com.icesoft.faces.util.event.servlet.ContextEventRepeater</listener-class>
</listener>
<!-- filters -->
<filter>
<filter-name>Seam Filter</filter-name>
<filter-class>org.jboss.seam.servlet.SeamFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>Seam Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<context-param>
<param-name>javax.faces.STATE_SAVING_METHOD</param-name>
<param-value>server</param-value>
</context-param>
<!-- Facelets development mode (disable in production) -->
<context-param>
<param-name>facelets.DEVELOPMENT</param-name>
<param-value>@debug@</param-value>
</context-param>
<context-param>
<param-name>javax.faces.DEFAULT_SUFFIX</param-name>
<param-value>.xhtml</param-value>
</context-param>
<context-param>
<param-name>com.icesoft.faces.actionURLSuffix</param-name>
<param-value>.seam</param-value>
</context-param>
<context-param>
<param-name>com.icesoft.faces.synchronousUpdate</param-name>
<param-value>false</param-value>
</context-param>
<context-param>
<param-name>com.icesoft.faces.doJSFStateManagement</param-name>
<param-value>true</param-value>
</context-param>
<context-param>
<param-name>org.icesoft.examples.serverClock</param-name>
<param-value>false</param-value>
</context-param>
<context-param>
<param-name>com.icesoft.faces.standardRequestScope</param-name>
<param-value>true</param-value>
</context-param>
<context-param>
<param-name>com.icesoft.faces.uploadDirectory</param-name>
<param-value>upload</param-value>
</context-param>
<!-- servlets -->
<!-- file upload Servlet -->
<servlet>
<servlet-name>uploadServlet</servlet-name>
<servlet-class>com.icesoft.faces.component.inputfile.FileUploadServlet</servlet-class>
<load-on-startup> 1 </load-on-startup>
</servlet>
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet>
<servlet-name>Seam Resource Servlet</servlet-name>
<servlet-class>org.jboss.seam.servlet.ResourceServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>Persistent Faces Servlet</servlet-name>
<servlet-class>com.icesoft.faces.webapp.xmlhttp.PersistentFacesServlet</servlet-class>
<load-on-startup> 1 </load-on-startup>
</servlet>
<servlet>
<servlet-name>Blocking Servlet</servlet-name>
<servlet-class>com.icesoft.faces.webapp.xmlhttp.BlockingServlet</servlet-class>
<load-on-startup> 1 </load-on-startup>
</servlet>
<!-- servlet mappings -->
<servlet-mapping>
<servlet-name>uploadServlet</servlet-name>
<url-pattern>/uploadHtml</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Persistent Faces Servlet</servlet-name>
<url-pattern>*.seam</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Persistent Faces Servlet</servlet-name>
<url-pattern>/xmlhttp/*</url-pattern>
</servlet-mapping>
<!-- Blocking Servlet Mapping -->
<servlet-mapping>
<servlet-name>Blocking Servlet</servlet-name>
<url-pattern>/block/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Seam Resource Servlet</servlet-name>
<url-pattern>/seam/resource/*</url-pattern>
</servlet-mapping>
<security-constraint>
<display-name>Restrict raw XHTML Documents</display-name>
<web-resource-collection>
<web-resource-name>XHTML</web-resource-name>
<url-pattern>*.xhtml</url-pattern>
</web-resource-collection>
<auth-constraint/>
</security-constraint>
<!-- uncomment <ejb-local-ref> entries when deploying to GlassFish and (optionally) JBoss AS 5 -->
<!--
<ejb-local-ref>
<ejb-ref-name>testupload/AuthenticatorBean/local</ejb-ref-name>
<ejb-ref-type>Session</ejb-ref-type>
<local-home/>
<local>com.mydomain.testupload.action.Authenticator</local>
</ejb-local-ref>
-->
<!-- Add entries for each EJB session bean which is also a Seam component (not required on JBoss AS) -->
<persistence-unit-ref>
<persistence-unit-ref-name>testupload/pu</persistence-unit-ref-name>
<persistence-unit-name>../testupload.jar#testupload</persistence-unit-name>
<!-- The relative reference doesn't work on GlassFish. Instead, set the <persistence-unit-name> to "testupload",
package persistence.xml in the WAR, and add a <jar-file> element in persistence.xml with value "../../testupload.jar".
<persistence-unit-name>testupload</persistence-unit-name>
-->
</persistence-unit-ref>
</web-app>
These are basically the only pieces of code I modified from the seam-gen'ed project.
I tested the seam-comp-showcase on the same platform and it works, so I have a hard time understanding what I am doing wrong.
Any help would be much apprecaited.