This blog states my personal opinions and are not representative of IBM or the WebSphere branded products.

Thursday, November 3, 2011

MyFaces 2.0 and WebSphere Application Server v7

JavaServer™ Faces (JSF) 2.0 was designed to work with Java EE 5 application servers.  The problem is that annotation processing and injections are not portable as written by the specs.  Each implementation of JSF has proprietary ways of plugging into an application server’s injection engine and most perform their own annotation scanning.  The following article will guide you through setting up MyFaces 2.0 on WebSphere Application Server, using a newly delivered annotation provider (as of fix pack 7.0.0.19) to give you built in injection engine support.

Setting up the MyFaces 2.0 binaries

Go to the MyFaces download page (http://myfaces.apache.org/download.html) and find the MyFaces Core 2.0.x compressed file that you would like to use.   Download and extract the files to a directory.  Look for a lib folder in the root directory.  The lib folder contains the jar files to create a WebSphere Application Server isolated shared library.  To begin, remove the ServletContainerInitializer and the Tomcat LifeCycleProvider that comes with MyFaces 2.0. 

ServletContainerInitializers are new to Servlet 3.0 and are not supported on WebSphere Application Server  Version 7.  Leaving ServletContainerInitializers  in the services folder of MyFaces will not hurt anything, as it will not be loaded.  MyFaces added this initializer to register the FacesServlet if it found a faces-context.xml in an application.  This means that in WebSphere Application Server Version7 you   define the FacesServlet in your web.xml file, as you would for a JSF 1.2 or earlier application. 

The org.apache.myfaces.config.annotation.LifecycleProvider that comes with MyFaces is specific to Tomcat and should be removed.  You will replace it with one that defines a LifecycleProvider and a LifecycleProviderFactory that were delivered in WebSphere Application Server  Version 7.0.0.19. 
Open up the myfaces-impl-2.0.x.jar file and remove the files in the META-INF\services\ directory. 
When you have completed that step, copy all of the JAR files from the lib directory to a common place on your server where you want to store them.  For this article, the JAR files are copied to ${WAS_INSTALL_ROOT}\optionalLibraries\Apache\MyFaces2.0.2.

When you are finished copying the JAR files, you should have a directory that looks similar to Figure 1.0.  Note: The jars that are delivered with different versions of MyFaces 2.x might not be exactly the same. 

Figure 1.0 ${WAS_INSTALL_ROOT}\optionalLibraries\Apache\MyFaces2.0.2 directory contents


Configuring WAS v7 shared libraries

Next, we configure the JAR files as Isolated Shared libraries.  Isolated Shared libraries have their own classloader that is shared between your applications.  These classloaders are always set to ‘PARENT_LAST’, meaning the classes in these libraries come before any parent classloader classes in the classpath.  You can apply these classloaders to different modules of your application and they will override any runtime classes.  In this manner, we can override the JSF implementation that comes with WebSphere Application Server Version 7 for any application web modules that your Isolated Shared library is applied to.  You will no longer need to set the classloader for your application or its web modules to ‘PARENT_LAST’ when using Isolated Shared libraries.   WebSphere Application Server Version 7 also uses the classloaders to determine if the application has its own implementation of JSF configured, and if so, it will not initialize the JSF implementation in the runtime. 

Log in to your WebSphere Application Server Version 7 administrative console and click on the Environment section of the left hand navigation menu.  Next, click on the Shared libraries link.  Choose the scope that you would like to create the Shared Library for in the dropdown menu and then click the New Button.  Be aware if you choose a scope outside of a single physical machine, you will need to make sure the MyFaces JAR files are manually copied to every machine.  Give your Shared Library a Name, such as, MyFaces 2.0,and add all of the JAR files to the Classpath field, making sure to separate each entry with a new line.   You can use WebSphere Application Server variables, such as ${WAS_INSTALL_ROOT}, to give common paths across machines.  There is a WebSphere-MyFaces20-annotation-provider.jar file that also should be added to your Shared Library.  This JAR file contains the new annotation provider classes and the services files to register them with MyFaces 2.0.  NOTE: This JAR file was added as of WebSphere Application Server Version 7.0.0.19.  The JAR file is located in the ‘optionalLibraries/IBM/JSFProviders’ directory of your WebSphere Application Server installation.  Add the following string to the Classpath of your Shared Library:
${WAS_INSTALL_ROOT}/optionalLibraries/IBM/JSFProviders/WebSphere-MyFaces20-annotation-provider.jar 

Click on the check box for ‘Use an isolated class loader for this shared library’.  Click Apply and Save.  Figure 2.0 shows what your panel should look like.
 Figure 2.0 WebSphere Admin Console screen shot for shared library.  

Configuring your application

Now you are ready to configure your application.  First make sure you have the FacesServlet and the MyFaces StartupConfigureListener defined in the web.xml file of your modules.  See Figure 3.0 for an example.  You need the FacesServlet since, as mentioned previously, the ServletContainerInitializers are not supported on Java EE 5 application servers.  You need the StartupConfigureListener because WebSphere Application Server Version 7 does not support loading of listeners from tld files in Shared Libraries.  Once you have your web.xml file configured, install your JSF 2.0 application in WebSphere Application Server Version 7. 

Figure 3.0 Web.xml

Now you are ready to add the Isolated Shared library to your application.  After you install your application, go to the Applications section in the left hand navigation menu and click on the ‘WebSphere enterprise applications' link.  In this panel, click the ‘Shared library references’ link.  You should see a list of your application’s modules in a table.  Check the box next to the web module you want to use JSF 2.0 with and then click the ‘Reference shared libraries’ button at the top of the table.  In the next panel you should see your MyFaces 2.0 shared library listed in the Available field.  Select it and click the right-arrow button to move it to the Selected list.  Click OK and save.  Figures 3.1 and 3.2 show you what the panels should look like when you are finished.  Repeat these steps for every web module that you want to use JSF 2.0 with.  After you configure the shared library with your application, start the application and start making requests.  You should see that your JSF 2.0 annotations are being injected properly.

Figure 3.1 Shared Library Mapping Panel

Figure 3.2 Shared library references Panel

As you can see, it is fairly simple to configure MyFaces 2.0 with WebSphere Application Server Version 7.  To see JSF 2.0 fully integrated into the WebSphere Application Server runtime, take a look at WebSphere Application Server Version 8, which is an IBM full Java EE 6 application server.  Here is a link to the WebSphere Application Server Version 8 InfoCenter samples gallery that includes some JSF 2.0 samples.


17 comments:

  1. Quick update. We just found that in MyFaces 2.0.8, there was a major package change that breaks the WAS annotation provider factory. Please use a version before MyFaces 2.0.8 until we can get this resolved.

    ReplyDelete
  2. Using MyFaces 2.0.7, I get a ClassNotFoundException for org.apache.myfaces.webapp.StartupServletContextListener

    Is that asymptomatic of not having an old enough library, or have I not configured WSP correctly?

    ReplyDelete
    Replies
    1. This comment has been removed by the author.

      Delete
    2. Hello,

      I've exactly the same problem.
      Did you solve it ?

      Thanks

      Delete
  3. When trying this on 7.0.0.21 I am getting this error, any ideas?

    An error occured while initializing MyFaces: com.ibm.ws.jsf.config.annotation.WebSphere20LifecycleProviderFactory incompatible with org.a│
    │pache.myfaces.config.annotation.LifecycleProviderFactory

    ReplyDelete
    Replies
    1. I was able to get it to work by REMOVING the reference to WebSphere-MyFaces20-annotation-provider.jar

      Delete
  4. I was able to add sucessfully the myfaces JARS but can´t seem to use component libraries. I think it has something to do with the following error when i run the portlet project this error appears :
    "Cannot set content type. Response already committed".

    Thanks

    ReplyDelete
    Replies
    1. This error messages appears to me, but it don't generate unexpected behavior. It is like a normal log or jsf2 bridge ignores it.

      Delete
  5. Can we use the approach for jsf1.1 libraries.

    ReplyDelete
  6. I follow the readme.pdf on JSF 2 Bridge from Green House and it worked well for me. I am passing this link to my WS7 admin to config stuffs on another environment.

    Stephen, did you know if web neeed to do some config to make .xhtml publish on update? I've noticed that it only work for .jsp files, and .xhtml is the default extension for JSF2/Facelets. What surprises me is the fact that JSF1.2/Facelets work fine on save/publish.

    ReplyDelete
  7. It´s not working. I got the follow error too:
    [28/11/12 13:21:26:489 BRST] 00000009 annotation W com.ibm.ws.webcontainer.annotation.WASAnnotationHelper collectClasses unable to instantiate class
    java.lang.ClassNotFoundException: org.apache.myfaces.webapp.StartupServletContextListener
    at java.lang.Class.forNameImpl(Native Method)
    at java.lang.Class.forName(Class.java:169)
    at com.ibm.ws.webcontainer.annotation.WASAnnotationHelper.loadClass(WASAnnotationHelper.java:725)

    ReplyDelete
  8. I have worked with the WAS team and had them update the WebSphere Infocenter to include this article and to also keep it up to date with the release as the implementation code in WAS for loading JSF changes. Here is the current link to that article. Please let me know if you are having any issues and I can direct them to the WAS JSF team. Thanks!

    http://www14.software.ibm.com/webapp/wsbroker/redirect?version=compass&product=was-express-iseries&topic=tweb_jsf_annotation

    ReplyDelete
  9. your giving such a nice information on ibm websphere mq and its relly usefull . WEBSPHERE Online Training.

    ReplyDelete
  10. Is there any special reason why you chose MyFaces instead of Mojarra for the JSF 2.0 spec?

    ReplyDelete
    Replies
    1. For the purposes of using a 3rd party impl of JSF with WAS, you could always use Mojarra. I chose MyFaces just because in the next release of WAS, MyFaces 2.0 was supported. It gave a clearer migration path onto the supported stack. Also, in WAS v8.x, MyFaces is bound into the other EE specs, such as CDI.

      Delete
  11. Hi. Thanks again for your help. I followed your advice, and this works fine when I use a single server environment. However, I need to set this up on a load balanced environment (2 different WAS servers). When I use this, I eventually get a lot of ViewExpiredException messages. We do have sticky sessions and all the needed configuration in the App Server (This works for other JSF 1.2 applications we have). Do you have any idea of how this could be solved, if possible at all? I'm using MyFaces 2.1.10, but might also consider moving to Mojarra if that is useful at all.
    Thanks again.

    ReplyDelete
  12. The same approach worked for MyFaces 2.2.2 on WAS 8.5.5.1. Thanks!

    ReplyDelete