Search code examples
primefacesliferay-6jsf-2.2

Liferay: jsf portlet and navigation from commandButton with view params


I am using Lifreay 6.2 with primefaces 6.0.

I have these two simple views:

view.xhtml

<f:view xmlns="http://www.w3.org/1999/xhtml"
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui">
<h:head />
<f:metadata>
    <f:viewParam name="fromPlace"
        value="#{modelBean.fromPlace}" />
</f:metadata>

<h:body>
    <h:form>
        <p:inputText id="foo"
            value="#{modelBean.fromPlace}" />
        <p:commandButton value="submit"
            action="search?faces-redirect=true&amp;includeViewParams=true" />
    </h:form>
</h:body>
</f:view>

search.xtml

<f:view xmlns="http://www.w3.org/1999/xhtml"
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui">
<h:head />
<f:metadata>
    <f:viewParam name="fromPlace"
        value="#{modelBean.fromPlace}" />
</f:metadata>

<h:body>
    #{param.fromPlace}

    #{modelBean.fromPlace}
</h:body>
</f:view>

The goal of this is simple. Type a value on the inputText element, click the submit button, and then redirect to the second page and show the result. The reason I have a command button is that I want in the future to execute some backing bean action and dynamically return the redirect viewId, but right now is irrelevant.

My question is this.. If I put ajax=false at the command button component, everything works as expected. If I put ajax=true at the command button component, I get a weird error ONLY when my input contains spaces. If it doesn't contain spaces, it works again as expected. Putting the parameters manually at the URL string didn't work either, regadless of various tries of encoding etc. Also, with regular jsf components (like here) same thing happens. In the eclipse console the following lines appear:

14:42:20,856 ERROR [BridgeContextImpl:234] Illegal character in query at index 79: /test-portlet/WEB-INF/views/search.xhtml?fromPlace=123 321&_bridgeAjaxRedirect=true
java.net.URISyntaxException: Illegal character in query at index 79: /test-portlet/WEB-INF/views/search.xhtml?fromPlace=123 321&_bridgeAjaxRedirect=true

Is this behavior normal?

Edit: I created a new jsf portlet project using the archetype provided from liferayfaces.org/ and then I imported it as an existing maven project but a similar error appears.

error

15:54:11,198 ERROR [ExceptionHandlerAjaxImpl:75] javax.portlet.faces.BridgeException: java.net.URISyntaxException: Illegal character in query at index 110: /com.mycompany.my.primefaces.portlet-portlet/WEB-INF/views/search.xhtml?_jsfBridgeRedirect=true&fromPlace=1234 1234
javax.faces.FacesException: javax.portlet.faces.BridgeException: java.net.URISyntaxException: Illegal character in query at index 110: /com.mycompany.my.primefaces.portlet-portlet/WEB-INF/views/search.xhtml?_jsfBridgeRedirect=true&fromPlace=1234 1234

pom.xml

<?xml version="1.0"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.mycompany</groupId>
    <artifactId>com.mycompany.my.primefaces.portlet</artifactId>
    <packaging>war</packaging>
    <name>com.mycompany.my.primefaces.portlet</name>
    <version>1.0-SNAPSHOT</version>
    <properties>
        <faces.api.version>2.2</faces.api.version>
        <liferay.faces.bridge.ext.version>3.0.0</liferay.faces.bridge.ext.version>
        <liferay.faces.bridge.version>4.0.0</liferay.faces.bridge.version>
        <mojarra.version>2.2.13</mojarra.version>
    </properties>
    <build>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.3</version>
                <configuration>
                    <encoding>UTF-8</encoding>
                    <source>1.7</source>
                    <target>1.7</target>
                </configuration>
            </plugin>
            <plugin>
                <artifactId>maven-war-plugin</artifactId>
                <version>2.3</version>
                <configuration>
                    <filteringDeploymentDescriptors>true</filteringDeploymentDescriptors>
                </configuration>
            </plugin>
        </plugins>
    </build>
    <dependencies>
        <dependency>
            <groupId>commons-fileupload</groupId>
            <artifactId>commons-fileupload</artifactId>
            <version>1.3.1</version>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.4</version>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>javax.faces</groupId>
            <artifactId>javax.faces-api</artifactId>
            <version>${faces.api.version}</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.glassfish</groupId>
            <artifactId>javax.faces</artifactId>
            <version>${mojarra.version}</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>com.liferay.faces</groupId>
            <artifactId>com.liferay.faces.bridge.ext</artifactId>
            <version>${liferay.faces.bridge.ext.version}</version>
        </dependency>
        <dependency>
            <groupId>com.liferay.faces</groupId>
            <artifactId>com.liferay.faces.bridge.impl</artifactId>
            <version>${liferay.faces.bridge.version}</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.14</version>
        </dependency>
        <dependency>
            <groupId>org.primefaces</groupId>
            <artifactId>primefaces</artifactId>
            <version>6.0</version>
        </dependency>
    </dependencies>
