问题
Update
I'm currently over at the ICEfaces forums to get my problem solved - sadly, none of the provided options led to a solution now, but they indeed gave me some more insight into the whole JSF topic (credits go to BalusC for that, as often :-)).
I will try to keep this thread up to date and post an answer if the problem is finally solved to help others which may encounter it.
My findings so far are:
- Disabling the Seam Multipart Filter is required because it prevents the fileEntry-component from working correctly
- I still have some nasty library issues in my application resulting in (silent) ClassLoading-issues: 2 icefaces-ace.jar-files were present, one in EAR/lib and one in EAR/WAR/WEB-INF/lib. Removing the one from WEB-INF results in the component doing nothing, removing the one from EAR/lib results in my app not longer deploying.
When moving all frontend jars (icefaces.jar, icefaces-ace.jar, icefaces-compat.jar) from EAR/lib to WEB-INF/lib, I receive various ClassNotFoundExceptions for the jar-part of my EAR: ValueChangeEvent, RowSelectorEvent etc. could not be found (that means, all those events coming from the view into the backend). Example:
12:12:42,145 ERROR [org.jboss.msc.service.fail] (MSC service thread 1-16) MSC00001:
Failed to start service jboss.deployment.subunit."myApp.ear"."myApp.jar".POST_MODULE:
org.jboss.msc.service.StartException in service
jboss.deployment.subunit."myApp.ear"."myApp.jar".POST_MODULE: Failed to process phase
POST_MODULE of subdeployment "myApp.jar" of deployment "myApp.ear"
at org.jboss.as.server.deployment.DeploymentUnitPhaseService.start(DeploymentUnitPhaseService.java:119) [jboss-as-server-7.1.1.Final.jar:7.1.1.Final]
at org.jboss.msc.service.ServiceControllerImpl$StartTask.startService(ServiceControllerImpl.java:1811) [jboss-msc-1.0.2.GA.jar:1.0.2.GA]
at org.jboss.msc.service.ServiceControllerImpl$StartTask.run(ServiceControllerImpl.java:1746) [jboss-msc-1.0.2.GA.jar:1.0.2.GA]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110) [rt.jar:1.7.0_06]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603) [rt.jar:1.7.0_06]
at java.lang.Thread.run(Thread.java:722) [rt.jar:1.7.0_06]
Caused by: java.lang.RuntimeException: Error getting reflective information for class my.company.myApp.myExampleBean with ClassLoader ModuleClassLoader for Module "deployment.myApp.ear.myApp.jar:main" from Service Module Loader
at org.jboss.as.server.deployment.reflect.DeploymentReflectionIndex.getClassIndex(DeploymentReflectionIndex.java:70) [jboss-as-server-7.1.1.Final.jar:7.1.1.Final]
at org.jboss.as.ee.metadata.MethodAnnotationAggregator.runtimeAnnotationInformation(MethodAnnotationAggregator.java:58)
at org.jboss.as.ee.component.deployers.InterceptorAnnotationProcessor.handleAnnotations(InterceptorAnnotationProcessor.java:85)
at org.jboss.as.ee.component.deployers.InterceptorAnnotationProcessor.processComponentConfig(InterceptorAnnotationProcessor.java:70)
at org.jboss.as.ee.component.deployers.InterceptorAnnotationProcessor.deploy(InterceptorAnnotationProcessor.java:55)
at org.jboss.as.server.deployment.DeploymentUnitPhaseService.start(DeploymentUnitPhaseService.java:113) [jboss-as-server-7.1.1.Final.jar:7.1.1.Final]
... 5 more
Caused by: java.lang.NoClassDefFoundError: com/icesoft/faces/component/ext/RowSelectorEvent
at java.lang.Class.getDeclaredMethods0(Native Method) [rt.jar:1.7.0_06]
at java.lang.Class.privateGetDeclaredMethods(Class.java:2442) [rt.jar:1.7.0_06]
at java.lang.Class.getDeclaredMethods(Class.java:1808) [rt.jar:1.7.0_06]
at org.jboss.as.server.deployment.reflect.ClassReflectionIndex.<init>(ClassReflectionIndex.java:65) [jboss-as-server-7.1.1.Final.jar:7.1.1.Final]
at org.jboss.as.server.deployment.reflect.DeploymentReflectionIndex.getClassIndex(DeploymentReflectionIndex.java:66) [jboss-as-server-7.1.1.Final.jar:7.1.1.Final]
... 10 more
Caused by: java.lang.ClassNotFoundException: com.icesoft.faces.component.ext.RowSelectorEvent from [Module "deployment.myApp.ear.myApp.jar:main" from Service Module Loader]
at org.jboss.modules.ModuleClassLoader.findClass(ModuleClassLoader.java:190) [jboss-modules.jar:1.1.1.GA]
at org.jboss.modules.ConcurrentClassLoader.performLoadClassUnchecked(ConcurrentClassLoader.java:468) [jboss-modules.jar:1.1.1.GA]
at org.jboss.modules.ConcurrentClassLoader.performLoadClassChecked(ConcurrentClassLoader.java:456) [jboss-modules.jar:1.1.1.GA]
at org.jboss.modules.ConcurrentClassLoader.performLoadClass(ConcurrentClassLoader.java:398) [jboss-modules.jar:1.1.1.GA]
at org.jboss.modules.ConcurrentClassLoader.loadClass(ConcurrentClassLoader.java:120) [jboss-modules.jar:1.1.1.GA]
... 15 more
The whole story
I'm working on an web application, using Seam 2.3 and ICEfaces 3.1.0. That means, JSF2 is being used.
My app is deployed on JBoss AS 7.1.0 as an EAR, containing a JAR for application logic and a WAR for all view related stuff.
I recently migrated from Seam 2.1.2 to Seam 2.3 and ICEfaces 1.8.2 to 3.1.0. That step was terrible, but now everything works fine, leaving aside some minor issues.
The only big issue is, when I'm using components to upload files, no matter if I use Seam components or ICEfaces components - in Seam, the uploaded file is always null and in ICEfaces, my fileEntryListener-Method never gets called.
With ICEfaces:
In ICEfaces versions prior to 2.X, there was the ice:inputFile
-component which has been removed with 2.X and replaced with ace:fileEntry
.
InputFile was working good, but FileEntry does not. My problem is exact the same as described in
JSF : Issues with File Upload using Icefaces component - the fileEntryListener is never called. I tried the suggestions there (using enctype="multipart/form-data" on the surrounding form, using h:commandButton
for form submission), but it didn't work. The only solution provided was switching to Richfaces, which is not an option for me.
With Seam:
Gladly, Seam has it's own build-in fileUpload-component, s:fileUpload
.
It doesn't work either, but at least showed me a spot where to look further. When debugging the doDecode-Methods of this component, I found that my request is no MultipartRequest. Crazy thing! All the forms used for uploading files declare the enctype as multipart/form-data. I think, the same is happening when I'm trying to use the ICEfaces component - no multipart request and that leads to no listeners being called.
So: How do I get this to work? What's the point that no Request comes in as MultipartRequest? Do I miss something in web/components.xml?
web.xml:
<web-app 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/xmlns/
javaee/web-app_3_0.xsd"
version="3.0">
<listener>
<listener-class>org.jboss.seam.servlet.SeamListener</listener-class>
</listener>
<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>*.seam</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.jsf</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>/icefaces/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.seam</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>Seam Resource Servlet</servlet-name>
<servlet-class>org.jboss.seam.servlet.SeamResourceServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Seam Resource Servlet</servlet-name>
<url-pattern>/seam/resource/*</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>Resource Servlet</servlet-name>
<servlet-class>com.icesoft.faces.webapp.CompatResourceServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Resource Servlet</servlet-name>
<url-pattern>/xmlhttp/*</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>60</session-timeout>
</session-config>
<context-param>
<param-name>javax.faces.FACELETS_SKIP_COMMENTS</param-name>
<param-value>true</param-value>
</context-param>
<context-param>
<param-name>facelets.DEVELOPMENT</param-name>
<param-value>true</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>javax.faces.FACELETS_REFRESH_PERIOD</param-name>
<param-value>-1</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>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>
<context-param>
<param-name>javax.faces.VALIDATE_EMPTY_FIELDS</param-name>
<param-value>false</param-value>
</context-param>
components.xml (leaving out the Seam 2.3 namespace declarations
<core:init jndi-pattern="java:app/myApp/#{ejbName}" debug="false"
distributable="false" />
<component class="org.jboss.seam.transaction.EjbSynchronizations"
jndi-name="java:app/jboss-seam/EjbSynchronizations" />
<core:manager concurrent-request-timeout="500"
conversation-timeout="90000000" conversation-id-parameter="cid"
parent-conversation-id-parameter="pid" />
<web:hot-deploy-filter url-pattern="*.seam" />
<web:multipart-filter create-temp-files="true"
max-request-size="1000000"
url-pattern="/*"/>
<persistence:managed-persistence-context
name="entityManager" auto-create="true" persistence-unit-jndi-name="java:/myAppEntityManagerFactory" />
<security:identity authenticate-method="#{authenticator.authenticate}" />
<security:remember-me enabled="true" />
<security:rule-based-permission-resolver
security-rules="#{securityRules}" />
<drools:rule-base name="securityRules">
<drools:rule-files>
<value>/security.drl</value>
</drools:rule-files>
</drools:rule-base>
<async:quartz-dispatcher />
<factory name="sessionTimeoutSeconds" scope="SESSION"
value="#{facesContext.externalContext.getSession(true).getMaxInactiveInterval()}" />
<factory name="basePath"
value="#{facesContext.externalContext.request.scheme}://#{facesContext.externalContext.request.serverName}:
#{facesContext.externalContext.request.serverPort}#{facesContext.externalContext.request.contextPath}" />
<factory name="contextPath"
value="#{facesContext.externalContext.request.contextPath}" />
Example JSF-source (Seam)
<h:form enctype="multipart/form-data">
<s:decorate>
<s:fileUpload data="#{uploadBean.fileData}"
contentType="#{uploadBean.contentType}"
fileName="#{uploadBean.fileName}" />
<h:commandButton value="Upload File" type="submit" />
</s:decorate>
</h:form>
Example JSF-source (ICEfaces)
<h:form enctype="multipart/form-data">
<ace:fileEntry id="file-entry" relativePath="/files/"
fileEntryListener="#{uploadBean.uploadFile}"
useSessionSubdir="true" />
<h:commandButton id="submit" type="submit" value="Send File" />
</h:form>
JSF maps to a Seam component, having a byte[] for fileData and String's for fileName and contentType. The fileEntryListener maps to a void method which takes a FileEntryEvent
as input.
Update
Just to keep you up to date, my findings so far:
Thinking about BalusC's answer, I looked deeper into the filter stuff. I already tried to add/remove the Seam Multipart Filter, but now I found out that when I add it in components.xml and explicitly disable it via
<web:multipart-filter disabled="true"/>
at least something is happening with ICEfaces: Exceptions are thrown by the FileEntryPhaseListener, what has never happened before:
09:26:19,124 SEVERE [javax.enterprise.resource.webcontainer.jsf.context] (http- localhost-127.0.0.1-8080-2) JSF1071: javax.faces.event.AbortProcessingException erfasst während beforePhase()-Verarbeitung von RENDER_RESPONSE 6 : UIComponent-ClientId=, Message=/ template/patient/documents/instantiation/documentInsertPopup.xhtml @135,98 fileEntryListener="#{uploadBean.fileUploadListener}": Method not found: my.company.package.stuff.UploadBean@313d 62f1.fileUploadListener(org.icefaces.ace.component.fileentry.FileEntryEvent) 09:26:19,126 SEVERE [javax.enterprise.resource.webcontainer.jsf.context] (http- localhost-127.0.0.1-8080-2) /template/upload.xhtml @135,98 fileEntryListener="# {uploadBean.fileUploadListener}": Method not found: my.company.package.stuff.UploadBean@313d 62f1.fileUploadListener(org.icefaces.ace.component.fileentry.FileEntryEvent): javax.faces.event.AbortProcessingException: /upload.xhtml @135,98 fileEntryListener="# {uploadBean.fileUploadListener}": Method not found: my.company.package.stuff.UploadBean@313d 62f1.fileUploadListener(org.icefaces.ace.component.fileentry.FileEntryEvent) at org.icefaces.ace.component.fileentry.FileEntry.broadcast(FileEntry.java:350) [icefaces-ace.jar:] at org.icefaces.ace.component.fileentry.FileEntryPhaseListener$1.visit(FileEntryPhaseListener.java:95) [icefaces-ace.jar:] at com.sun.faces.component.visit.PartialVisitContext.invokeVisitCallback(PartialVisitContext.java:183) [javax.faces.jar:2.1.4-FCS] at javax.faces.component.UIComponent.visitTree(UIComponent.java:1612) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final] at javax.faces.component.UIComponent.visitTree(UIComponent.java:1623) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final] at javax.faces.component.UIComponent.visitTree(UIComponent.java:1623) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final] at javax.faces.component.UIComponent.visitTree(UIComponent.java:1623) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final] at javax.faces.component.UIComponent.visitTree(UIComponent.java:1623) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final] at javax.faces.component.UIComponent.visitTree(UIComponent.java:1623) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final] at javax.faces.component.UIComponent.visitTree(UIComponent.java:1623) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final] at javax.faces.component.UIForm.visitTree(UIForm.java:371) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final] at javax.faces.component.UIComponent.visitTree(UIComponent.java:1623) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final] at javax.faces.component.UIComponent.visitTree(UIComponent.java:1623) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final] at org.icefaces.ace.component.fileentry.FileEntryPhaseListener.beforePhase(FileEntryPhaseListener.java:100) [icefaces-ace.jar:] at com.sun.faces.lifecycle.Phase.handleBeforePhase(Phase.java:228) [javax.faces.jar:2.1.4-FCS] at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:99) [javax.faces.jar:2.1.4-FCS] at com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:139) [javax.faces.jar:2.1.4-FCS] at javax.faces.webapp.FacesServlet.service(FacesServlet.java:594) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:329) [jbossweb-7.0.13.Final.jar:] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:248) [jbossweb-7.0.13.Final.jar:] at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:83) [jboss-seam.jar:2.3.0.Final] at org.jboss.seam.web.LoggingFilter.doFilter(LoggingFilter.java:60) [jboss-seam.jar:2.3.0.Final] at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69) [jboss-seam.jar:2.3.0.Final] at org.jboss.seam.web.ExceptionFilter.doFilter(ExceptionFilter.java:64) [jboss-seam.jar:2.3.0.Final] at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69) [jboss-seam.jar:2.3.0.Final] at org.jboss.seam.web.RedirectFilter.doFilter(RedirectFilter.java:45) [jboss-seam.jar:2.3.0.Final] at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69) [jboss-seam.jar:2.3.0.Final] at org.jboss.seam.web.IdentityFilter.doFilter(IdentityFilter.java:40) [jboss-seam.jar:2.3.0.Final] at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69) [jboss-seam.jar:2.3.0.Final] at org.jboss.seam.servlet.SeamFilter.doFilter(SeamFilter.java:158) [jboss-seam.jar:2.3.0.Final] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:280) [jbossweb-7.0.13.Final.jar:] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:248) [jbossweb-7.0.13.Final.jar:] at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:275) [jbossweb-7.0.13.Final.jar:] at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:161) [jbossweb-7.0.13.Final.jar:] at org.jboss.as.jpa.interceptor.WebNonTxEmCloserValve.invoke(WebNonTxEmCloserValve.java:50) [jboss-as-jpa-7.1.1.Final.jar:7.1.1.Final] at org.jboss.as.web.security.SecurityContextAssociationValve.invoke(SecurityContextAssociationValve.java:153) [jboss-as-web-7.1.1.Final.jar:7.1.1.Final] at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:155) [jbossweb-7.0.13.Final.jar:] at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102) [jbossweb-7.0.13.Final.jar:] at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109) [jbossweb-7.0.13.Final.jar:] at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:368) [jbossweb-7.0.13.Final.jar:] at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:877) [jbossweb-7.0.13.Final.jar:] at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:671) [jbossweb-7.0.13.Final.jar:] at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:930) [jbossweb-7.0.13.Final.jar:] at java.lang.Thread.run(Thread.java:722) [rt.jar:1.7.0_06]
At least this is something to look at. If I use the fileEntryListener like
fileEntryListener="#{uploadBean.fileUploadListener}"
the above exception is thrown, if I use:
fileEntryListener="#{uploadBean.fileUploadListener()}"
It complains that the method requires parameters and if I use it like:
fileEntryListener="#{uploadBean.fileUploadListener(null)}"
no exceptions are thrown, but due to the event being null, no files reach my UploadBean. Smells like some library issues, but at least something else to look at.
Upload bean
Not much happens here, it's simply:
@Stateful
@Name("uploadBean")
@Scope(ScopeType.SESSION)
@JndiName(value = "java:app/myApp.jar/UploadBean")
public class UploadBean implements IUploadBean
{
public void fileUploadListener(FileEntryEvent event)
{
System.out.println("listener called!");
}
}
Listener is declared in the bean's interface, too.
回答1:
First some technical background information: until the upcoming JSF 2.2, JSF doesn't natively support multipart/form-data
requests. So the component library offering the file upload component has to come up with a custom Filter
itself. This should properly parse multipart/form-data
requests and store all the necessary regular data in the HTTP request parameter map and the uploaded file(s) as request attribute(s). This way JSF can continue using request.getParameter()
for regular data the usual way and the component library itself can get the uploaded file(s) as request attribute.
In case of Seam's <s:fileUpload>
, you need the org.jboss.seam.web.MultipartFilter
to perform the multipart/form-data
parsing job. I have never used Seam (nor ICEfaces), but Google shows me that you basically need either this in webapp's web.xml
<filter>
<filter-name>Seam Multipart Filter</filter-name>
<filter-class>org.jboss.seam.web.MultipartFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>Seam Multipart Filter</filter-name>
<url-pattern>*.seam</url-pattern>
</filter-mapping>
or this in Seam components.xml
:
<web:multipart-filter url-pattern="*.seam" />
The ICEfaces component must have a similar Filter configured. The ICEfaces 3.x documentation is lacking (or my Google / icefaces.com search skills are bad), so I can't go in detail about this.
Important to keep in mind is that a HTTP request can be parsed only once (the client will send it only once, not multiple times) and thus you can't use the both multipart/form-data
parsers simultaneously on the same request. The one which kicks in after the first one would get an empty request body which isn't parseable into anything sensible. So if you're using a component which is using the latter filter, then you wouldn't get anything in the model. Make sure that you haven't by accident or by experiment configured both.
回答2:
I'm still in the process of investigating this, but it looks like
<web:multipart-filter disabled="true" url-pattern="bleh"/>
is not working as expected in my test case components.xml, but
<component class="org.jboss.seam.web.MultipartFilter">
<property name="disabled">true</property>
</component>
is working to disable the seam MultipartFilter.
回答3:
Maybe it might help. What i did was redeploy my ear project as war.
remove multipart filtering in web.xml and add this to components.xml :
<web:multipart-filter disabled="true"/>
sample of my component:
<ace:panel id="pnl">
<h:form>
<ice:panelGrid columns="2" bgcolor="#0063AA">
<ace:fileEntry id="file-entry" useOriginalFilename="true" immediate="true"
required="true" requiredMessage="The file is required to submit this form."
fileEntryListener="#{imageHome.sampleListener}"/>
<h:commandButton type="submit" value="Upload" />
</ice:panelGrid>
</h:form>
</ace:panel>
my FileEntryEvent has been called.
回答4:
I do not use Seam but I noticed the beans that I define as JSF beans are using different annotations than what you are using.
For the bean, i use @ManagedBean. For the scope, I use @SessionScoped.
来源:https://stackoverflow.com/questions/13008943/icefaces-seam-file-upload-component-not-uploading-files