Reputation: 1332
Running on JSF 2.0.9, Weblogic 10.3.4. We're now running JSF in our production environment but have encountered some issues with Session Replication and fail over. We are using viewscope for our beans and I have ensured they are Serializable/transient and that the transient variables are effectively stateless. However session fail over is not working. I have done extensive testing and managed to get it working by setting the following params in web.xml
<context-param>
<param-name>javax.faces.STATE_SAVING_METHOD</param-name>
<param-value>client</param-value>
</context-param>
<context-param>
<param-name>javax.faces.PARTIAL_STATE_SAVING</param-name>
<param-value>false</param-value>
</context-param>
If I set STATE_SAVING_METHOD
to server
I get a viewexpired exception on failover. If I set to client
with PARTIAL_STATE_SAVING
to true
I get the following error:
java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
at java.util.ArrayList.RangeCheck(ArrayList.java:547)
at java.util.ArrayList.get(ArrayList.java:322)
at javax.faces.component.AttachedObjectListHolder.restoreState(AttachedObjectListHolder.java:165)
at javax.faces.component.UIComponentBase.restoreState(UIComponentBase.java:1433)
at com.sun.faces.application.view.StateManagementStrategyImpl$1.visit(StateManagementStrategyImpl.java:265)
at com.sun.faces.component.visit.FullVisitContext.invokeVisitCallback(FullVisitContext.java:151)
at javax.faces.component.UIComponent.visitTree(UIComponent.java:1507)
at javax.faces.component.UIComponent.visitTree(UIComponent.java:1521)
at com.sun.faces.component.visit.VisitUtils.doFullNonIteratingVisit(VisitUtils.java:75)
at com.sun.faces.application.view.StateManagementStrategyImpl.restoreView(StateManagementStrategyImpl.java:282)
at com.sun.faces.application.StateManagerImpl.restoreView(StateManagerImpl.java:181)
at com.sun.faces.application.view.ViewHandlingStrategy.restoreView(ViewHandlingStrategy.java:123)
at com.sun.faces.application.view.FaceletViewHandlingStrategy.restoreView(FaceletViewHandlingStrategy.java:448)
at com.sun.faces.application.view.MultiViewHandler.restoreView(MultiViewHandler.java:148)
at com.sun.faces.lifecycle.RestoreViewPhase.execute(RestoreViewPhase.java:187)
at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
at com.sun.faces.lifecycle.RestoreViewPhase.doPhase(RestoreViewPhase.java:111)
at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118)
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:508)
at weblogic.servlet.internal.StubSecurityHelper$ServletServiceAction.run(StubSecurityHelper.java:227)
at weblogic.servlet.internal.StubSecurityHelper.invokeServlet(StubSecurityHelper.java:125)
at weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:301)
at weblogic.servlet.internal.TailFilter.doFilter(TailFilter.java:27)
at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:57)
at weblogic.servlet.internal.RequestEventsFilter.doFilter(RequestEventsFilter.java:27)
at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:57)
at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.wrapRun(WebAppServletContext.java:3730)
at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.run(WebAppServletContext.java:3696)
at weblogic.security.acl.internal.AuthenticatedSubject.doAs(AuthenticatedSubject.java:321)
at weblogic.security.service.SecurityManager.runAs(SecurityManager.java:120)
at weblogic.servlet.internal.WebAppServletContext.securedExecute(WebAppServletContext.java:2273)
at weblogic.servlet.internal.WebAppServletContext.execute(WebAppServletContext.java:2179)
at weblogic.servlet.internal.ServletRequestImpl.run(ServletRequestImpl.java:1490)
at weblogic.work.ExecuteThread.execute(ExecuteThread.java:256)
at weblogic.work.ExecuteThread.run(ExecuteThread.java:221)
So my questions are these:
STATE_SAVING_METHOD
- client
& PARTIAL_STATE_SAVING
- false
the only way I'm going to get failover to work? Thanks in advance.
Upvotes: 13
Views: 10916
Reputation: 1332
I finally got this working but not without some extra bits and bobs. Firstly I added the following to the web.xml (yes agressive is spelled incorrectly):
<context-param>
<param-name>com.sun.faces.enableAgressiveSessionDirtying</param-name>
<param-value>true</param-value>
</context-param>
The client saving is now server and partial-state saving is false still (true simply doesn't work)
Secondly after implementing a HttpSessionAttributeListener I discovered that the com.sun.faces.renderkit.ServerSideStateHelper.LogicalViewMap
which holds the state in the session only got added once and never removed/added/replaced again. Therefore although it was being updated in the local session these changes were never replicated to a second jvm. Weblogic docs state that setAttribute must be called on session attributes for replication to work. To fix this I created a phase listener as follows:
public class ViewPhaseListener implements PhaseListener {
public void afterPhase(PhaseEvent phaseEvent)
{
}
public void beforePhase(PhaseEvent phaseEvent)
{
HttpServletRequest request = ((HttpServletRequest) phaseEvent.getFacesContext().getExternalContext().getRequest());
HttpSession session = request.getSession();
session.setAttribute("com.sun.faces.renderkit.ServerSideStateHelper.LogicalViewMap", session.getAttribute("com.sun.faces.renderkit.ServerSideStateHelper.LogicalViewMap"));
}
public PhaseId getPhaseId()
{
return PhaseId.RENDER_RESPONSE;
//To change body of implemented methods use File | Settings | File Templates.
}
}
This simply replaces the attribute after each request and ensures it replicates. As an additional point I am limiting the data stored in the views with the following:
<context-param>
<param-name>com.sun.faces.numberOfViewsInSession</param-name>
<param-value>3</param-value>
</context-param>
<context-param>
<param-name>com.sun.faces.numberOfLogicalViews</param-name>
<param-value>1</param-value>
</context-param>
Hope this helps anyone with the same issues.
Upvotes: 14
Reputation: 597
The session replication should be handled by the load balancer as the JSF application is only aware of the context on the node that it is deployed to. As such, it shouldn't matter if you set the STATE_SAVING_METHOD to client or server.
It sounds to me like you have an incorrect load balancer configuration. If you're using Apache HTTP Server as your proxy please see the following link for more information on session stickyness:
http://httpd.apache.org/docs/2.2/mod/mod_proxy_balancer.html
I would recommend setting ProxySet stickysession=ROUTEID and see if that resolves the issue.
Upvotes: 0