Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mixing JSP and XHTML (Facelets) in JSF2 Project - possible?

I have a client who wants to use JSF2 and they like that XHTML is now the default (Facelets).

However, they have a huge amount of "legacy" JSP from their JSF1.x codebase.

I know it's probably not desirable, but will it be possible to support a mix of both in JSF2, at least for a transition period whilst they port?

I know it was possible to mix the two in JSF1.x, but I can't find any information about this in JSF2.

I've googled hard but naturally all the JSF2 focus is on Facelets. Also my brief attempt at mixing (I'm not an expert at JSF!) has led to failure.

like image 790
Dick Chesterwood Avatar asked Oct 14 '10 18:10

Dick Chesterwood


3 Answers

This is answered in the Facelets FAQ: use prefix mapping on FacesServlet. You can then access JSP pages by http://example.com/faces/page.jsp and Facelets pages by http://example.com/faces/page.xhtml. Here's a cite of relevance:

How do I use Facelets and JSP in the same application?

You have to use prefix mapping for the Facelets pages in order for this to work. Leave the DEFAULT_SUFFIX with the JSF default of .jsp. Configure the Facelet's VIEW_MAPPINGS parameter:

<web-app>
    <context-param>
        <param-name>javax.faces.DEFAULT_SUFFIX</param-name>
        <param-value>.jsp</param-value>
    </context-param>

    <!-- Facelets pages will use the .xhtml extension -->
    <context-param>
        <param-name>facelets.VIEW_MAPPINGS</param-name>
        <param-value>*.xhtml</param-value>
    </context-param>     

    <servlet>
        <servlet-name>Faces Servlet</servlet-name>
        <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
    </servlet>

    <!-- Use prefix mapping for Facelets pages, e.g. http://localhost:8080/webapp/faces/mypage.xhtml -->
    <servlet-mapping>
        <servlet-name>Faces Servlet</servlet-name>
        <url-pattern>/faces/*</url-pattern>
    </servlet-mapping>
</web-app>
like image 200
BalusC Avatar answered Oct 23 '22 11:10

BalusC


The wiki section cited by BalusC seems to be indeed out of date. In my extension mapping (*.faces) setup I had the problem with the proposed javax.faces.DEFAULT_SUFFIX set to .jsp that generated action URLs inside form tags of *.xhtml pages got a .jsp extension instead of a .faces extension (and therefore could not be mapped).

After I stepped into the corresponding classes of the Apache MyFaces 2.x implementation (see org.apache.myfaces.shared.application.DefaultViewHandlerSupport.calculateActionURL(FacesContext context, String viewId)) the following setup turned out to work in our parallel use of JSP and Facelets View Handling.

How do I use Facelets and JSP in the same application?

Besides prefix mapping you may use extension mapping (e.g. *.faces) for the Facelets pages in order for this to work. Leave the DEFAULT_SUFFIX with the JSF default of .jsp .xhtml. Configure the Facelet's VIEW_MAPPINGS parameter:

<web-app>
    <context-param>
        <param-name>javax.faces.DEFAULT_SUFFIX</param-name>
        <param-value>.jsp .xhtml</param-value>
    </context-param>

    <!-- Facelets pages will use the .xhtml extension -->
    <context-param>
        <param-name>javax.faces.FACELETS_VIEW_MAPPINGS</param-name>
        <param-value>*.xhtml</param-value>
    </context-param>     

    <servlet>
        <servlet-name>Faces Servlet</servlet-name>
        <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
    </servlet>

    <!-- use extension mapping in this sample -->
    <servlet-mapping>
            <servlet-name>Faces Servlet</servlet-name>
            <url-pattern>*.faces</url-pattern>
    </servlet-mapping>
</web-app>

For those who are interested in the details of the processing of action urls inside org.apache.myfaces.shared.application.DefaultViewHandlerSupport.calculateActionURL(FacesContext context, String viewId):

        if ( mapping.isExtensionMapping() ) {
            // See JSF 2.0 section 7.5.2
            String[] contextSuffixes = _initialized ? _contextSuffixes : getContextSuffix( context );
            boolean founded = false;
            for ( String contextSuffix : contextSuffixes ) {
                if ( viewId.endsWith( contextSuffix ) ) {
                    builder.append( viewId.substring( 0, viewId.indexOf( contextSuffix ) ) );
                    builder.append( mapping.getExtension() );
                    founded = true;
                    break;
                }
            }
            if ( !founded ) {
                // See JSF 2.0 section 7.5.2
                // - If the argument viewId has an extension, and this extension is mapping,
                // the result is contextPath + viewId
                //
                // -= Leonardo Uribe =- It is evident that when the page is generated, the
                // derived
                // viewId will end with the
                // right contextSuffix, and a navigation entry on faces-config.xml should use
                // such id,
                // this is just a workaroud
                // for usability. There is a potential risk that change the mapping in a webapp
                // make
                // the same application fail,
                // so use viewIds ending with mapping extensions is not a good practice.
                if ( viewId.endsWith( mapping.getExtension() ) ) {
                    builder.append( viewId );
                } else if ( viewId.lastIndexOf( "." ) != -1 ) {
                    builder.append( viewId.substring( 0, viewId.lastIndexOf( "." ) ) );
                    builder.append( contextSuffixes[0] );
                } else {
                    builder.append( viewId );
                    builder.append( contextSuffixes[0] );
                }
            }
        } else {
            builder.append( mapping.getPrefix() );
            builder.append( viewId );
        }
like image 20
Florian Sager Avatar answered Oct 23 '22 13:10

Florian Sager


The above suggestion did not work at all for me. The wiki page is probably out of date. From the JSF2 specification I got the following parameter that worked:

  <!-- Facelets pages will use the .xhtml extension -->
  <context-param>
    <param-name>javax.faces.FACELETS_VIEW_MAPPINGS</param-name>
    <param-value>*.xhtml</param-value>
  </context-param> 

instead of:

<context-param>
    <param-name>facelets.VIEW_MAPPINGS</param-name>
    <param-value>*.xhtml</param-value>
</context-param>
like image 23
Karl Kildén Avatar answered Oct 23 '22 11:10

Karl Kildén