Details
-
Type: Bug
-
Status: Closed
-
Priority: Major
-
Resolution: Won't Fix
-
Affects Version/s: EE-3.0.0.GA_P01, 3.2
-
Fix Version/s: EE-3.2.0.GA, 3.3
-
Component/s: ACE-Components
-
Labels:None
-
Environment:All
-
Assignee Priority:P1
-
Salesforce Case Reference:
Description
-
Hide
- Case11779Example.war
- 8.03 MB
- Arran Mccullough
-
- META-INF/MANIFEST.MF 0.1 kB
- META-INF/context.xml 0.1 kB
- WEB-INF/classes/com/.../example/Item.class 0.3 kB
- WEB-INF/classes/.../example/TestBean.class 5 kB
- WEB-INF/lib/commons-beanutils.jar 226 kB
- WEB-INF/lib/commons-collections.jar 558 kB
- WEB-INF/lib/commons-digester.jar 140 kB
- WEB-INF/lib/commons-logging.jar 52 kB
- WEB-INF/lib/icefaces-ee-ace.jar 1.50 MB
- WEB-INF/lib/icefaces-ee-compat.jar 2.58 MB
- WEB-INF/lib/icefaces-ee-ext.jar 56 kB
- WEB-INF/lib/icefaces-ee.jar 277 kB
- WEB-INF/lib/icepush.jar 190 kB
- WEB-INF/lib/javax.faces.jar 2.47 MB
- WEB-INF/web.xml 3 kB
- welcomeICEfaces.xhtml 4 kB
-
- Case11779Example.zip
- 21 kB
- Arran Mccullough
Activity
- All
- Comments
- History
- Activity
- Remote Attachments
- Subversion
When closing the tab while an upload was in progress, neither the fileEntryListener is invoked, nor is the @PreDestroy method in the window scoped bean. It looks like the lifecycle was not properly executing, and window scope was not getting resolved. Even after tweaking the file upload handling code, the fact remains that the multi-part data is truncated, and the information to identify the window and view can still be missing, and cause things to not properly work, even if they're forced to limp along.
There may be something that might be able to be done in the browser / bridge side, to still notify the server of the window / tab close, but nothing can be done to fix the upload's broken lifecycle.
And I'm not really certain that session folder cleanup should happen in a window destroy anyway, since that would make more sense in a session cleanup callback.
One of two exceptions were thrown in all my tests. This is the first. If this one got thrown then nothing later happened, no fileEntryListener and no @PreDestroy. I was able to add more catch statements and remove a FacesMessage addition to get it past this point, but then it would skip execute from having incomplete info for the RequestParameterMap.
org.icefaces.ace.component.fileentry.FileEntryResourceHandler uploadFile
SEVERE: Problem processing uploaded file
org.icefaces.apache.commons.fileupload.MultipartStream$MalformedStreamException: Stream ended unexpectedly
at org.icefaces.apache.commons.fileupload.MultipartStream$ItemInputStream.makeAvailable(MultipartStream.java:983)
at org.icefaces.apache.commons.fileupload.MultipartStream$ItemInputStream.read(MultipartStream.java:887)
at java.io.InputStream.read(InputStream.java:82)
at org.icefaces.ace.component.fileentry.FileEntryResourceHandler.uploadFile(FileEntryResourceHandler.java:316)
at org.icefaces.ace.component.fileentry.FileEntryResourceHandler.isResourceRequest(FileEntryResourceHandler.java:116)
at javax.faces.application.ResourceHandlerWrapper.isResourceRequest(ResourceHandlerWrapper.java:68)
at javax.faces.application.ResourceHandlerWrapper.isResourceRequest(ResourceHandlerWrapper.java:68)
at org.icefaces.impl.push.servlet.ICEpushResourceHandler$ICEpushResourceHandlerImpl.isResourceRequest(ICEpushResourceHandler.java:263)
at org.icefaces.impl.push.servlet.ICEpushResourceHandler.isResourceRequest(ICEpushResourceHandler.java:133)
at org.icefaces.impl.push.DynamicResourceDispatcher.isResourceRequest(DynamicResourceDispatcher.java:69)
at javax.faces.application.ResourceHandlerWrapper.isResourceRequest(ResourceHandlerWrapper.java:68)
at org.icefaces.impl.application.WindowScopeManager.isSessionAwareResourceRequest(WindowScopeManager.java:80)
at org.icefaces.impl.application.SessionAwareResourceHandlerWrapper.isResourceRequest(SessionAwareResourceHandlerWrapper.java:32)
at javax.faces.application.ResourceHandlerWrapper.isResourceRequest(ResourceHandlerWrapper.java:68)
at org.icefaces.impl.application.SessionTimeoutMonitor.isSessionAwareResourceRequest(SessionTimeoutMonitor.java:42)
at org.icefaces.impl.application.SessionAwareResourceHandlerWrapper.isResourceRequest(SessionAwareResourceHandlerWrapper.java:32)
at org.icefaces.impl.util.CharacterEncodingHandler.isResourceRequest(CharacterEncodingHandler.java:73)
at javax.faces.application.ResourceHandlerWrapper.isResourceRequest(ResourceHandlerWrapper.java:68)
at javax.faces.application.ResourceHandlerWrapper.isResourceRequest(ResourceHandlerWrapper.java:68)
at javax.faces.application.ResourceHandlerWrapper.isResourceRequest(ResourceHandlerWrapper.java:68)
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:188)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:224)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:169)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:168)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:98)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:928)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:987)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:539)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:298)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:680)
And with this exception, it seems that validation failed the file before the browser would cut off the file upload, so the fileEntryListener would get called, but window scope couldn't be resolved, so the fileEntryListener would be called on one instance of the bean which would not be the same instance that @PreDestroy could get called on, and everything would exception in render anyways.
org.apache.myfaces.el.unified.resolver.ManagedBeanResolver getValue
WARNING: Custom scope '#
org.apache.myfaces.el.unified.resolver.ManagedBeanResolver putInScope
WARNING: Custom scope '#{window}
' evaluated to null. Cannot store managed bean 'navigationModel' in custom scope.
org.apache.myfaces.el.unified.resolver.ManagedBeanResolver getValue
WARNING: Custom scope '#
org.apache.myfaces.el.unified.resolver.ManagedBeanResolver putInScope
WARNING: Custom scope '#{window}
' evaluated to null. Cannot store managed bean 'fileEntry' in custom scope.
org.apache.myfaces.el.unified.resolver.ManagedBeanResolver getValue
WARNING: Custom scope '#
org.apache.myfaces.el.unified.resolver.ManagedBeanResolver putInScope
WARNING: Custom scope '#{window}
' evaluated to null. Cannot store managed bean 'navigationModel' in custom scope.
org.apache.myfaces.el.unified.resolver.ManagedBeanResolver getValue
WARNING: Custom scope '#
org.apache.myfaces.el.unified.resolver.ManagedBeanResolver putInScope
WARNING: Custom scope '#{window}
' evaluated to null. Cannot store managed bean 'navigationModel' in custom scope.
org.apache.myfaces.el.unified.resolver.ManagedBeanResolver getValue
WARNING: Custom scope '#
org.apache.myfaces.el.unified.resolver.ManagedBeanResolver putInScope
WARNING: Custom scope '#{window}
' evaluated to null. Cannot store managed bean 'fileEntry' in custom scope.
FileEntryBean.sampleListener() [File Name: Anche.Se.e?.Amore.Non.Si.Vede.2011.iTALiAN.MD.TELESYNC-P76 [IDN_CREW].avi, File was not saved because: Submitted file is too large.]
org.apache.myfaces.el.unified.resolver.ManagedBeanResolver getValue
WARNING: Custom scope '#
org.apache.myfaces.el.unified.resolver.ManagedBeanResolver putInScope
WARNING: Custom scope '#{window}
' evaluated to null. Cannot store managed bean 'navigationModel' in custom scope.
org.apache.myfaces.el.unified.resolver.ManagedBeanResolver getValue
WARNING: Custom scope '#
org.apache.myfaces.el.unified.resolver.ManagedBeanResolver putInScope
WARNING: Custom scope '#{window}
' evaluated to null. Cannot store managed bean 'navigationModel' in custom scope.
org.apache.myfaces.el.unified.resolver.ManagedBeanResolver getValue
WARNING: Custom scope '#
org.apache.myfaces.el.unified.resolver.ManagedBeanResolver putInScope
WARNING: Custom scope '#{window}
' evaluated to null. Cannot store managed bean 'navigationModel' in custom scope.
org.icefaces.impl.event.BridgeSetup getBodyResources
WARNING: Unable to find WindowScope for view /showcase.xhtml
org.apache.myfaces.el.unified.resolver.ManagedBeanResolver getValue
WARNING: Custom scope '#
org.apache.myfaces.el.unified.resolver.ManagedBeanResolver putInScope
WARNING: Custom scope '#{window}
' evaluated to null. Cannot store managed bean 'navigationModel' in custom scope.
org.apache.myfaces.el.unified.resolver.ManagedBeanResolver getValue
WARNING: Custom scope '#
org.apache.myfaces.el.unified.resolver.ManagedBeanResolver putInScope
WARNING: Custom scope '#{window}
' evaluated to null. Cannot store managed bean 'navigationModel' in custom scope.
org.apache.myfaces.el.unified.resolver.ManagedBeanResolver getValue
WARNING: Custom scope '#
org.apache.myfaces.el.unified.resolver.ManagedBeanResolver putInScope
WARNING: Custom scope '#{window}
' evaluated to null. Cannot store managed bean 'navigationModel' in custom scope.
java.lang.NullPointerException
at org.icefaces.impl.event.WindowAndViewIDSetup$1.encode(WindowAndViewIDSetup.java:65)
at org.icefaces.impl.event.UIOutputWriter.encodeBegin(UIOutputWriter.java:27)
at javax.faces.component.UIComponentBase.encodeAll(UIComponentBase.java:515)
at javax.faces.component.UIComponentBase.encodeAll(UIComponentBase.java:539)
at org.apache.myfaces.shared.renderkit.RendererUtils.renderChildren(RendererUtils.java:693)
at org.apache.myfaces.shared.renderkit.html.HtmlGroupRendererBase.encodeEnd(HtmlGroupRendererBase.java:115)
at javax.faces.component.UIComponentBase.encodeEnd(UIComponentBase.java:663)
at javax.faces.component.UIComponentBase.encodeAll(UIComponentBase.java:543)
at org.apache.myfaces.shared.renderkit.RendererUtils.renderChildren(RendererUtils.java:693)
at org.apache.myfaces.shared.renderkit.html.HtmlGroupRendererBase.encodeEnd(HtmlGroupRendererBase.java:115)
at javax.faces.component.UIComponentBase.encodeEnd(UIComponentBase.java:663)
at javax.faces.component.UIComponentBase.encodeAll(UIComponentBase.java:543)
at org.apache.myfaces.shared.renderkit.RendererUtils.renderChildren(RendererUtils.java:693)
at org.apache.myfaces.shared.renderkit.html.HtmlGroupRendererBase.encodeEnd(HtmlGroupRendererBase.java:115)
at javax.faces.component.UIComponentBase.encodeEnd(UIComponentBase.java:663)
at javax.faces.component.UIComponentBase.encodeAll(UIComponentBase.java:543)
at org.apache.myfaces.shared.renderkit.RendererUtils.renderChildren(RendererUtils.java:693)
at org.apache.myfaces.shared.renderkit.html.HtmlGroupRendererBase.encodeEnd(HtmlGroupRendererBase.java:115)
at javax.faces.component.UIComponentBase.encodeEnd(UIComponentBase.java:663)
at javax.faces.component.UIComponentBase.encodeAll(UIComponentBase.java:543)
at javax.faces.component.UIComponentBase.encodeAll(UIComponentBase.java:539)
at org.icefaces.impl.context.DOMPartialViewContext.processPartial(DOMPartialViewContext.java:142)
at javax.faces.component.UIViewRoot.encodeChildren(UIViewRoot.java:408)
at javax.faces.component.UIComponentBase.encodeAll(UIComponentBase.java:530)
at org.apache.myfaces.view.facelets.FaceletViewDeclarationLanguage.renderView(FaceletViewDeclarationLanguage.java:1981)
at org.apache.myfaces.application.ViewHandlerImpl.renderView(ViewHandlerImpl.java:285)
at org.apache.myfaces.lifecycle.RenderResponseExecutor.execute(RenderResponseExecutor.java:116)
at org.apache.myfaces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:241)
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:199)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:224)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:169)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:168)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:98)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:928)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:987)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:539)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:298)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:680)
org.icefaces.impl.application.ExtendedExceptionHandler handle
WARNING: queued exception
java.lang.NullPointerException
at org.icefaces.impl.event.WindowAndViewIDSetup$1.encode(WindowAndViewIDSetup.java:65)
at org.icefaces.impl.event.UIOutputWriter.encodeBegin(UIOutputWriter.java:27)
at javax.faces.component.UIComponentBase.encodeAll(UIComponentBase.java:515)
at javax.faces.component.UIComponentBase.encodeAll(UIComponentBase.java:539)
at org.apache.myfaces.shared.renderkit.RendererUtils.renderChildren(RendererUtils.java:693)
at org.apache.myfaces.shared.renderkit.html.HtmlGroupRendererBase.encodeEnd(HtmlGroupRendererBase.java:115)
at javax.faces.component.UIComponentBase.encodeEnd(UIComponentBase.java:663)
at javax.faces.component.UIComponentBase.encodeAll(UIComponentBase.java:543)
at org.apache.myfaces.shared.renderkit.RendererUtils.renderChildren(RendererUtils.java:693)
at org.apache.myfaces.shared.renderkit.html.HtmlGroupRendererBase.encodeEnd(HtmlGroupRendererBase.java:115)
at javax.faces.component.UIComponentBase.encodeEnd(UIComponentBase.java:663)
at javax.faces.component.UIComponentBase.encodeAll(UIComponentBase.java:543)
at org.apache.myfaces.shared.renderkit.RendererUtils.renderChildren(RendererUtils.java:693)
at org.apache.myfaces.shared.renderkit.html.HtmlGroupRendererBase.encodeEnd(HtmlGroupRendererBase.java:115)
at javax.faces.component.UIComponentBase.encodeEnd(UIComponentBase.java:663)
at javax.faces.component.UIComponentBase.encodeAll(UIComponentBase.java:543)
at org.apache.myfaces.shared.renderkit.RendererUtils.renderChildren(RendererUtils.java:693)
at org.apache.myfaces.shared.renderkit.html.HtmlGroupRendererBase.encodeEnd(HtmlGroupRendererBase.java:115)
at javax.faces.component.UIComponentBase.encodeEnd(UIComponentBase.java:663)
at javax.faces.component.UIComponentBase.encodeAll(UIComponentBase.java:543)
at javax.faces.component.UIComponentBase.encodeAll(UIComponentBase.java:539)
at org.icefaces.impl.context.DOMPartialViewContext.processPartial(DOMPartialViewContext.java:142)
at javax.faces.component.UIViewRoot.encodeChildren(UIViewRoot.java:408)
at javax.faces.component.UIComponentBase.encodeAll(UIComponentBase.java:530)
at org.apache.myfaces.view.facelets.FaceletViewDeclarationLanguage.renderView(FaceletViewDeclarationLanguage.java:1981)
at org.apache.myfaces.application.ViewHandlerImpl.renderView(ViewHandlerImpl.java:285)
at org.apache.myfaces.lifecycle.RenderResponseExecutor.execute(RenderResponseExecutor.java:116)
at org.apache.myfaces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:241)
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:199)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:224)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:169)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:168)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:98)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:928)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:987)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:539)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:298)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:680)
Here is a slightly modified version of the code that fileEntry uses to create the session folder:
// absolutePath takes precedence over relativePath
protected static String calculateFolder(FacesContext facesContext,
String absolutePath, String relativePath, boolean useSessionSubdir) {
String folder = null;
if (absolutePath != null && absolutePath.length() > 0)
else
{ folder = CoreUtils.getRealPath(facesContext, relativePath); }if (folder == null)
{ folder = ""; } if (useSessionSubdir) {
String sessionId = CoreUtils.getSessionId(facesContext);
if (sessionId != null && sessionId.length() > 0) {
String FILE_SEPARATOR = System.getProperty("file.separator");
if (folder != null && folder.trim().length() > 0)
folder = folder + sessionId;
}
}
return folder;
}
Using a session scoped bean with a void no-arg method having a @PreDestroy annotation, call this calculateFolder method, passing in the values that you've given for your fileEntry component(s) for their absolutePath, relativePath and useSessionSubdir properties. This will allow you to get the folder path, which you can then delete, without first needing a fileEntryListener callback to give you that path, that way if an upload is aborted, and files and folders linger, then they can be cleaned up when the session is being cleaned up.
In theory we could add logic to the file saving / writing process to detect when a session folder was created and no file was successfully saved, and then delete the created folder, and only do that for malformed streams, so we don't affect any pre-existing app code that might rely on session folders existing when it's just a validation failure. But there's still the cases where the malformed stream is detected past the file upload, when reading the other form parameters after or between files. So the single place that would catch everything is still the session bean's @PreDestroy method. And it would be easier for applications to then choose what they want to do with the session folder if it contains previously successfully uploaded files.
Attached test case that shows this issue. The test case has code that when the window is closed it will cleanup the uploaded files and the session directory.
If an upload is started and the window/tab is closed the code to clean up the files can't run correctly as it needs a reference to an uploaded file.