1

I have a Java EE App that has JSF2 + PrettyFaces + Facelets + EJB3 + EclipseLink.

I'm continually running into an IllegalStateException as stated above, due to some inconsistencies in the JSF2 + Faceletes rendering model to work along with PrettyFaces and h:link tag.

I removed all my old JSTL tags and also all the commandLink tags, according to good practices when using JSF2 + Faceletes.

In 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">
  <display-name>atlPortal</display-name>

    <context-param>
        <param-name>com.sun.faces.prefer.XHTML</param-name>
        <param-value>true</param-value>
    </context-param>

  <context-param>
    <param-name>javax.faces.PROJECT_STAGE</param-name>
    <param-value>Development</param-value>
  </context-param>

    <context-param>
        <param-name>javax.faces.FACELETS_LIBRARIES</param-name>
        <param-value>/WEB-INF/facelets/customTags.taglib.xml</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>*.faces</url-pattern>
  </servlet-mapping>

    <servlet>
        <servlet-name>imageServlet</servlet-name>
        <servlet-class>com.mindvortex.atl.web.common.servlet.ImageServlet</servlet-class>
        <load-on-startup>2</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>imageServlet</servlet-name>
        <url-pattern>/image/*</url-pattern>
        <url-pattern>/pages/image/*</url-pattern>
        <url-pattern>/pages/protected/image/*</url-pattern>
    </servlet-mapping>

    <filter>
       <filter-name>Pretty Filter</filter-name>
       <filter-class>com.ocpsoft.pretty.PrettyFilter</filter-class>    
       <async-supported>false</async-supported>    
    </filter>

    <filter-mapping> 
       <filter-name>Pretty Filter</filter-name>    
       <url-pattern>/*</url-pattern>
       <dispatcher>FORWARD</dispatcher> 
       <dispatcher>REQUEST</dispatcher>
       <dispatcher>ERROR</dispatcher>
    </filter-mapping>

  <listener>
    <listener-class>com.sun.faces.config.ConfigureListener</listener-class>
  </listener>

  <!-- servlets and such would be above -->

    <login-config>
        <auth-method>FORM</auth-method>
        <realm-name>userauth</realm-name>
        <form-login-config>
            <form-login-page>/login.faces</form-login-page>
            <form-error-page>/loginError.xhtml</form-error-page>
        </form-login-config>                
    </login-config>

    <security-constraint>
        <display-name>Block All XHTML</display-name>
        <web-resource-collection>
            <web-resource-name>blockXHTML</web-resource-name>
            <description></description>
            <url-pattern>*.xhtml</url-pattern>
            <http-method>GET</http-method>
            <http-method>POST</http-method>
            <http-method>HEAD</http-method>
            <http-method>PUT</http-method>
            <http-method>OPTIONS</http-method>
            <http-method>TRACE</http-method>
            <http-method>DELETE</http-method>
        </web-resource-collection>
        <auth-constraint />             
    </security-constraint>


    <security-constraint>   
        <display-name>ConstraintSSL</display-name>
        <web-resource-collection>
            <web-resource-name>protected</web-resource-name>
            <description/>
            <url-pattern>/pages/protected/*</url-pattern>
            <url-pattern>/login/*</url-pattern>
            <url-pattern>/login.*</url-pattern>
            <url-pattern>/account/*</url-pattern>
            <http-method>GET</http-method>
            <http-method>POST</http-method>
            <http-method>HEAD</http-method>
            <http-method>PUT</http-method>
            <http-method>OPTIONS</http-method>
            <http-method>TRACE</http-method>
            <http-method>DELETE</http-method>
        </web-resource-collection>

        <user-data-constraint>
          <description>SSL not required for Development</description>
          <transport-guarantee>CONFIDENTIAL</transport-guarantee>
        </user-data-constraint>        
    </security-constraint>

    <security-constraint>   
        <display-name>ConstraintUser</display-name>
        <web-resource-collection>
            <web-resource-name>user</web-resource-name>
            <description/>
            <url-pattern>/account/*</url-pattern>
            <http-method>GET</http-method>
            <http-method>POST</http-method>
            <http-method>HEAD</http-method>
            <http-method>PUT</http-method>
            <http-method>OPTIONS</http-method>
            <http-method>TRACE</http-method>
            <http-method>DELETE</http-method>
        </web-resource-collection>
        <auth-constraint>       
            <description/>
            <role-name>ADMINISTRATORS</role-name>
            <role-name>USERS</role-name>
        </auth-constraint>

        <user-data-constraint>
          <description>SSL not required for Development</description>
          <transport-guarantee>CONFIDENTIAL</transport-guarantee>
        </user-data-constraint>        
    </security-constraint>

    <security-role>
        <description/>
        <role-name>USERS</role-name>
    </security-role>
    <security-role>
        <description/>
        <role-name>ADMINISTRATORS</role-name>
    </security-role>

  <session-config>
    <session-timeout>30</session-timeout>
    <tracking-mode>COOKIE</tracking-mode>
  </session-config>

   <welcome-file-list>
    <welcome-file>init.faces</welcome-file>    
   </welcome-file-list>

</web-app>

This happens whenever I navigate from one XHTML page to another via

                        <h:link outcome="pretty:viewContactUs" styleClass="nav6">
                            #{msg['contactUs']}
                        </h:link>                                                                                                                                      

in pretty-faces.xml

  <url-mapping id="viewContactUs">
      <pattern value="/contactUs/" />
      <view-id value="contactUs.faces" />
      <action>#{commentsMB.openContactUs}</action>
  </url-mapping>            

in CommentsMB Managed Bean:

@ManagedBean
@RequestScoped
public class CommentsMB extends UserCrudMB<Comments, Integer> {

    private static final long serialVersionUID = 1L;

    @EJB(mappedName="ejb/CommentsService")
    private CommentsServiceBeanLocal commentsService;

// ... Code

    public String openContactUs() {
        this.entity = new Comments();
        return NavigationViews.VIEW_CONTACT_US;
    }

}

in faces-config.xml:

   <navigation-rule>
        <from-view-id>/*</from-view-id>
        <navigation-case>
            <from-outcome>contactUs</from-outcome>
            <to-view-id>/pages/contactUs.xhtml</to-view-id>         
        <redirect /></navigation-case>

in contactUs.xhtml:

                    <div class="form_row">
                        <h:link id="commentsSave" outcome="pretty:commentsSave" styleClass="contact">
                            #{msg.send}
                        </h:link>
                    </div>

The error happens just when I click the commentsSave Button. It gives: IllegalStateException: PWC3990: getWriter() has already been called for this response.

the pretty-config.xml for commentsSave URL mapping:

  <url-mapping id="commentsSave">
      <pattern value="/comments/save/" />
      <view-id value="contactUs.faces" />
      <action>#{commentsMB.save}</action>
  </url-mapping>                       

CommentsMB save action signature:

public String save() {
    return save(this.getEntity());
}

The commentsMB.save Bean action is not called and I get a page not found error with the exception thrown in the logs.

StackTrace:

[#|2012-03-30T13:47:54.968-0300|SEVERE|glassfish3.1.1|org.apache.jasper.servlet.JspServlet|_ThreadID=25;_ThreadName=http-thread-pool-8084(4);|PWC6117:
 File "C%3A%5CGBL%5Cprop%5Cprogs%5Cglassfish-3.1.1%5Cglassfish3%5Cglassfish%5Cdomains%5Cdomain1%5Capplications%5CatlanteusEAR%5CatlanteusPortal-1.0.0_
war%5Ccomments%5Csave%5CcontactUs.jsp" not found|#]

[#|2012-03-30T13:47:54.976-0300|WARNING|glassfish3.1.1|org.apache.catalina.core.ApplicationDispatcherForward|_ThreadID=25;_ThreadName=http-thread-pool
-8084(4);|Exception processing ErrorPage[errorCode=404, location=/pages/error/error404.xhtml]
java.lang.IllegalStateException: PWC1227: Cannot forward after response has been committed
        at org.apache.catalina.core.ApplicationDispatcher.doDispatch(ApplicationDispatcher.java:370)
        at org.apache.catalina.core.ApplicationDispatcher.dispatch(ApplicationDispatcher.java:350)
        at org.apache.catalina.core.ApplicationDispatcherForward.custom(ApplicationDispatcherForward.java:253)
        at org.apache.catalina.core.ApplicationDispatcherForward.status(ApplicationDispatcherForward.java:209)
        at org.apache.catalina.core.ApplicationDispatcherForward.commit(ApplicationDispatcherForward.java:131)
        at org.apache.catalina.core.ApplicationDispatcher.dispatch(ApplicationDispatcher.java:353)
        at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:300)
        at com.ocpsoft.pretty.PrettyFilter.doFilter(PrettyFilter.java:110)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:256)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:217)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:279)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
        at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:655)
        at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:595)
        at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:98)
        at com.sun.enterprise.web.PESessionLockingStandardPipeline.invoke(PESessionLockingStandardPipeline.java:91)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:162)
        at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:330)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:231)
        at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:174)
        at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:828)
        at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:725)
        at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:1019)
        at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:225)
        at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:137)
        at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:104)
        at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:90)
        at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:79)
        at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:54)
        at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:59)
        at com.sun.grizzly.ContextTask.run(ContextTask.java:71)
        at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:532)
        at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:513)
        at java.lang.Thread.run(Thread.java:619)
|#]

Seems that JSF is interpreting the navigation as a .jsp altough I use XHTML only.

Could someone help me figure out what am I doing wrong ? This is my major issue since I began using JSF2 + Facelets.

guilhebl
  • 8,330
  • 10
  • 47
  • 66
  • Edit your question to include the stacktrace, please. This way we can find out who is trying to write to the response writer while it should apparently not do that. – BalusC Mar 30 '12 at 03:44
  • @BalusC Did as you proposed, thanks! – guilhebl Mar 30 '12 at 16:57
  • Okay, it's `PrettyFilter` of PrettyFaces who isn't checking if the response is committed. Well, at least your own code is excluded from being the cause. I'll leave this question for ones who are more familiar with PrettyFaces. It'll be either a bug in PrettyFaces itself or a misconiguration of `pretty-config.xml`. – BalusC Mar 30 '12 at 16:58
  • I saw many of your posts related to JSF, I'm using JSF2 with Facelets and since it's recommended not to use commandLink and JSTL, do you have any suggestion for any other tag that I could use that would provide navigation based on a Managed Bean Action method ? And that would not fall into the same issue of the getWriter already called ? Thanks in advance. – guilhebl Mar 30 '12 at 17:57
  • Your problem is caused by PrettyFaces, not by JSF/Facelets. Your JSF/Facelets code is perfectly fine. – BalusC Mar 30 '12 at 17:58
  • Sure but I mean since in JSF2 it's recommended to use h:link instead of h:commandLink. How can I use h:link and still have the navigation based on a JSF managed Bean? Are their any alternative tags for this approach? – guilhebl Mar 30 '12 at 18:09
  • The `` is recommended when you want page-to-page navigation. The `` should only be used to submit a form. You can always use plain HTML `` elements, but you have to set the real URL yourself. – BalusC Mar 30 '12 at 18:10
  • In this case I want to submit a form and also perform navigation to another page or not based on the Bean's Action method response, could I use in this case ? Or should I use only commandLink when there's no navigation, say returning always null from the Action method ? – guilhebl Mar 30 '12 at 18:57
  • I wouldn't say the problem is caused by PrettyFaces, I'd say that the problem is because of an improperly configured prettyfaces :) – Lincoln Mar 30 '12 at 20:54

2 Answers2

1

Don't you need a slash '/' in front of your "contactUs.faces" view-id value?

I think it should be:

"/contactUs.faces", right?

~Lincoln

Lincoln
  • 3,151
  • 17
  • 22
  • Lincoln, when I used with a / slash, the link URL couldn't be resolved: [#|2012-03-30T13:32:49.050-0300|WARNING|glassfish3.1.1|javax.enterprise.resource.webcontainer.jsf.renderkit|_ThreadID=21;_ThreadName=http-thread-pool- 8084(5);|JSF1090: Navigation case not resolved for component commentsSave.|#] – guilhebl Mar 30 '12 at 16:34
  • Ah, that's because this path needs to be fully qualified. You need to specify the full path to the JSF resource. – Lincoln Mar 30 '12 at 20:54
  • I tried using the fully qualified path to the JSF resource but it didn't work, my page is located at: /pages/contactUs.xhtml - but in pretty-config.xml I use in faces-config.xml I have contactUs /pages/contactUs.xhtml this pattern works fine for all pages across my app. The only problem is when I have 2 consecutive links rendered with PrettyFaces. Do you have any suggestions? Thanks in advance. – guilhebl Mar 30 '12 at 23:32
  • Why are you mixing navigation cases and pretty-config.xml? I would use one or the other.This may be your problem, but there is certainly a configuration issue at work here. If you would like to post for help on the OCPsoft support forums, we may be able to be of more assistance there. http://ocpsoft.org/support/ since you'll be able to post your entire stack traces and project files. – Lincoln Apr 01 '12 at 05:57
  • The only clue I can guess here is that the error you are receiving is not the root cause. There is a problem displaying the error page, which means that some other error is causing the problem, then the error page also happens to fail to display. Look for the first error and you should find your problem. – Lincoln Apr 01 '12 at 05:58
  • I have changed all my JSF view-id path references in pretty-config.xml to be fully qualified. And now the contactUs mappings works. Some other pages gives too many redirect errors. I'm concerned about you said mixing JSF navigation and pretty-config. So should I not have the faces-config navigation mappings ? I couldn't see through PrettyFaces docs how the faces-config mappings should look like when using PrettyFaces Filter. Thanks! – guilhebl Apr 02 '12 at 13:46
  • So in order to correctly use PrettyFaces with JSF we should avoid having navigation rules configured in faces-config.xml, and only keep the fully-qualified JSF resources in pretty-config.xml. So that answers this issue. Thank you very much for the help! – guilhebl Apr 02 '12 at 14:36
1

After considering answers I came up with the final solution so I will post here for others to understand:

  1. Changed the URL mappings in pretty-faces.xml for all JSF resources to be fully-qualified: for example if contactUs.xhtml is under /pages/ then the mapping would be:

    <url-mapping id="viewContactUs">
      <pattern value="/contactUs/" />
      <view-id value="/pages/contactUs.faces" />
      <action>#{commentsMB.openContactUs}</action></url-mapping>            
    
  2. Removed all the JSF navigation rules from faces-config.xml. For example rules like:

    <navigation-case>
        <from-outcome>contactUs</from-outcome>
        <to-view-id>/pages/contactUs.xhtml</to-view-id>         
    </navigation-case>
    

would be removed or commented out. After doing this the actual navigation mappings would be only present in pretty-config.xml and will work correctly with the PrettyFaces Filter.

guilhebl
  • 8,330
  • 10
  • 47
  • 66
  • To clarify. Whether or not the navigation rules exist does not matter - you just can't use them with prettyfaces unless you use – Lincoln Apr 13 '12 at 03:43