cannot create session after response has been committed
Asked Answered
T

2

8

i am getting the following error on my application startup page load :

 SEVERE: Error Rendering View[/HomeTemplate/equityVolume.xhtml]
javax.el.ELException: /HomeTemplate/equityVolume.xhtml @70,78 value="#{equityBean.scripList}": java.lang.IllegalStateException: PWC3999: Cannot create a session after the response has been committed...

    Caused by: java.lang.IllegalStateException: PWC3999: Cannot create a session after the response has been committed...

i get this error when i apply the css to my homepage, the error disappears when i remove the css template(but i want to aplly the css template) following is the bean code snippet that causes the error(found by debugging)

public List<MasterScrip> getScripList() {
   HttpServletRequest req=(HttpServletRequest)FacesContext.getCurrentInstance().getExternalContext().getRequest(); //error line
   HttpSession session=req.getSession();
   type=(String)session.getAttribute("type");...

xhtml code:

<h:body>
    <ui:composition template="commonClientLayout.xhtml">

    <ui:define name="contentFile">
            <div id="content">
    <h:form id="frm">...

when i remove the ui:composition and define tags(i.e. if i dont apply the css), then i dont get this error. what could be causing this error and how do i solve it?

edited:

    @PostConstruct
void initialiseSession() {
    if(type!=null)
      {
       if(type.equalsIgnoreCase("losers"))
       {
        scripList=new ArrayList<MasterScrip> ();
        scripList=getScripByPriceLosers(exchange);
       // return scripList;
       }
       else if(type.equalsIgnoreCase("gainers"))
       {
        scripList=new ArrayList<MasterScrip> ();
     scripList=getScripByPriceGainers(exchange);
       // return scripList;
       }
       else
       {
           scripList=new ArrayList<MasterScrip> ();
     scripList=getScripByVolumeType(exchange);
     //  return scripList;
       }
      }
      else
      {
          scripList=new ArrayList<MasterScrip> ();
     scripList=getScripByVolumeType(exchange);
      }

}

    public List<MasterScrip> getScripList() {
       return scripList;

    }

edited again:

 SEVERE: Error Rendering View[/equityVolume.xhtml]
java.lang.IllegalStateException
    at org.apache.catalina.connector.ResponseFacade.setBufferSize(ResponseFacade.java:275)...

edit: web.xml

    <?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" 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">
    <context-param>
        <param-name>javax.faces.PROJECT_STAGE</param-name>
        <param-value>Production</param-value>
    </context-param>
    <context-param>
        <param-name>javax.faces.FACELETS_BUFFER_SIZE</param-name>
        <param-value>65535</param-value>
    </context-param>

    <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>
    <session-config>
        <session-timeout>
            30
        </session-timeout>

    </session-config>
    <welcome-file-list>
        <welcome-file>equityVolume.xhtml</welcome-file>
    </welcome-file-list>
    <security-constraint>
        <display-name>Constraint1</display-name>
        <web-resource-collection>
            <web-resource-name>AdminTemplate</web-resource-name>
            <description/>
            <url-pattern>/AdminTemplate/*</url-pattern>
        </web-resource-collection>
        <auth-constraint>
            <description/>
            <role-name>admin</role-name>
        </auth-constraint>
    </security-constraint>
    <security-constraint>
        <display-name>Constraint2</display-name>
        <web-resource-collection>
            <web-resource-name>ClientTemplate</web-resource-name>
            <description/>
            <url-pattern>/ClientTemplate/*</url-pattern>
        </web-resource-collection>
        <auth-constraint>
            <description/>
            <role-name>client</role-name>
        </auth-constraint>
    </security-constraint>
    <login-config>
        <auth-method>FORM</auth-method>
        <realm-name>DataRealm</realm-name>
        <form-login-config>
            <form-login-page>/equityVolume.xhtml</form-login-page>
            <form-error-page>/errorpage.xhtml</form-error-page>
        </form-login-config>
    </login-config>
    <security-role>
        <description/>
        <role-name>admin</role-name>
    </security-role>
    <security-role>
        <description/>
        <role-name>client</role-name>
    </security-role>
</web-app>
Troika answered 8/6, 2012 at 13:13 Comment(0)
D
6

You shouldn't be doing business job in getters. Do it in the bean (post)constructor instead.

Your concrete problem is caused because you're requesting a relatively large page on a fresh new browser session for which the server HttpSession hasn't been created yet and the EL expression #{equityBean.scripList} is referenced relatively late in the page.

The response buffer is by default 2KB and when it overflows due to a large response, then it will be committed. This means that all response headers will be sent and that first ~2KB of the HTML output will be sent. Then, after that point, the EL expression #{equityBean.scripList} will be resolved wherein you're trying to get the session. If the server HttpSession hasn't been created yet at that moment, then the server needs to set a cookie in the response header in order to maintain it for subsequent requests. But that's of course not possible if the response has already been committed. Hence this exception.

As said, just do the job in bean's (post)constructor instead. Or just inject it as managed property.

@ManagedProperty("#{type}")
private String type;

If the exception still occurs, you're probably using an older version of Mojarra which suffers from the bug as described in issues 2215 and 2277 which is caused by too extreme postponing of the "unnecessary" session creation. This has been fixed since Mojarra 2.1.8. So, upgrading to it or newer (it's currently 2.1.9) should do it.


Unrelated to the concrete problem, the getScripList() logic is by the way smelly. But that's subject for a different problem/question. Are you aware that you can just access the session attribute with name "type" in EL as #{type}? Are you aware that having raw javax.servlet.* imports in a JSF backing bean class more than often indicate that you're possibly doing things the wrong way and that there may be more "JSF-ish" ways to achieve the concrete functional requirement?

Digestible answered 8/6, 2012 at 15:9 Comment(17)
thanks for the explanation. i set the business logic in the postConstruct method, still i get the same error(see the edited question). i cant get any further in my app, what should i do? :(Troika
So the bean is simply not referenced anywhere earlier in the page? What JSF impl/version are you using? A similar issue was fixed in Mojarra 2.1.8. Alternatively you could change and increase the default response buffer size.Digestible
The exception indicates it's not early enough. Apparently the view is too large. As a quick test, put #{equityBean} before the <h:head> or so.Digestible
It's currently at 2.1.9, give it a try first. Otherwise increase the buffer size by setting the context param javax.faces.FACELETS_BUFFER_SIZE to a value of for example 65535 (64KB) in web.xml.Digestible
Mojarra has regression tests, so you should only get bugfixes/improvements with every new release, no regressions.Digestible
before upgrading mojarra, i tried to set the buffer size as you suggested, but i got the error edited in my questionTroika
so i think i should upgrade mojarra and hope it doesnt give me troubleTroika
um , sorry but i guess mojarra comes shipped with glassfish, so how do i upgrade it?Troika
You've to upgrade it in Glassfish itself. Is this under your control? If not, then, well, increase the buffer size or create (or reuse) a filter which does just a request.getSession();Digestible
its not under my control, pls see the edited question for the error that comes when i try to resize the bufferTroika
This in turn suggests that you're trying to set it while the response is already committed. Did you really set it by the aforementioned context parameter or not?Digestible
yes indeed, pls check the edited question , i have edited it again to include the we.xmlTroika
This is strange. The combination of those problems suggests that something else is explicitly committing the response by calling flushBuffer() or commit() on it. If you can't find out by debugging who's doing that, then I'd start creating a @WebFilter("*.xhtml") which does just a ((HttpServletRequest) request).getSession(); chain.doFilter(request, response); inside the doFilter() method.Digestible
before doing that may i ask you the steps to upgrade to mojarra 2.1.9? i have all rights on glassfish on another system. maybe i should upgrade it on that system to see if it works, if not i ll go with the filter thingTroika
the system is ubuntu and i have downloaded the mojarra stable release 2.1.9 binary from javaserverfaces.java.net/download.html, what next?Troika
Put it in /glassfish/modules folder and remove the older one if any. Before Mojarra 2.1.5 it are 2 files jsf-api.jar and jsf-impl.jar, after Mojarra 2.1.5 it is 1 file javax.faces.jar.Digestible
i didnt remove the aforementioned jar files and added the javax.faces.jar file and i also removed the contents of /glassfish/osgi, it worked! @BalusC- you rock dude, thanks a ton for your support :)Troika
J
3

I don't know this web framework (is it JSF?) but here is what happens. Your XHTML begins rendering the output and a few characters have already been sent to the browser. This implies that the whole header was sent as well.

Somewhere in the middle of your template you are calling #{equityBean.scripList} (BTW typo) which in turns calls:

HttpSession session=req.getSession();

This method will create HTTP session if one does not exist. The session ID must be sent with response (using cookie or URL rewriting) back to the client in order to identify the session back on subsequent requests. However since response headers were already sent, the servlet container is not capable of sending the session id back - and throws an exception avoiding even bigger problems.

How can you solve this? Looks like you are rendering the page for the first time when there is absolutely no session associated with the request. You can avoid creating the session:

HttpSession session=req.getSession(false);  //false here!
if(session != null) {
  type=(String)session.getAttribute("type");
}
//handle the case when session or type attribute weren't there

Another approach is to proactively create the session before you pass the control to the view. However you still have to check the type attribute for null.

Jeffreyjeffreys answered 8/6, 2012 at 13:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.