Details
-
Type: Bug
-
Status: Closed
-
Priority: Major
-
Resolution: Fixed
-
Affects Version/s: 1.8.2-EE-GA_P02
-
Fix Version/s: EE-1.8.2.GA_P04
-
Component/s: Framework
-
Labels:None
-
Environment:Liferay 5.2.3 + Tomcat 6
-
Affects:Documentation (User Guide, Ref. Guide, etc.), Compatibility/Configuration
-
Workaround Exists:Yes
-
Workaround Description:HideUse namespace stored as request attribute:
public String getNamespace() {
Map requestMap = FacesContext.getCurrentInstance().getExternalContext().getRequestMap();
Object namespace = requestMap.get("com.icesoft.faces.NAMESPACE");
if( namespace != null ){
return namespace.toString();
}
return null;
}
ShowUse namespace stored as request attribute: public String getNamespace() { Map requestMap = FacesContext.getCurrentInstance().getExternalContext().getRequestMap(); Object namespace = requestMap.get("com.icesoft.faces.NAMESPACE"); if( namespace != null ){ return namespace.toString(); } return null; }
Description
<ice:outputLabel value="#{facesContext.externalContext.response.namespace}" />
In a partial update (button click or hitting enter in an inputText) in P02, the PortletResponse acquired using the property response of the externalContext is null. However in P01, the PortletResponse is correctly set.
Test case is intended for deployment on Liferay 5.2.3 + Tomcat 6 and can be found under the "Test" portlet category.
-
Hide
- sc10164.war
- 9.08 MB
- Tyler Johnson
-
- META-INF/MANIFEST.MF 0.0 kB
- WEB-INF/classes/it/.../pagecode/Test.java 0.3 kB
- WEB-INF/lib/commons-digester.jar 140 kB
- WEB-INF/lib/icefaces-comps.jar 1.75 MB
- WEB-INF/classes/it/.../pagecode/Test.class 0.4 kB
- WEB-INF/lib/icefaces-composite-comps.jar 4.17 MB
- common/ErrorView.jspx 0.8 kB
- common/.svn/.../ErrorView.jspx.svn-base 0.8 kB
- WEB-INF/lib/jsf-impl.jar 837 kB
- common/.svn/all-wcprops 0.3 kB
- WEB-INF/lib/icefaces.jar 1.21 MB
- WEB-INF/web.xml 5 kB
- WEB-INF/lib/commons-collections.jar 558 kB
- .DS_Store 6 kB
- WEB-INF/lib/backport-util-concurrent.jar 319 kB
- portlet/test/Test.jspx 1 kB
- common/.svn/entries 0.4 kB
- WEB-INF/liferay-display.xml 0.2 kB
- WEB-INF/lib/commons-beanutils.jar 226 kB
- WEB-INF/faces-config.xml 1 kB
- WEB-INF/portlet.xml 1 kB
- WEB-INF/lib/commons-fileupload.jar 56 kB
- index.jsp 0.1 kB
- WEB-INF/lib/jsf-api.jar 355 kB
- portlet/.DS_Store 6 kB
- WEB-INF/lib/commons-logging.jar 52 kB
- WEB-INF/lib/icefaces-facelets.jar 596 kB
- WEB-INF/liferay-portlet.xml 0.5 kB
Activity
- All
- Comments
- History
- Activity
- Remote Attachments
- Subversion
As part of the work for case http://jira.icesoft.org/browse/ICE-6197, we ported over some portlet optimizations that fixed memory leaks. One of these optimizations was to null out the reference to the PortletResponse when the PortletExternalContext was released.
The upside was that it got rid of some serious leaks. The side-effect was that, with extended request scope, we no longer had a PortletResponse to query. Which brings us to this JIRA.
Because of extended request scope and the way of handling portlet requests in ICEfaces 1.x, all the subsequent Ajax requests from the portlet no longer have a valid response object. In other words the following returns a valid PortletResponse only during the initial render and returns null for subsequent Ajax calls:
Object obj = FacesContext.getCurrentInstance().getExternalContext().getResponse();
For the most part this isn't a massive problem as we don't recommend working directly with the portlet response anyway, instead choosing to use ExternalContext API only. Of course the best laid plans....
This change to release the response reference was made between P01 and P02 and caused a regression with the customer's app. We provided some workaround code that helped out in the interim. To "really" fix this properly is beyond the scope of work for the product at this point. So instead, when someone calls ExternalContext.getResponse():
public Object getResponse() {
if(response != null)
//ICE-6929: As part of the fix for ICE-6197, we released the response reference in order to
// avoid memory leaks but that means that ExternalContext.getResponse() will return
// null and can't be used. Here we provide a proxy that is mostly unimplemented except
// specific methods required to help with bugs.
boolean useProxyPortletResponse = configuration.getAttributeAsBoolean("useProxyPortletResponse", true);
if(useProxyPortletResponse)
return null;
}
If the response is no longer valid (for all those Ajax requests in extended request scope) we return a ProxyPortletResponse instance. This is kind of similar to the technique we use newer versions of ICEfaces. For almost all the methods in the proxy, we return an UnsupportedOperationException:
public PortletURL createActionURL()
{ log.error(UNSUPPORTED_MESSAGE); throw new UnsupportedOperationException(); }For the getNamespace() method, we use the workaround code as noted before in the description:
public String getNamespace() {
Map requestMap = FacesContext.getCurrentInstance().getExternalContext().getRequestMap();
Object namespace = requestMap.get("com.icesoft.faces.NAMESPACE");
if (namespace != null)
return null;
}
Note that this new proxy behaviour is active by default but that there is a context parameter to turn it off:
<context-param>
<param-name>com.icesoft.faces.useProxyPortletResponse</param-name>
<param-value>false</param-value>
</context-param>
This is provided in case application developer's code relies on checking for the response being null:
if( response == null)...
which could have undesirable side-effects. It's possible that more of the proxy methods could be implemented as required in the future.
Committed a fix that allows a proxy response to be created once the original response has been released. This is constrained to PortletExternalContext only and the proxy is mostly unimplemented except for getNamespace(). I tested against the test case in this JIRA as well as the Component Showcase and didn't see any side-effects.
I also tested the context parameter to ensure that setting it to false it has the desired effect of not creating/using the proxy. While doing that I made a slight adjustment to the name of the parameter to make is consistent with our other portlet-specific context parameters:
<context-param>
<param-name>com.icesoft.faces.portlet.useProxyPortletResponse</param-name>
<param-value>false</param-value>
</context-param>
I have confirmed the regression is between P01 and P02 and was introduced as part of this change:
http://jira.icefaces.org/browse/ICE-6197
This JIRA was to merge in substantial patches we'd made against P01 for other customers. The specific change in this case that is causing this problem relates to the RenderResponse reference. In the PortletExternalContext (our version of the JSF ExternalContext for portlet environments) was maintaining a reference to the original RenderResponse between Ajax requests. This was causing a significant memory leak during load testing and could only be solved by releasing the reference to the RenderResponse when the FacesContext.release() method was called. The side-effect is the regression where calling PortletExternalContext.getResponse() now returns null after the initial page request.
There is a workaround as we do store the namespace as a request attribute and this can be retrieved. Unfortunately, the strategy of using more direct EL syntax does not work:
<ice:outputText value="Namespace: #
{facesContext.externalContext.response.namespace}"/>
But it is possible to use some simple backing bean code and modify the EL to something like the following. Assume a managed bean called "Simple" that has the following method:
public String getNamespace() {
{ return namespace.toString(); }Map requestMap = FacesContext.getCurrentInstance().getExternalContext().getRequestMap();
Object namespace = requestMap.get("com.icesoft.faces.NAMESPACE");
if( namespace != null )
return null;
}
then the following EL can be used to get the namespace which will survive multiple Ajax requests:
<ice:outputText value="Namespace alternative: #
{simple.namespace}"/>
I've verified that this works against the test case. However, the response not being available may be considered a more serious issue and to fix it will require some effort in order not to re-introduce the memory issues that were originally addressed.