Primefaces JSF null returned from RequestContext.getCurrentInstance()

8.5k views Asked by At

I'm developing an app using Primefaces tag library.

So far I've copied some examples from their official website and all seems to work except for anything that uses the RequestContext.getCurrentInstance() method. It either returns null every time, causing Tomcat to throw a NullPointer exception or hangs forever, never returning anything.

Here's my code (the case where it hangs):

GlobalCounterBean.java

package org.primefaces.examples.view;

import java.io.Serializable;
import org.primefaces.context.RequestContext;

public class GlobalCounterBean implements Serializable{

    private int count;

    public int getCount() {
    return count;
    }

    public void setCount(int count) {
    this.count = count;
    }

    public synchronized void increment() {
    count++;
    System.out.println("aaaa");
        RequestContext.getCurrentInstance().push("counter", count);
    }
}

test.xhtml:

<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:h="http://java.sun.com/jsf/html"
        xmlns:f="http://java.sun.com/jsf/core"
        xmlns:p="http://primefaces.org/ui">
    <h:head>
    </h:head>   
    <h:body>    

        <p:spinner />   

        <h:form>
    <h:outputText value="#{globalCounter.count}" styleClass="ui-widget display" />

    <br />

    <p:commandButton value="Click" actionListener="#{globalCounter.increment}" />
</h:form>

<p:push onmessage="handleMessage" channel="counter" />

<script type="text/javascript">
    function handleMessage(evt, data) {
            $('.display').html(data);
    }
</script>


    </h:body>
</html>

And here's the code for the case when it returns null (all files are in the same project):

ChatController.java:

    package org.primefaces.examples.view;

    import java.io.Serializable;
    import java.util.HashSet;
    import java.util.Set;

    import javax.faces.application.FacesMessage;
    import javax.faces.bean.ApplicationScoped;
    import javax.faces.bean.ManagedBean;
    import javax.faces.context.FacesContext;
    import javax.faces.event.ActionEvent;

    import org.primefaces.context.RequestContext;


    public class ChatController implements Serializable {

        private final static String CHANNEL = "chat";

        private String message;

        private String username;

        private boolean loggedIn;

        private Set<String> users = new HashSet<String>();

        public String getMessage() {
            return message;
        }
        public void setMessage(String message) {
            this.message = message;
        }

        public String getUsername() {
            return username;
        }
        public void setUsername(String username) {
            this.username = username;
        }

        public boolean isLoggedIn() {
            return loggedIn;
        }
        public void setLoggedIn(boolean loggedIn) {
            this.loggedIn = loggedIn;
        }

        public void send() {
            RequestContext.getCurrentInstance().push(CHANNEL, username + ": "+  message);

            message = null;
        }

        public void login() {

            RequestContext requestContext = RequestContext.getCurrentInstance();

            if(users.contains(username)) {
                loggedIn = false;
                FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, "Username taken", "Try with another username."));

                requestContext.addPartialUpdateTarget("growl");
            }
            else {
                users.add(username);
                loggedIn = true;

                requestContext.push(CHANNEL, username + " joined the channel.");
            }
        }

        public void disconnect() {
            RequestContext.getCurrentInstance().push(CHANNEL, username + " has left the channel.");
            loggedIn = false;
            username = null;
        }
    }

chat.xhtml

        <html xmlns="http://www.w3.org/1999/xhtml"
            xmlns:h="http://java.sun.com/jsf/html"
            xmlns:f="http://java.sun.com/jsf/core"
            xmlns:p="http://primefaces.org/ui">

        <head>
        <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
        <title>Insert title here</title>
        </head>
        <body>
        <f:view>
        <p:growl id="growl" showDetail="true" />

        <h:form>

            <p:fieldset id="container" legend="PrimeChat">

                <h:panelGroup rendered="#{chatController.loggedIn}" >
                    <p:outputPanel layout="block" style="width:600px;height:200px;overflow:auto" 
                               styleClass="chatroom" />
                    <p:spinner />
                    <p:separator />

                    <p:inputText value="#{chatController.message}" styleClass="messageInput" />
                    <p:spacer width="5" />
                    <p:commandButton value="Send" actionListener="#{chatController.send}" global="false" oncomplete="$('.messageInput').val('').focus()"/>
                    <p:spacer width="5" />
                    <p:commandButton value="Disconnect" actionListener="#{chatController.disconnect}" global="false" 
                                        oncomplete="chatAgent.close()" update="container" />
                </h:panelGroup>

                <h:panelGroup rendered="#{not chatController.loggedIn}" >
                    Username: <p:inputText value="#{chatController.username}" />

                    <p:spacer width="5" />
                    <p:commandButton value="Login" actionListener="#{chatController.login}" update="container" 
                                     icon="ui-icon-person"/>
                </h:panelGroup>

            </p:fieldset>

        </h:form>

        <p:push onmessage="handleMessage" channel="chat" widgetVar="chatAgent" />

        <script type="text/javascript">
            function handleMessage(evt, data) {
                var chatContent = $('.chatContent');
                chatContent.append(data + '<br />');

                //keep scroll
                chatContent.scrollTop(chatContent.height());
            }
        </script>
        <script type="text/javascript">
        function handleComplete(xhr, status, args) {
            if(args.validationFailed) {
                PrimeFaces.debug("Validation Failed");
            } 
            else {
                PrimeFaces.debug("Save:" + args.saved);
                PrimeFaces.debug("FirstName: " + args.user.firstname + ", Lastname: " + args.user.lastname); 
            }
        }
        </script>

        </f:view>
        </body>
        </html>

