0

Currently im working on primefaces push function. actually, the push function is working properly.

This is my push flow: I have two application with share same database, admin dashboard(primefaces + spring) and webapi (spring mvc). when there are data inserted to database via webapi, then web api will call the admin url that will trigger to push notification for all logged in user. and its working fine, as expected.

my problems is, when there are push notification, and then user do logout at the same time (at least notification growl not gone) it will throw java.lang.IllegalStateException: Cannot call sendRedirect() after the response has been committed and sometime Cannot create a session after the response has been committed.

i have try to change Login Controller to ViewScope, and put this context-param to web xml, but still not working.

<context-param>
    <param-name>javax.faces.STATE_SAVING_METHOD</param-name>
    <param-value>client</param-value>
</context-param>

Please Help,

this is the full stack trace:

SEVERE: Servlet.service() for servlet [facesServlet] in context with path [/WebAdmin] threw exception [java.lang.IllegalStateException: Cannot call sendRedirect() after the response has been committed] with root cause
java.lang.IllegalStateException: Cannot call sendRedirect() after the response has been committed
    at org.apache.catalina.connector.ResponseFacade.sendRedirect(ResponseFacade.java:482)
    at com.sun.faces.context.ExternalContextImpl.redirect(ExternalContextImpl.java:678)
    at org.omnifaces.util.FacesLocal.redirect(FacesLocal.java:882)
    at org.omnifaces.util.Faces.redirect(Faces.java:1170)
    at com.sepakbole.web.controller.LoginController.doLogout(LoginController.java:84)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.apache.el.parser.AstValue.invoke(AstValue.java:279)
    at org.apache.el.MethodExpressionImpl.invoke(MethodExpressionImpl.java:273)
    at com.sun.faces.facelets.el.TagMethodExpression.invoke(TagMethodExpression.java:105)
    at javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:87)
    at com.sun.faces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:102)
    at javax.faces.component.UICommand.broadcast(UICommand.java:315)
    at javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:790)
    at javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:1282)
    at com.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:81)
    at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
    at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:198)
    at javax.faces.webapp.FacesServlet.service(FacesServlet.java:658)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at com.sepakbole.web.filter.AuthorizationFilter.doFilter(AuthorizationFilter.java:51)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.logging.log4j.web.Log4jServletFilter.doFilter(Log4jServletFilter.java:71)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:218)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:505)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:169)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:956)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:442)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1082)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:623)
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:316)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:745)

Update: This is my Controller:

import java.io.Serializable;

import javax.faces.bean.ApplicationScoped;
import javax.faces.bean.ManagedBean;

import org.primefaces.push.EventBus;
import org.primefaces.push.EventBusFactory;

@ManagedBean
@ApplicationScoped
public class PushMessageController implements Serializable {
    private static final long serialVersionUID = 1L;
    private String data;

    public String getData() {
        return data;
    }

    public void setData(String data) {
        this.data = data;
    }

    public void execute(){
        EventBus eventBus = EventBusFactory.getDefault().eventBus();
        eventBus.publish("/receive-message", data);
    }
}

And Below is the PushEndPoint: import org.primefaces.push.annotation.OnMessage; import org.primefaces.push.annotation.PushEndpoint; import org.primefaces.push.annotation.Singleton; import org.primefaces.push.impl.JSONEncoder;

@PushEndpoint("/receive-message")
@Singleton
public class MessageResource {

    @OnMessage(encoders = {JSONEncoder.class})
    public String onMessage(String data) {
        return data;
    }
}

and this this is placed on my template:

<p:socket channel="/receive-message" onMessage="handleMessage"></p:socket>
    <p:growl widgetVar="growl-msg" globalOnly="true" id="growl-msg" life="2000" />
    <script type="text/javascript">
        function handleMessage(facesmessage) {
               PF('growl-msg').renderMessage({"summary":"New Message",
                   "detail":facesmessage,
                   "severity":"info"})
        }
    </script>

