dssof
dssof

Reputation: 305

Error when restoring view after rolling update

I have implemented rolling updates with JSF 2.3. I'm using Redis (with the Redisson library) to store HTTP sessions, HAProxy as a load balancer with sticky sessions. Additionally, I am using Tomcat 8.5. When I deploy a new version, I take down the previous version of the app, and traffic is redirected to the new Tomcat with the updated app.

The issue arises when I need to update an XHTML file, for example, to add a new column to a data table. In this case, when the session is transferred from one server to another, I encounter this error:

org.primefaces.application.exceptionhandler.PrimeExceptionHandler.logException 2
    java.lang.ArrayIndexOutOfBoundsException: 2
        at javax.faces.component.UIComponentBase.restoreState(UIComponentBase.java:1245)
        at com.sun.faces.application.view.FaceletPartialStateManagementStrategy$2.visit(FaceletPartialStateManagementStrategy.java:376)
        at com.sun.faces.component.visit.FullVisitContext.invokeVisitCallback(FullVisitContext.java:127)
        at javax.faces.component.UIComponent.visitTree(UIComponent.java:1457)
        at javax.faces.component.UIComponent.visitTree(UIComponent.java:1469)
        at javax.faces.component.UIComponent.visitTree(UIComponent.java:1469)
        at javax.faces.component.UIComponent.visitTree(UIComponent.java:1469)
        at javax.faces.component.UIComponent.visitTree(UIComponent.java:1469)
        at javax.faces.component.UIComponent.visitTree(UIComponent.java:1469)
        at javax.faces.component.UIComponent.visitTree(UIComponent.java:1469)
        at javax.faces.component.UIComponent.visitTree(UIComponent.java:1469)
        at javax.faces.component.UIComponent.visitTree(UIComponent.java:1469)
        at com.sun.faces.application.view.FaceletPartialStateManagementStrategy.restoreView(FaceletPartialStateManagementStrategy.java:362)
        at com.sun.faces.application.StateManagerImpl.restoreView(StateManagerImpl.java:113)
        at com.sun.faces.application.view.ViewHandlingStrategy.restoreView(ViewHandlingStrategy.java:99)
        at com.sun.faces.application.view.FaceletViewHandlingStrategy.restoreView(FaceletViewHandlingStrategy.java:272)
        at com.sun.faces.application.view.MultiViewHandler.restoreView(MultiViewHandler.java:133)
        at javax.faces.application.ViewHandlerWrapper.restoreView(ViewHandlerWrapper.java:101)
        at javax.faces.application.ViewHandlerWrapper.restoreView(ViewHandlerWrapper.java:101)
        at org.omnifaces.viewhandler.OmniViewHandler.restoreView(OmniViewHandler.java:117)
        at com.sun.faces.lifecycle.RestoreViewPhase.execute(RestoreViewPhase.java:181)
        at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:76)
        at com.sun.faces.lifecycle.RestoreViewPhase.doPhase(RestoreViewPhase.java:110)
        at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:177)
        at javax.faces.webapp.FacesServlet.executeLifecyle(FacesServlet.java:707)
        at javax.faces.webapp.FacesServlet.service(FacesServlet.java:451)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at jsf.filters.CacheFilter.doFilter(CacheFilter.java:27)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at com.filters.SecurityFilter.posResult(SecurityFilter.java:104)
        at com.filters.SecurityFilter.doFilter(SecurityFilter.java:86)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.primefaces.webapp.filter.FileUploadFilter.doFilter(FileUploadFilter.java:89)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.omnifaces.filter.GzipResponseFilter.doFilter(GzipResponseFilter.java:183)
        at org.omnifaces.filter.HttpFilter.doFilter(HttpFilter.java:108)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:196)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)
        at org.redisson.tomcat.UpdateValve.invoke(UpdateValve.java:62)
        at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135)
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81)
        at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:698)
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:364)
        at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:624)
        at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
        at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:831)
        at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1650)
        at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
        at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)
        at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
        at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
        at java.lang.Thread.run(Thread.java:750)

I have already tried the solution suggested in this answer (JSF Session Fail over and Partial State Saving), but I had no luck because when I change to PARTIAL_STATE_SAVING=false, I get the following error when restoring (on every page):