faces-config.xml:

    <?xml version="1.0" encoding="utf-8"?>
    <faces-config version="2.0" xmlns="http://java.sun.com/xml/ns/javaee"
     xmlns:xi="http://www.w3.org/2001/XInclude"
     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-facesconfig_2_0.xsd">
     <managed-bean eager="true">
      <managed-bean-name>chatController</managed-bean-name>
      <managed-bean-class>org.primefaces.examples.view.ChatController</managed-bean-class>
      <managed-bean-scope>request</managed-bean-scope>
     </managed-bean>
     <managed-bean>
      <managed-bean-name>globalCounter</managed-bean-name>
      <managed-bean-class>org.primefaces.examples.view.GlobalCounterBean</managed-bean-class>
      <managed-bean-scope>application</managed-bean-scope>
     </managed-bean>
     <!--
        No ManagedBean declarations here as we are using @ManagedBean Annotations.
        -->
    </faces-config>

web.xml:

        <?xml version="1.0" encoding="UTF-8"?>
        <web-app version="2.5"
            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_2_5.xsd" >

            <welcome-file-list>
                <welcome-file>index.jsp</welcome-file>
            </welcome-file-list>

            <servlet>
                <servlet-name>Faces Servlet</servlet-name>
                <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
                <load-on-startup>1</load-on-startup>
            </servlet>

            <servlet-mapping>
                <servlet-name>Faces Servlet</servlet-name>
                <url-pattern>*.xhtml</url-pattern>
            </servlet-mapping>

        </web-app>

And here's the exception thrown in tomcat console:

                        2012-05-27 19:16:25 com.sun.faces.context.ExceptionHandlerImpl log
            SEVERE: JSF1073: javax.faces.event.AbortProcessingException caught during processing of INVOKE_APPLICATION 5 : UIComponent-ClientId=j_idt2:j_idt16, Message=java.lang.NullPointerException
            2012-05-27 19:16:25 com.sun.faces.context.ExceptionHandlerImpl log
            SEVERE: java.lang.NullPointerException
            javax.faces.event.AbortProcessingException: java.lang.NullPointerException
                at javax.faces.event.MethodExpressionActionListener.processAction(MethodExpressionActionListener.java:178)
                at javax.faces.event.ActionEvent.processListener(ActionEvent.java:84)
                at javax.faces.component.UIComponentBase.broadcast(UIComponentBase.java:773)
                at javax.faces.component.UICommand.broadcast(UICommand.java:296)
                at javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:781)
                at javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:1246)
                at com.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:77)
                at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:97)
                at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:114)
                at javax.faces.webapp.FacesServlet.service(FacesServlet.java:308)
                at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
                at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
                at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
                at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
                at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
                at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
                at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
                at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293)
                at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:859)
                at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:602)
                at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489)
                at java.lang.Thread.run(Thread.java:680)
            Caused by: java.lang.NullPointerException
                at org.primefaces.examples.view.ChatController.login(ChatController.java:69)
                at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
                at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
                at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
                at java.lang.reflect.Method.invoke(Method.java:597)
                at org.apache.el.parser.AstValue.invoke(AstValue.java:191)
                at org.apache.el.MethodExpressionImpl.invoke(MethodExpressionImpl.java:276)
                at javax.faces.event.MethodExpressionActionListener.processAction(MethodExpressionActionListener.java:149)
                ... 21 more                    
1

There are 1 answers

5
BalusC On

Your web.xml is missing the "URL Configuration" part of PrimeFaces Push setup.

As mentioned in my answer on your previous question, Installation details of PrimeFaces Push are outlined in chapter 6 of PrimeFaces User's Guide. Here's an extract of relevance for the step you're missing:

6.1 Setup

Push Server

PrimeFaces Push uses a servlet as a dispatcher. This servlet should be in a different application than the JSF application and at the moment can only be deployed on jetty server.

<servlet>
    <servlet-name>Push Servlet</servlet-name>
    <servlet-class>org.primefaces.push.PushServlet</servlet-class>
    <load-on-startup>1</load-on-startup> 
    <init-param>
        <param-name>channels</param-name>
        <param-value>chat,counter</param-value>
    </init-param>
</servlet>
<servlet-mapping>
    <servlet-name>Push Servlet</servlet-name>
    <url-pattern>/prime-push/*</url-pattern>
</servlet-mapping>

channels configuration defines the topic names that push server can publish to.

URL Configuration

The JSF application needs to define the push server url to send messages.

<context-param>
    <param-name>primefaces.PUSH_SERVER_URL</param-name>
    <param-value>ws://url_to_push_server</param-value>
</context-param>