Search code examples
javahibernatejsfnavigationconditional-statements

Conditional navigation not working properly in JSF


I am developing a website with JSF 2.0, hibernate and primefaces. I'm implementing an admin panel where the website admin can put the whole application on "maintenance mode". This is done by changing a flag on an application scoped bean (called on purpose AppConfigurationBean).

If the flag is active the user is necessarily returned to a page, called maintenance.xhtml, by a conditional navigation rule declared in faces-config.xml.

The user can bypass the maintenance page by inserting a special bypass key which can be given seldom by the admin. If he does so, a flag is activated on a special session scoped bean, which holds information about the user and is called CurrentClientSessionBean.

The navigation rule works if the value returned from a special method on the CurrentClientSessionBean, which take in counts the maintenance mode flag on the application bean and the "has bypass key" flag on himself.

Here is the navigation rule on faces-config.xml:

<navigation-rule>
    <description>System</description>
    <from-view-id>*</from-view-id>
    <navigation-case>
        <display-name>Maintenance Mode</display-name>
        <from-outcome>*</from-outcome>
        <if>#{currentClientSessionBean.toReturnToMaintenance}</if>
        <to-view-id>/maintenance.xhtml</to-view-id>
        <redirect />
    </navigation-case>
</navigation-rule>

Here is the maintenance.xhtml page:

<ui:composition id="maintenance" xmlns="http://www.w3.org/1999/xhtml"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:p="http://primefaces.org/ui"
    xmlns:plm="http://java.sun.com/jsf/composite/plmCustomComponents">

    <f:verbatim>&lt;!DOCTYPE html&gt;</f:verbatim>

    <html>

        <h:head>
        
        <title>#{msg.applicationTitle}</title>
        
        <meta charset="UTF-8"></meta>
        <meta http-equiv="content-type" content="text/html; charset=utf-8"></meta>
        
        <h:outputStylesheet library="default" name="css/normalize.css" />
        <h:outputStylesheet library="default" name="css/icons.css" />
        <h:outputStylesheet library="default" name="css/main.css" />
        
        </h:head>
        
        <f:metadata>
        <ui:include src="metadata/browserViewParams.xhtml" />
        </f:metadata>
        
        <h:body>
        
        <div id="legalPart">
            <ui:insert name="legalPart">
            <ui:include src="/structure/legalPart.xhtml" />
            </ui:insert>
        </div>
        
        <p:panel>
        
        <h1>
            <h:outputText value="#{msg.maintenancePageTitle}" />
        </h1>
        <p>
            <h:outputText value="#{msg.maintenancePageBodyMsg}" />
        </p>
        <h:form>
            <p:outputLabel for="bypassKeyInput"
            value="#{msg.maintenancePageInsertBypassKeyLabel}" />
            <br />
            <p:inputText id="bypassKeyInput"
            value="#{maintenanceBacking.keyBuffer}" required="true" />
            <br />
            <p:message for="bypassKeyInput" />

            <p:commandButton value="#{msg.checkPassword}"
            action="#{maintenanceBacking.checkBypassKey}" ajax="false" />
        </h:form>
        
        </p:panel>
        
        <ui:debug />
        
        </h:body>

    </html>

</ui:composition>

The maintenance backing is really simple, it simply checks if the bypasskey matches the true one and does a simple navigation to the home page if true.

Now the CurrentClientSessionBean method for the conditional navigation is this one:

/**
 * Special getter that determines if user should return to maintenance
 * 
 * @return
 */
public boolean isToReturnToMaintenance(){
    try{
        AppConfigurationBean appConfigurationBean = JSFAppUtils.findApplicationBean("appConfigurationBean");
        boolean result = ((!this.hasBypassKey) && appConfigurationBean.isMaintenanceModeOn());
        return result;
    }catch(NotFoundException e){
        logger.error("NotFoundException thrown in isToReturnToMaintenance method", e);
        throw new RuntimeException("NotFoundException thrown in isToReturnToMaintenance method", e);
    }
}

Here is the main problem: for some odd reason, when the maintenance mode is active the user is forced to return to maintenance page even if he puts the right bypass key in the input.

Furthermore: There must be something really wrong within my application, because i tried to comment the conditional navigation rule, which means that maintenance page should be unreachable and changes to the maintenance mode should have no effect on the application, but still the maintenance mode system went on working with the same attitude I described.


Solution

  • It seems that I added a redirect on the homepage which was connected to the maintenanceModeOn boolean flag, and didn't take in count the hasBypassKey flag.

    The rule was deeply nested in some part of the code which I wrote long long time ago and I forgot about.

    <h:panelGroup rendered="#{appConfigurationBean.maintenanceModeOn}">
        <script>
            window.location = "maintenance.faces";
        </script>       
    </h:panelGroup>`