to trigger the notification, i call this url. Where the data parameter is dynamic message that will showed into growl.

http://localhost:5050/WebAdmin/primepushpage/receive-message.jsf?data=Testing123

and this is my receive-message.xhtml

<ui:composition xmlns="http://www.w3.org/1999/xhtml"
    xmlns:h="http://xmlns.jcp.org/jsf/html"
    xmlns:f="http://xmlns.jcp.org/jsf/core"
    xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
    xmlns:p="http://primefaces.org/ui"
    template="../pages/template.xhtml">

    <ui:define name="content">
        <f:metadata>
            <f:viewParam name="data" value="#{pushMessageController.data}" />
        </f:metadata>

        <h:form>
        <p:remoteCommand name="remoteCommand" actionListener="#{pushMessageController.execute}" autoRun="true" />
        </h:form>
    </ui:define>

</ui:composition>

and this is doFilter method on my Authorization Filter:

public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws ServletException, IOException {    
            HttpServletRequest request = (HttpServletRequest) req;
            HttpServletResponse response = (HttpServletResponse) res;
            HttpSession session = request.getSession(false);
            String loginURL = request.getContextPath() + "/pages/index.jsf";

            boolean loggedIn = (session != null) && (session.getAttribute("user") != null);
            boolean loginRequest = request.getRequestURI().equals(loginURL);
            boolean resourceRequest = request.getRequestURI().startsWith(request.getContextPath() + ResourceHandler.RESOURCE_IDENTIFIER + "/");
            boolean ajaxRequest = "partial/ajax".equals(request.getHeader("Faces-Request"));
            boolean pushRequest = request.getRequestURI().contains("primepush");

            if (loggedIn || loginRequest || resourceRequest || pushRequest) {
                if (!resourceRequest) { // Prevent browser from caching restricted resources. See also http://stackoverflow.com/q/4194207/157882
                    response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // HTTP 1.1.
                    response.setHeader("Pragma", "no-cache"); // HTTP 1.0.
                    response.setDateHeader("Expires", 0); // Proxies.
                }

                chain.doFilter(request, response); // So, just continue request.
            }
            else if (ajaxRequest) {
                response.setContentType("text/xml");
                response.setCharacterEncoding("UTF-8");
                response.getWriter().printf(AJAX_REDIRECT_XML, loginURL); // So, return special XML response instructing JSF ajax to send a redirect.
            }
            else {
                if(!response.isCommitted()){
                    response.sendRedirect(loginURL); // So, just perform standard synchronous redirect.
                    return;
                }
            }
        }

and i have add push servlet mapping on my web.xml, also my pom.xml already have atmosphere-runtime dependency. and i use Tomcat 7 for the container.

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
dibrut
  • 81
  • 1
  • 2
  • 9

1 Answers1

3

I had a same issue. After page was refresh via ajax and user manualy refreshed page I got from ocpsoft rewrite following warning:
Response has already been committed, and further write operations are not permitted. This may result in an IllegalStateException being triggered by the underlying application.

And after that the page was in invalid state and second refresh was needed. I have spent many hours trying to solve this issue and as last thing I tried to use different versions of atmosphere runtime (at first I have used the latest 2.4.9) and found out that it works correctly with versions 2.4.0 until 2.4.2.

Primefaces manual says that you can use version 2.3.RC6 and newest, but with versions below 2.4.0 I got nasty exceptions during application startup.

I use Primefaces 6.0 and application is deployed on Tomcat 8.0.39

Rado Skrib
  • 396
  • 1
  • 4
  • 7
  • Thanks @Rado you save me. changing to 2.4.2 and the previous error is gone. Thanks. – dibrut Jan 04 '17 at 03:34
  • I also had observed this exact behavior when using atmosphere-runtime below 2.4.0 and above 2.4.2 and finally I had used 2.4.2 with PrimeFaces 5.3. – Parkash Kumar Jul 05 '17 at 08:45