</project>

web.xml

<?xml version="1.0" encoding="UTF-8"?>

<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0">

    <!-- Seting the JSF 2 PROJECT_STAGE to Development will cause the JSF implementation will do the following at runtime: -->
    <!-- 1. Log more verbose messages. -->
    <!-- 2. Render tips and/or warnings in the view markup. -->
    <!-- 3. Cause the default ExceptionHandler to display a developer-friendly error page. -->
    <context-param>
        <param-name>javax.faces.PROJECT_STAGE</param-name>
        <param-value>Development</param-value>
    </context-param>
    <!-- JSF 2.2 now allows for composite components and resources to be hidden under WEB-INF -->
    <context-param>
        <param-name>javax.faces.WEBAPP_RESOURCES_DIRECTORY</param-name>
        <param-value>/WEB-INF/resources</param-value>
    </context-param>
    <!-- Although the FacesServlet will not be invoked by any portlet requests, it is required to initialize JSF. -->
    <servlet>
        <servlet-name>Faces Servlet</servlet-name>
        <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <security-constraint>
        <display-name>Prevent direct access to Facelet XHTML</display-name>
        <web-resource-collection>
            <web-resource-name>Facelet XHTML</web-resource-name>
            <url-pattern>*.xhtml</url-pattern>
        </web-resource-collection>
        <auth-constraint/>
    </security-constraint>
</web-app>

liferay-portlet.xml

<?xml version="1.0"?>
<!DOCTYPE liferay-portlet-app PUBLIC "-//Liferay//DTD Portlet Application 6.2.0//EN" "http://www.liferay.com/dtd/liferay-portlet-app_6_2_0.dtd">

<liferay-portlet-app>
    <portlet>
        <portlet-name>com.mycompany.my.primefaces.portlet</portlet-name>
        <icon>/resources/images/icon.png</icon>
        <requires-namespaced-parameters>false</requires-namespaced-parameters>
        <ajaxable>false</ajaxable>
    </portlet>
    <role-mapper>
        <role-name>administrator</role-name>
        <role-link>Administrator</role-link>
    </role-mapper>
    <role-mapper>
        <role-name>guest</role-name>
        <role-link>Guest</role-link>
    </role-mapper>
    <role-mapper>
        <role-name>power-user</role-name>
        <role-link>Power User</role-link>
    </role-mapper>
    <role-mapper>
        <role-name>user</role-name>
        <role-link>User</role-link>
    </role-mapper>
</liferay-portlet-app>

Solution

  • Edit: FACES-2958 has been fixed as of Bridge Impl 4.1.1 and Bridge Ext 5.0.2.

    You are running into a bug: FACES-2958.

    As you've found, you can workaround this issue by using the commandButton without ajax.

    p:commandButton:

    <p:commandButton value="submit"
        action="search?faces-redirect=true&amp;includeViewParams=true"
        ajax="false" />
    

    h:commandButton:

    <h:commandButton value="submit"
        action="search?faces-redirect=true&amp;includeViewParams=true" />