ICEfaces
  1. ICEfaces
  2. ICE-7684

ace:fileEntry does not send or display file info after upload in Liferay portal

    Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: 3.0
    • Fix Version/s: 3.0
    • Labels:
      None
    • Environment:
      ICEfaces 3 ACE portal portlet
    • Assignee Priority:
      P1

      Description

      When running the File Entry component as a portlet, the file appears to get uploaded properly but the update the follows (presumably the information about the file name, type, size) throws JavaScript exceptions on the client:

      ace1:1Uncaught Error: NOT_FOUND_ERR: DOM Exception 8
      ace1:1Uncaught TypeError: Cannot set property '_updateElems' of undefined

      The problem occurs in with both Mojarra and MyFaces.

        Issue Links

          Activity

          Hide
          Deryk Sinotte added a comment - - edited

          I tested the ossrepo/icefaces2/tags/icefaces-core-2.1.0.BETA/samples/ace/showcase-portlet version of File Entry and it works so something between then and now has changed (screenshot provided).

          Show
          Deryk Sinotte added a comment - - edited I tested the ossrepo/icefaces2/tags/icefaces-core-2.1.0.BETA/samples/ace/showcase-portlet version of File Entry and it works so something between then and now has changed (screenshot provided).
          Hide
          Deryk Sinotte added a comment -

          During RESTORE_VIEW, restoreState() is called from our BridgeSetup$NonTransientJavascriptResourceOutput:

          public void restoreState(FacesContext context, Object state) {
          //call method from super-class to restore the component attributes first
          super.restoreState(context, state);
          Map attributes = getAttributes();
          String name = (String) attributes.get("name");
          String library = (String) attributes.get("library");
          String version = (String) attributes.get("version");

          ResourceHandler resourceHandler = context.getApplication().getResourceHandler();
          --> Resource r = resourceHandler.createResource(name, fixResourceParameter(library));
          String path = r.getRequestPath();
          if (version == null)

          { script = path; }

          else {
          if (path.contains("?"))

          { script = path + "&v=" + version; }

          else

          { script = path + "?v=" + version; }

          }
          }

          The line we are interested in is the createResource() call which is marked with a -->. This method was added shortly after our 2.1 Beta 2 release so the code that leads to the issue was not being executed previous to the change.

          The call to createResource() ends up going through all the ResourceHandlers until if finally hits org.portletfaces.bridge.application.ResourceHandlerImpl.createResource():

          public Resource createResource(String resourceName, String libraryName, String contentType) {
          FacesContext facesContext = FacesContext.getCurrentInstance();
          BridgeFactoryFinder bridgeFactoryFinder = BridgeFactoryFinder.getInstance();
          PortletContainerFactory portletContainerFactory = (PortletContainerFactory) bridgeFactoryFinder.getFactory(
          BridgeFactoryFinder.PORTLET_CONTAINER_FACTORY);
          BridgeContext bridgeContext = (BridgeContext) facesContext.getAttributes().get(Bridge.BRIDGE_CONTEXT_ATTRIBUTE);
          --> PortletContainer portletContainer = portletContainerFactory.getPortletContainer(bridgeContext);
          Resource wrappableResource = wrappedResourceHandler.createResource(resourceName, libraryName, contentType);

          if (wrappableResource == null)

          { return new MissingResourceImpl(wrappedResourceHandler, resourceName, libraryName, contentType); }

          else

          { return new ResourceImpl(wrappableResource, portletContainer); }

          }

          Part of the processing is to get an instance of the PortletContainer by using the factory. After it goes through the steps of determining a portlet container reference, the end of that method is:

          if (portletContainer != null)

          { portletContainer.setPortletRequest(portletRequest); portletContainer.setPortletResponse(portletResponse); }

          The process of setting the new portletRequest ends up replacing the current reference to our FileUploadPortletRequestWrapper So even though our wrapper is still "alive" and appears to have the correct data, it's no longer the request that is being used to retrieve all the relevant values - the request reference has been reset to point to the non-wrapped request.

          Had a quick talk with Mark and there are likely several different ways to fix this:

          1) During our wrapping and setting of the request, add some code to set it in two places to ensure it doesn't get swapped out. This would require some reflection to avoid having PortletFaces specific code in our File Entry logic.

          2) Talk with Neil and see if there's a way so ensure that when the request is set to our wrapper, it doesn't inadvertently get set back.

          3) Turn off the bit of our code in restoreState that calls createResource() which leads to the resetting of the request in PortletFaces.

          I believe 1 and/or 3 are probably the correct places to tackle this but due to the tight timeline for releasing, we've gone with 2 for the time being. The code is constrained to the FileEntryPhaseListener and only comes into affect when running with portlets. A new JIRA will be opened to look at applying a different strategy in a future release.

          Show
          Deryk Sinotte added a comment - During RESTORE_VIEW, restoreState() is called from our BridgeSetup$NonTransientJavascriptResourceOutput: public void restoreState(FacesContext context, Object state) { //call method from super-class to restore the component attributes first super.restoreState(context, state); Map attributes = getAttributes(); String name = (String) attributes.get("name"); String library = (String) attributes.get("library"); String version = (String) attributes.get("version"); ResourceHandler resourceHandler = context.getApplication().getResourceHandler(); --> Resource r = resourceHandler.createResource(name, fixResourceParameter(library)); String path = r.getRequestPath(); if (version == null) { script = path; } else { if (path.contains("?")) { script = path + "&v=" + version; } else { script = path + "?v=" + version; } } } The line we are interested in is the createResource() call which is marked with a -->. This method was added shortly after our 2.1 Beta 2 release so the code that leads to the issue was not being executed previous to the change. The call to createResource() ends up going through all the ResourceHandlers until if finally hits org.portletfaces.bridge.application.ResourceHandlerImpl.createResource(): public Resource createResource(String resourceName, String libraryName, String contentType) { FacesContext facesContext = FacesContext.getCurrentInstance(); BridgeFactoryFinder bridgeFactoryFinder = BridgeFactoryFinder.getInstance(); PortletContainerFactory portletContainerFactory = (PortletContainerFactory) bridgeFactoryFinder.getFactory( BridgeFactoryFinder.PORTLET_CONTAINER_FACTORY); BridgeContext bridgeContext = (BridgeContext) facesContext.getAttributes().get(Bridge.BRIDGE_CONTEXT_ATTRIBUTE); --> PortletContainer portletContainer = portletContainerFactory.getPortletContainer(bridgeContext); Resource wrappableResource = wrappedResourceHandler.createResource(resourceName, libraryName, contentType); if (wrappableResource == null) { return new MissingResourceImpl(wrappedResourceHandler, resourceName, libraryName, contentType); } else { return new ResourceImpl(wrappableResource, portletContainer); } } Part of the processing is to get an instance of the PortletContainer by using the factory. After it goes through the steps of determining a portlet container reference, the end of that method is: if (portletContainer != null) { portletContainer.setPortletRequest(portletRequest); portletContainer.setPortletResponse(portletResponse); } The process of setting the new portletRequest ends up replacing the current reference to our FileUploadPortletRequestWrapper So even though our wrapper is still "alive" and appears to have the correct data, it's no longer the request that is being used to retrieve all the relevant values - the request reference has been reset to point to the non-wrapped request. Had a quick talk with Mark and there are likely several different ways to fix this: 1) During our wrapping and setting of the request, add some code to set it in two places to ensure it doesn't get swapped out. This would require some reflection to avoid having PortletFaces specific code in our File Entry logic. 2) Talk with Neil and see if there's a way so ensure that when the request is set to our wrapper, it doesn't inadvertently get set back. 3) Turn off the bit of our code in restoreState that calls createResource() which leads to the resetting of the request in PortletFaces. I believe 1 and/or 3 are probably the correct places to tackle this but due to the tight timeline for releasing, we've gone with 2 for the time being. The code is constrained to the FileEntryPhaseListener and only comes into affect when running with portlets. A new JIRA will be opened to look at applying a different strategy in a future release.
          Hide
          Deryk Sinotte added a comment -

          I've checked in the change. Resolving as fixed.

          Show
          Deryk Sinotte added a comment - I've checked in the change. Resolving as fixed.
          Hide
          Mark Collette added a comment -

          Discussion emails:

          FileEntryPhaseListener.beforePhase() request: org.icefaces.ace.component.fileentry.FileUploadPortletRequestWrapper@4fcfb70d
          FileEntryPhaseListener.beforePhase() rpm: org.portletfaces.bridge.context.map.RequestParameterMapImpl@4dfadf6a
          FileUploadPortletRequestWrapper execute: A2497:example-form
          FileUploadPortletRequestWrapper render: @all
          RPM execute: null
          RPM render: null

          This shows up in all phases. Our wrapper is working properly, but the Portlets RequestParameterMapImpl, or something in-between the two, is what's losing the execute and render (and other) parameters.

          --------

          What I'm currently investigating is that the portlet bridge code that acts as a RequestParameterMap is using getPropert*() methods to populate itself, not only getParameter*() methods, which are the only ones we override in the FileUploadPortletRequestWrapper. And from stack traces I've gotten, it expects to get at the headers from there. It doesn't look like we fake out the headers at all, which was one of the things that the servlet wrapper does. And when JSF doesn't think that it's in a partial request, from the header, then it won't care about setting the partial execute and partial render fields.

          It might be worth investigating the differences between the portlet wrapping method used when the class was inner to FileEntryPhaseListener, versus now, to see how our handling of HTTP headers may have changed.

          -------

          I'm trying a convoluted system of svn updating grimlock to whichever versions, building and then copying those jars to my icefaces3 lib folder, and building portlets showcase there.

          On the other side of investigation, the RequestParameterMap that Portlets use is:

          http://svn.portletfaces.org/svn/portletfaces/bridge/portletfaces-bridge-impl/trunk/src/main/java/org/portletfaces/bridge/context/map/RequestParameterMapImpl.java

          which extends:

          http://svn.portletfaces.org/svn/portletfaces/bridge/portletfaces-bridge-impl/trunk/src/main/java/org/portletfaces/bridge/context/map/RequestParameterMap.java

          which extends:

          http://svn.portletfaces.org/svn/portletfaces/bridge/portletfaces-bridge-impl/trunk/src/main/java/org/portletfaces/bridge/util/AbstractPropertyMap.java

          and all that is created here:

          http://svn.portletfaces.org/svn/portletfaces/bridge/portletfaces-bridge-impl/trunk/src/main/java/org/portletfaces/bridge/context/map/RequestParameterMapFactory.java

          RequestParameterMapImpl seems to use the request object for the list of parameters/properties but uses the PortletContainer for the actual values:

          http://svn.portletfaces.org/svn/portletfaces/bridge/portletfaces-bridge-impl/trunk/src/main/java/org/portletfaces/bridge/container/PortletContainerImpl.java

          Notice how their own multi-part RPM doesn't defer to anyone but just feeds of its own map:

          http://svn.portletfaces.org/svn/portletfaces/bridge/portletfaces-bridge-impl/trunk/src/main/java/org/portletfaces/bridge/context/map/RequestParameterMapMultiPartImpl.java

          A bunch of stuff is setup in:

          http://svn.portletfaces.org/svn/portletfaces/bridge/portletfaces-bridge-impl/trunk/src/main/java/org/portletfaces/bridge/context/ExternalContextImpl.java

          Perhaps you can run things in a debugger, with the portlets bridge source, to see how RequestParameterMapImpl is getting the null values.

          The ExternalContext comments specifically mention ace:fileEntry, and some work-around they're doing to work with us. Maybe that area is somewhere we've changed.

          It might be easiest to override RequestParameterMapFactory and just return a different RPM that doesn't defer to the PortletContainer.

          Show
          Mark Collette added a comment - Discussion emails: FileEntryPhaseListener.beforePhase() request: org.icefaces.ace.component.fileentry.FileUploadPortletRequestWrapper@4fcfb70d FileEntryPhaseListener.beforePhase() rpm: org.portletfaces.bridge.context.map.RequestParameterMapImpl@4dfadf6a FileUploadPortletRequestWrapper execute: A2497:example-form FileUploadPortletRequestWrapper render: @all RPM execute: null RPM render: null This shows up in all phases. Our wrapper is working properly, but the Portlets RequestParameterMapImpl, or something in-between the two, is what's losing the execute and render (and other) parameters. -------- What I'm currently investigating is that the portlet bridge code that acts as a RequestParameterMap is using getPropert*() methods to populate itself, not only getParameter*() methods, which are the only ones we override in the FileUploadPortletRequestWrapper. And from stack traces I've gotten, it expects to get at the headers from there. It doesn't look like we fake out the headers at all, which was one of the things that the servlet wrapper does. And when JSF doesn't think that it's in a partial request, from the header, then it won't care about setting the partial execute and partial render fields. It might be worth investigating the differences between the portlet wrapping method used when the class was inner to FileEntryPhaseListener, versus now, to see how our handling of HTTP headers may have changed. ------- I'm trying a convoluted system of svn updating grimlock to whichever versions, building and then copying those jars to my icefaces3 lib folder, and building portlets showcase there. On the other side of investigation, the RequestParameterMap that Portlets use is: http://svn.portletfaces.org/svn/portletfaces/bridge/portletfaces-bridge-impl/trunk/src/main/java/org/portletfaces/bridge/context/map/RequestParameterMapImpl.java which extends: http://svn.portletfaces.org/svn/portletfaces/bridge/portletfaces-bridge-impl/trunk/src/main/java/org/portletfaces/bridge/context/map/RequestParameterMap.java which extends: http://svn.portletfaces.org/svn/portletfaces/bridge/portletfaces-bridge-impl/trunk/src/main/java/org/portletfaces/bridge/util/AbstractPropertyMap.java and all that is created here: http://svn.portletfaces.org/svn/portletfaces/bridge/portletfaces-bridge-impl/trunk/src/main/java/org/portletfaces/bridge/context/map/RequestParameterMapFactory.java RequestParameterMapImpl seems to use the request object for the list of parameters/properties but uses the PortletContainer for the actual values: http://svn.portletfaces.org/svn/portletfaces/bridge/portletfaces-bridge-impl/trunk/src/main/java/org/portletfaces/bridge/container/PortletContainerImpl.java Notice how their own multi-part RPM doesn't defer to anyone but just feeds of its own map: http://svn.portletfaces.org/svn/portletfaces/bridge/portletfaces-bridge-impl/trunk/src/main/java/org/portletfaces/bridge/context/map/RequestParameterMapMultiPartImpl.java A bunch of stuff is setup in: http://svn.portletfaces.org/svn/portletfaces/bridge/portletfaces-bridge-impl/trunk/src/main/java/org/portletfaces/bridge/context/ExternalContextImpl.java Perhaps you can run things in a debugger, with the portlets bridge source, to see how RequestParameterMapImpl is getting the null values. The ExternalContext comments specifically mention ace:fileEntry, and some work-around they're doing to work with us. Maybe that area is somewhere we've changed. It might be easiest to override RequestParameterMapFactory and just return a different RPM that doesn't defer to the PortletContainer.
          Hide
          Ted Goddard added a comment -

          createResource() is an expensive call, so factoring this out into a startup phase of BridgeSetup may be worthwhile in general.

          Show
          Ted Goddard added a comment - createResource() is an expensive call, so factoring this out into a startup phase of BridgeSetup may be worthwhile in general.

            People

            • Assignee:
              Mark Collette
              Reporter:
              Deryk Sinotte
            • Votes:
              0 Vote for this issue
              Watchers:
              0 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved: