Facelets and legacy JSP

28 April 2010, by: Development

It’s well known that Facelets is the far superior technology when it comes to authoring pages using JSF. By default, Facelets has no provisions to include content from JSP pages, or Servlets for that matter. Normally this really isn’t needed. Facelets provides a better and clearer templating mechanism than what JSP has ever offered.

Facelets & JSP in one app

However, when migrating a large application you might have to run a while in mixed-mode, that is running with both Facelets and JSP pages in a single application. It ain’t pretty, but it is explicitly supported. Ever wondered why you are forced to use prefix mapping for this? Well, the Facelets view handler delegates to the default view handler for createView, which transforms a view ID suffix like .jsf or .xhtml to a default one (e.g. .jsp), but leaves the suffix alone when using a prefix mapping like /faces/*. The Facelets viewhandler later decides to handle a request itself or delegate again to the default view handler, based on the suffix. When using suffix mapping, the first delegation had just caused this suffix to be replaced with the default suffix and the Facelets view handler thus can’t make any distinction between a Facelets request and a JSP request anymore.

The above is thus why you have to use prefix mapping for Facelets pages if you want to use both Facelets and JSP in a single application.

JSP includes

Having Facelets and JSP pages in 1 application might be only half of the story. It’s not unlikely that the existing JSP pages make use of included resources that are also JSP based, or maybe Servlet based. Rewriting these to full-fledged Facelets artifacts is technically the best option, but if you have to run in mixed-mode for a while, this means you have to maintain two versions of these includes. Obviously maintaining two separate versions is not ideal too.

One alternative, that I like to present here, is building a bridge component that executes the JSP or Servlet and writes its output to the standard JSF response writer. Thanks to Facelets and JSF in general, such a component is actually not that hard to build:

The component’s source code:



public class JSPIncludeComponent extends UIComponentBase {

public String getFamily() {
   return "components.jsp.include";
}

public void encodeBegin(FacesContext context) throws IOException {
   try {
      ExternalContext externalContext = context.getExternalContext();
      HttpServletRequest request = (HttpServletRequest) externalContext.getRequest();
      HttpServletResponse response = (HttpServletResponse) externalContext.getResponse();

      // Create dispatcher for the resource given by the componen's page attribute.
      RequestDispatcher requestDispatcher = request.getRequestDispatcher((String) getAttributes().get("page"));

      // Catch the resource's output.
      CharResponseWrapper responseWrapper = new CharResponseWrapper(response);
      requestDispatcher.include(request, responseWrapper);

      // Write the output from the resource to the JSF response writer.
      context.getResponseWriter().write(responseWrapper.toString());
   }
   catch (ServletException e) {
      throw new IOException();
   }
}
}

The component here gets its content from the resource path denoted by the attribute “page”. To JSF, there is no difference between content that is generated locally in the component and content that the component obtained from somewhere else.

The component makes use of a HttpServletResponseWrapper, which is a fairly common artifact in many legacy Servlet/JSP applications. For completeness, here is the source of the particular implementation I used:



public class CharResponseWrapper extends HttpServletResponseWrapper {

   private CharArrayWriter output;

   @Override
   public String toString() {
      return output.toString();
   }

   public CharResponseWrapper(HttpServletResponse response) {
      super(response);
      output = new CharArrayWriter();
   }

   public CharArrayWriter getCharWriter() {
      return output;
   }

   @Override
   public PrintWriter getWriter() {
       return new PrintWriter(output);
  }

   @Override
   public ServletOutputStream getOutputStream() {
      return new CharOutputStream(output);
   }

   public InputStream getInputStream() {
      return new ByteArrayInputStream( toString().getBytes() );
   }
}

class CharOutputStream extends ServletOutputStream {

   private Writer output;

   public CharOutputStream( Writer writer ) {
      output = writer;
   }

   @Override
   public void write(int b) throws IOException {
      output.write(b);
   }
}

In JSF 1.2 there’s a minor inconvenience where you have to register the component you just created in an .XML file. JSF 2.0 provides a convenient annotation for this, but in JSF 1.2 it has to happen via XML:


<?xml version="1.0" encoding="UTF-8"?>
<faces-config 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-facesconfig_1_2.xsd"
    version="1.2"
>      
	<component>
		<component-type>com.example.component.JSPIncludeComponent</component-type>
		<component-class>com.example.component.JSPIncludeComponent</component-class>
	</component>

</faces-config>

This can either be put in your regular faces-config.xml, or in a separate faces-config.xml in a META-INF directory on your class-path. The latter option is typically when packaging in a jar, but also works for any regular Java source dir of your web module.

To make the component usable on a Facelets page, we only have to assign it a name space and a tag name. This has to happen in a file with a suffix .taglib.xml that’s also in a META-INF directory on your class-path. Even in JSF 2.0, there are unfortunately no annotations for this. For this example I called the file foo-include.xml:


<!DOCTYPE facelet-taglib PUBLIC "-//Sun Microsystems, Inc.//DTD Facelet Taglib 1.0//EN" "http://java.sun.com/dtd/facelet-taglib_1_0.dtd">

<facelet-taglib> 
	<namespace>http://foo.com/jsf</namespace> 

	<tag>
	  <tag-name>include</tag-name>
	  <component>
	    <component-type>com.example.component.JSPIncludeComponent</component-type>
	  </component>
	</tag>

</facelet-taglib>

Note that this example uses the older DTD for the standalone Facelets implementation for JSF 1.2. JSF 2.0 uses a more modern xsd, for which an example can be seen here. Also note that we don’t have to define any attributes nor did we had to define any getters and setters for those attributes on the UI component implementation. This convenience does come at a cost though, as your IDE now can’t provide you with any content assist for the component’s attributes.

Finally an example of how it all comes together on an actual Facelets page:


<?xml version="1.0" encoding="UTF-8"?> 
<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page"
   xmlns:ui="http://java.sun.com/jsf/facelets" 
   xmlns:h="http://java.sun.com/jsf/html"
   xmlns:foo="http://foo.com/jsf"
   version="2.1"
>	
	<ui:composition>
		<html xmlns="http://www.w3.org/1999/xhtml">

			<head>    
				<title>JSP include example</title>
				<meta http-equiv="pragma" content="no-cache"/>
				<meta http-equiv="cache-control" content="no-cache"/>
				<meta http-equiv="expires" content="0"/>	
			</head>  

			<body>				
				JSP: <br/>
				<foo:include page="/test.jsp"/><br/><br/>

				SERVLET: <br/>
				<foo:include page="/TestServlet"/><br/><br/>				    		
			</body>
		</html>

	</ui:composition> 

</jsp:root>

I wouldn’t recommend using this as a lasting solution, but it might ease a migration from legacy JSP with smelly scriptlets and all on them to a more sane and modern Facelets application.

Arjan Tijms

18 comments to “Facelets and legacy JSP”

  1. john draper says:

    Apart from the actual purpose of the component, this also shows how relative easy it is to define a java based custom component in jsf.

    It would be even better if the facelet tag could be generated too from an annotation. The tag attributes could be deduced from annotated getters/setters.

  2. Tom says:

    I’ve worked with jsp and facelets and JSF and Seam and I can tell you, I’d take a dynamically typed language like Ruby, Python or Groovy + jQuery anyday.

    I’m not bringing this up to be negative I’m just kinda curious why in 2010 people are still using JSF when easier to use technologies like Groovy + jQuery are available.

  3. development says:

    Tom, to each his own. We really like JSF and are very productive with it. JSF 2.0 that we started to use in small test projects, works like a charm. Next to that there are tons of high quality components available for it.

    We also like Python a lot. One of our developers builds various plug-ins for Edgewall’s Trac.

    Groovy is very interesting as well. I don’t really understand why you compare JSF with Groovy though. JSF is a web framework and Groovy is a language. You can easily build JSF backing beans with Groovy. As a matter of fact, I’m currently experimenting with just that ;)

  4. Tom says:

    I compare Groovy/JQuery with Java/JSF because they are both technologies used to build similar things – Web apps. Plus, there are “components” that I can build using jQuery in a gsp page that IMO are just as powerful as anything I’ve seen in JSF.

    But yea to each his own. I guess I’m still a bit irrationally hostile at the J2EE world that made things too harder to do ;)

  5. Tom says:

    As an example, every day I find a new awesome widget in jQuery. Check out this “bubble” menu:

    http://tympanus.net/Tutorials/BubbleNavigation/#

  6. development says:

    The bubble widget surely is cool Tom, thanks for the pointer ;)

    The point of JSF is not so much that it somehow ‘creates’ widgets like that on the server, but that it provides a server side component interface for exactly those kind of cool widgets that jQuery provides.

    With JSF, I could very easily attach a Java or Groovy backing bean that reacts to events of that bubble widget or the other way around, feed the widget with data coming from the backing bean. So, JSF doesn’t aim to compete with jQuery or other powerful javascript libraries at all. On the contrary, it embraces these technologies fully and ‘only’ aims to provide a server side component interface for them and offers the programmer an easy way to compose complicated pages via parts (templating aka composition or tiling).

    See for example this component: http://www.primefaces.org:8080/prime-showcase/ui/terminalHome.jsf or any of the other examples on that page. Those are Javascript widgets with an easy server side component ‘interface’.

    I understand some hostility at J2EE. At Jdevelopment this is what we started out with. JSP, JSTL , early JNDI, EJB2 and the needlessly verbose XML were all a pain to work with.

    But Java EE is almost like a completely different platform; very light weight and really friendly towards open source and projects from the community. As said, with JSF we embrace all the best that’s available in Javascript libraries and it’s trivial to write the backing bean in Groovy, or if you don’t need the extra abstraction layer skip the backing bean entirely and have your UI components bind directly to your business classes.

  7. Insert page jsp in facelets « Raphael Rodrigues – Java Technical Blog says:

    [...] i found this solution . I really thought  a pretty solution, but unfortunatelly this solution was not enough for me. This [...]

  8. Alexander Rühl says:

    Hello,
    I was happy to find your article – but there must be something wrong when trying to use it in my application, so I do hope you still see the reactions to the article.
    Here’s the problem:
    I created the 2 classes JSPIncludeComponent and CharResponseWrapper as listed above, added the component definition in WEB-INF/faces-config.xml, added a file META-INF/foo-include.xml with the listed content, and used an xhtml test page with the include reference to a jsp test page.
    I deployed the war file to a Tomcat 6.x which uses Mojarra JSF 1.2.
    Now when I load the xhtml page, I don’t see the content of the JSP and if I take a look at the source of the page the is still in there and not replaced by other content.
    I then adapted the web.xml as referred to in the beginning of the article (as I’m not sure if it was necessary) and used *.taglib.xml as suffix for taglib include file.
    I guess there’s still a point I missed, but I don’t know which – so can you help me out there please? What can cause the tag not to be processed?
    Thanks a lot in advance,
    regards Alex

  9. Alexander Rühl says:

    Small addition to my post: There was one thing eaten up by the comment processor of this website:
    In line 11 it should say
    …source of the page the foo:include tag is still in there…

  10. Alexander Rühl says:

    Me again – it worked after adding
    param-name facelets.LIBRARIES
    param-value /WEB-INF/tags/foo-include.taglib.xml
    as context-param in web.xml.
    Is it just my setup or was that step missing in the description?

  11. development says:

    Sorry for the late reply, I indeed don’t automatically receive responses anymore for older articles.

    Normally, it should have worked if your foo-include.taglib.xml is in a META-INF package on your class-path. This is also how component libraries package this file. You don’t *have* to create the web.xml entry then.

    Maybe you stored the file in a META-INF directory that wasn’t on the class-path, or maybe you put it there when it was still called something else? For the automatic pick-up to work, both conditions need to be satisfied: on the class-path AND having the right name.

    If for some bizarre reason this is not working for you, explicitly putting it in web.xml is a fallback that always works. Glad you found it :)

  12. Lin says:

    I am glad to find this article. Thank you very much!

  13. JoSeTe says:

    At first I was scared because I thought I had to develop my own custom JSF 1.2 Component… but thanks to this page and Facelets everything went fine ! :D Thank u very much.

  14. André Fróes says:

    I’ve tried several ways of doing this, and no success, I even tried the solution of Alexander Rühl, but it is not working.
    Can you attach a war in the post so we can see how it works properly?
    My problem:
    I’ve created the 2 classes above, no problem there, i put the foo-include inside meta-inf and then make the page (working with JSF2.0) with jsp and xhtml extensions, none of it worked. I’m getting this error:

    XML Parsing Error: prefix not bound to a namespace

    Location: https://localhost:8080/direc/lista-funcionarios2.jsp

    Line Number 1, Column 1:JSP include example

    I’ve tried everything but still no success. I added the context-param as he said to, but same error keeps comming.

    My current situation: I work in a company that refuses to change the scriplet “technology” + odbc, i implemented jpa and they liked, now bit by bit i want to make them see that JSF is much better to work with and more productive. But I must implement it in jsp for now.

    I appreciate any help
    Nice post btw

  15. jesus says:

    Well Andre. I also had same problem, I have to include a old header jsp into a new webpage jsf, so …. this solution sucks because the order rendering the tree of the components in JSF and JSP is totally different, I would advise you to try that with a iframe, like this:

    Any way if u still thinking to create your own component, this tuturial WORKS, but remember to add the component in the web.xml adding next lines:

    javax.faces.FACELETS_LIBRARIES
    /WEB-INF/JSPIncludeComponent.taglib.xml

    But the result … you will see, probably is not what you are specting.

    Kind regards. publicdinamipi[at]gmail.com

    Ah! I forgot to tell u that every custom component should be created by agreement with the class Name like: HtmlJSPIncludeComponent.java and not JSPIncludeComponent.java

  16. jesus says:

    Damn! XML labels are missing in my last comment. lets type the code one more time:

    
    	 
     		javax.faces.FACELETS_LIBRARIES
      		/WEB-INF/JSPIncludeComponent.taglib.xml
     	 
    
  17. jesus says:
    <context-param>
        <param-name>javax.faces.FACELETS_LIBRARIES</param-name>
        <param-value>/WEB-INF/HtmlCustomComponent.taglib.xml</param-value>
    </context-param>

    [edit admin: hope it works now]

  18. arjan tijms says:

    I have to include a old header jsp into a new webpage jsf, so …. this solution sucks because the order rendering the tree of the components in JSF and JSP is totally different

    Normally it would be different, but in this case the component will simply render whatever the JSP outputs. So, if the JSP outputs just “bla” and you insert the component on a Facelet below the literal text “foo” and above “bar”, then the output will be “foo” “bla” “bar”.

    While we were migrating our site (www.m4n.nl) from JSP to Facelets, we actually went into production with the very component described in this post. The footer as well as the left-side part of the page was rendered by the JSPIncludeComponent.

Type your comment below:


1 × = six

css.php best counter