06-Oct-2023 16:25:25.953 SEVERE [http-nio-9090-exec-1] com.sun.faces.util.Util.checkIdUniqueness JSF1007: Duplicate component ID j_idt2 found in view.
06-Oct-2023 16:25:25.967 SEVERE [http-nio-9090-exec-1] com.sun.faces.util.Util.checkIdUniqueness +id: j_id1
 type: javax.faces.component.UIViewRoot@103f414
  +id: javax_faces_location_HEAD
   type: com.sun.faces.component.ComponentResourceContainer@23a6f92f
    +id: j_id2
     type: javax.faces.component.UIOutput@23d4beea
    +id: j_id3
     type: javax.faces.component.UIOutput@4638b819
    +id: j_id4
     type: javax.faces.component.UIOutput@101099f6
    +id: j_id5

This is a parcial stack because it basically says that every component on the page is duplicated.

I also tried STATE_SAVING_METHOD on the client and server. I also updated the Mojarra version to 2.3.21.

Edit: here is an example of the xhtml page

<div class="layout-main" >
            <h:form id="mainForm" >

                <div class="ui-g" >
                    <div  class="ui-g-12" >
                        <p:commandButton    value="#{msg.test}" styleClass="BtnAccionesLista Fright  Wid100 "
                                            actionListener="#{bbTest.test()}" process="@this" update=":mainForm" partialSubmit="true"  />
                    </div>
                </div>
                <div class="ui-g" >
                    <div  class="ui-g-12" >
                        <h:panelGroup  >
                            <p:outputLabel  value="date_from" />
                            <p:calendar mask="true" value="#{bbTest.dateFrom}"
                                        showButtonPanel="true" showTodayButton="true" showOn="button"   >
                                <p:ajax event="dateSelect" process="@this" update=":mainForm" partialSubmit="true" listener="#{bbTest.test()}" />
                                <p:ajax event="change" process="@this" update=":mainForm" partialSubmit="true" listener="#{bbTest.test()}" />
                            </p:calendar>
                        </h:panelGroup>
                    </div>
                    <div  class="ui-g-12" >
                        <h:panelGroup  >
                            <p:outputLabel  value="date_to" />
                            <p:calendar mask="true" value="#{bbTest.dateTo}"
                                        showButtonPanel="true" showTodayButton="true" showOn="button"   >
                                <p:ajax event="dateSelect" process="@this" update=":mainForm" partialSubmit="true" listener="#{bbTest.test()}" />
                                <p:ajax event="change" process="@this" update=":mainForm" partialSubmit="true" listener="#{bbTest.test()}" />
                            </p:calendar>
                        </h:panelGroup>
                    </div>
                </div>
                <div class="ui-g" >
                    <div  class="ui-g-12" >
                        <p:dataTable    value="#{bbTest.list}" var="item"
                                        paginator="true" paginatorPosition="bottom" sortBy="#{item.field1}" sortOrder="DESCENDING"
                                        scrollable="true"
                                        rows="15" rowsPerPageTemplate="15,25">

                            <p:column headerText="field1"  sortable="false">
                                <h:outputText value="#{item.field1}" title="#{item.field1}"/>
                            </p:column>
                            <p:column headerText="field2"  sortable="false">
                                <h:outputText value="#{item.field2}" title="#{item.field2}"/>
                            </p:column>
                        </p:dataTable>
                    </div>
                </div>


            </h:form>
        </div>
@Named("bbTest")
@ViewScoped
public class BBTest implements Serializable {

    private static final long serialVersionUID = 4543464259557561468L;
    private Date dateFrom;
    private Date dateTo;
    private List<Test> list;


    @PostConstruct
    private void init(){
        dateFrom = DateUtil.firstDay();
        dateTo = DateUtil.lastDay();
        completeList();
    }

    private void completeList(){
        list = new ArrayList<>();
        for(int i=0;i<30;i++){
            Test test = new Test();
            test.setField1("value"+i);
            list.add(test);
        }
    }

    public void test(){
        System.out.println("test");
    }

    public List<Test> getList() {
        return list;
    }

    public void setList(List<Test> list) {
        this.list = list;
    }

    public Date getDateFrom() {
        return dateFrom;
    }

    public void setDateFrom(Date dateFrom) {
        this.dateFrom = dateFrom;
    }

    public Date getDateTo() {
        return dateTo;
    }

    public void setDateTo(Date dateTo) {
        this.dateTo = dateTo;
    }
}

If I remove a column of the datatable on the new tomcat instance, then when the session is moved from one tomcat to another, I get the error.

So, my question is, in cases where I need to deploy a change in an XML file, is it possible to restore the JSF view correctly, or should I create a parallel file for existing sessions? What would be the best approach?

Upvotes: 2

Views: 103

Answers (0)

Related Questions