10 March 2011

JSF with Managed Beans and Dependency Injection and WebLogic Server

A question appears from time to time on various forums postings regarding the use of dependency injection within JSF Managed Beans when running on WebLogic Sever.  The usual problem reported is that the dependency injection simply does not work. 

A recent example of this is here:

http://forums.oracle.com/forums/thread.jspa?messageID=9418272&tstart=0#9418272

The Short Story

The short story is that WebLogic Server does indeed support the use of dependency injection, within Managed Beans in JSF applications.  The simplest way to get it to work is to use the documented mechanism of deploying and using the WebLogic Server supplied JSF shared-library, in which the WebLogic Server specific implementation of the com.sun.faces.spi.InjectionProvider class is supplied, and automatically configured as the InjectionProvider implementation on the Web container.

It is this WebLogic Server specific class -- com.bea.faces.WeblogicInjectionProvider – in which the actual dependency injection calls are realized.  Without this class being present, the dependency injection calls from JSF essentially become NOOPs.

See the documentation for more detailed instructions on how to deploy the JSF shared-library to WebLogic Server and reference it within applications.

Configuring JSF and JSTL Libraries
http://download.oracle.com/docs/cd/E17904_01/web.1111/e13712/configurejsfandjtsl.htm#i163440

The Longer Story

To provide support for multiple versions of JSF, WebLogic Server uses its it’s shared-library mechanism.  In a WebLogic Server installation, there are a set of “deployable-libraries” provided that can be deployed as libraries to a WebLogic Server domain to extend its base functionality, in this specific instance by providing a JSF runtime.

deployable-libraries 

The JSF 2.0 shared-library is represented by the jsf-2.0.war archive.  This archive contains the standard JSF and JSTL jar files, plus an additional library wls.jsf.di.jar

jsf-2.0.war

The wls.jsf.di.jar library contains a single class com.bea.faces.WeblogicInjectionProvider, which is the WebLogic Server specific implementation of the com.sun.faces.spi.InjectionProvider interface required to support dependency inject from JSF. 

Furthermore, WebLogic Server detects when JSF is present in a web application by examining if the “jsf” shared-library is referenced, or if the Faces Servlet is configured, and automatically sets the ServletContext parameter com.sun.faces.injectionProvider parameter to the com.bea.faces.WebLogicInjectionProvider class to specify the InjectionProvider to use.

** See http://blogs.sun.com/rlubke/entry/jsf_ri_1_2_and for the details of this standard JSF SPI mechanism.

wls.jsf.di.jar 

public class com.bea.faces.WeblogicInjectionProvider implements com.sun.faces.spi.InjectionProvider {


    public com.bea.faces.WeblogicInjectionProvider();


    public void inject(java.lang.Object)  throws com.sun.faces.spi.InjectionProviderException;


    public void invokePostConstruct(java.lang.Object)  throws com.sun.faces.spi.InjectionProviderException;


    public void invokePreDestroy(java.lang.Object) throws com.sun.faces.spi.InjectionProviderException;


}






Thus without this wls.jsf.di.jar library and the com.bea.faces.WeblogicInjectionProvider class it contains that implements the JSF dependency injection SPI, any dependencies declared in the JSF application are not able to be fulfilled.




Using WebLogic Server JSF Shared Libraries



The simplest way to use dependency injection in JSF with WebLogic Server is to follow the documented approach for deploying and using JSF shared-library as referenced above.  Once the shared-library is deployed, applications use it by providing a reference in a weblogic deployment descriptor to the JSF library.  At runtime, WebLogic Server will arrange to have the contents of the shared-library made available for the application to use.



For deployment of shared-libraries to WebLogic Server, the standard tools such as the console, or the weblogic.Deployer utility are used, specifying the deployment type as a library.



console-library



Screen shot 2011-03-10 at 1.26.17 PM



With the JSF shared-library deployed to WebLogic Server, applications can reference it using a weblogic deployment descriptor.



An example weblogic.xml deployment descriptor referencing the deployed JSF@2.0 shared-library is shown below.




<?xml version="1.0" encoding="UTF-8"?>


<weblogic-web-app xmlns="http://www.bea.com/ns/weblogic/90" xmlns:j2ee="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.bea.com/ns/weblogic/90 http://www.bea.com/ns/weblogic/90/weblogic-web-app.xsd">


  <jsp-descriptor>


    <keepgenerated>true</keepgenerated>


  </jsp-descriptor>


  <context-root>/WLS-JSF-EJB-DI-WEB</context-root>


    


  <library-ref>


    <library-name>jsf</library-name>


    <specification-version>2.0</specification-version>


    <implementation-version>1.0.0.0_2-0-2</implementation-version>


  </library-ref>  


  


</weblogic-web-app>




This is the documented and supported approach and is what we recommend based on the current architecture we use to support JSF.



Embedding JSF within a Web Application



A common arrangement for applications using JSF, is to provide the JSF jar files within the web archive itself, so that they are always available when the application is deployed.  It is this case typically where problems surface with dependency injection not working, since the WeblogicInjectionProvider class provider is not present, resulting in a NOOP when dependency injection calls are made.



If this embedding approach is to be used, then the undocumented (and daresay unsupported at this time) approach to getting dependency injection to work in JSF, is to extract the wls.jsf.di.jar file from the jsf-1.2.war or jsf-2.0.war files from a WebLogic Server installation, and put it into the WEB-INF/lib directory of the web application, alongside the JSF jars.  When the application is deployed, the WeblogicInjectionProvider will be available.  This works because the web application initialization code we have, in addition to looking at the shared-library references, also checks to see whether the Faces Servlet -- javax.faces.webapp.FacesServlet -- is configured in web.xml.  If so, it sets the InjectionProvider property appropriately on the ServletContext of the web application, delegating the dependency injection operations to the WeblogicInjectionProvider.



A Simple Example



Right, with that explained (hopefully) lets take a look at a simple example in NetBeans.



Here is a Java EE project with two modules: WLS-JSF-EJB-DI-WEB and WLS-JSF-EJB-DI-EJB:



netbeans-app



In WLS-JSF-EJB-DI-EJB there is a single EJB 3.0 stateless session bean defined as follows:




package oracle.com.demo.ejb;


 


import javax.ejb.Local;


 


@Local


public interface DateTimeLocal {


    String getCurrentDateTime();


    String getCurrentTime();


    String getCurrentDate();


    int getDateStyle();


    int getTimeStyle();


    void setDateStyle(int style);


    void setTimeStyle(int style); 


}




This purpose of this EJB is to return a formatted string representing the current date and time.  The formatting of the date is controlled via the DateStyle and TimeStyle properties.



In  the WLS-JSF-EJB-DI-WEB module, there is a single DateTimeManagedBean class, annotated with @ManagedBean (no faces-config.xml here!) and a single JSF facelet that uses the Managed Bean to displays the formatted date and time.  It also allows the user to change the formatting, again via the Managed Bean.



The Managed Bean class uses an @EJB annotation to inject an instance of the DateTimeLocal EJB, and then delegates all work to it, in order obtain the appropriately formatted date and time string. 




package oracle.com.demo.web.beans;


 


import javax.ejb.EJB;


import javax.faces.bean.ManagedBean;


import oracle.com.demo.ejb.DateTimeLocal;


 


@ManagedBean


public class DateTimeManagedBean {


    


    @EJB


    DateTimeLocal dateTimeEJB;


    


    public int getDateStyle() {


        return dateTimeEJB.getDateStyle();


    }


    


    public int getTimeStyle() {


        return dateTimeEJB.getTimeStyle();


    }


    


    public void setDateStyle(int style) {


        dateTimeEJB.setDateStyle(style);


    }


    


    public void setTimeStyle(int style) {


        dateTimeEJB.setTimeStyle(style);


    }    


    


    public String getCurrentDateTime() {


        return dateTimeEJB.getCurrentDateTime();


    }


    


    public String getCurrentDate() {


        return dateTimeEJB.getCurrentDate();


    }


    


    public String getCurrentTime() {


        return String.format("%s", dateTimeEJB.getCurrentTime());


    }


 


    public String applyFormats() {


        return "index.xhtml"; // 


    }


    


}



 









The index.xhtml facelet uses the Managed Bean to sets and apply the formatting properties and obtain the current date and time in the desired format.



Finally, a weblogic.xml file is provided in the WEB-INF directory that specifies the use of the jsf#2.0 shared-library. 



** NetBeans offers great support for WebLogic here.  When you add the “JSF Framework” to a project that is configured to run on WebLogic Server, NetBeans automatically offers you the choice of JSF implementations it is aware of on the server and generates the weblogic.xml file.  It will also transparently deploy the specified JSF shared-library to the target WebLogic Server domain if it is not already deployed. 



When deployed to WebLogic Server 10.3.4, the resulting page looks like this:



app1 



Changing the format properties and applying them, the Managed Bean gets updated, which in turn makes the changes on the DateTimeLocal EJB, which ultimately returns the date and time in the specified format:



 app2



This simple application demonstrates the successful use of JSF with a Managed Bean, which injects and uses an EJB 3.0 stateless session bean.



I creates this sample application to assist an OTN question that was asked – the project can be be downloaded from here: http://bit.ly/wlsjsfejb.

9 comments:

Anonymous said...

Thank You very much. This is a very detailed explanation and helped me a lot!!!

Chathura Asanga said...

This should be truly appreciated! Each and every single thing has been well discussed in detail, and precisely, this blog is such a worthy learning source!!!!

Buttso said...

Thanks, I'm glad it was of some help to you.

-steve-

susDev said...

Hi Steve,
I am following exactly what you have said still encountering the same problem.

My conf : weblogic 10.3.4 , netbeans 7

1. I have added wls.jsf.di.jar to my library.
2. I see jsf 2 deployed in weblogic admin console.
3. weblogic.xml is all fine.

But still deployment fails . I get the following error message
"
The ejb-ref does not have an ejb-link and the JNDI name of the target bean has not been specified.
"

Any idea where i am getting wrong.

Triste Rey Billy said...

Many Thanx! You saved my life ;-)

Anonymous said...

Thanks for the tip. However, there is no wls.jsf.di.jar in jsf-1.2.jar in Weblogic 10.3 version. Maybe Weblogic 10.3 doesn't support DI?

Buttso said...

Possibly. I haven't used 10.3, it pre-dates my WLS experienced.

It's definitely in jsf-1.2.war in the latter releases, here's 10.3.5 for instance:

sbutton:~/Java/wls-1035-dev/wlserver/common/deployable-libraries $ jar tf jsf-1.2.war
META-INF/
META-INF/MANIFEST.MF
WEB-INF/
WEB-INF/lib/
META-INF/javadoc.mf
WEB-INF/lib/glassfish.jsf_1.0.0.0_1-2-15.jar
WEB-INF/lib/glassfish.jstl_1.2.0.1.jar
WEB-INF/lib/javax.jsf_1.1.0.0_1-2.jar
WEB-INF/lib/wls.jsf.di.jar
WEB-INF/web.xml

Anonymous said...

Steve,
I need to use JSF 2.2 with CDI but WLS 12c supplies only JSF 2.1.
Could you please share steps that should be followed.

Buttso said...

Updating to JSF 2.2 is a little trickier, particularly when CDI is involved.

The simplest but unsupported way to do it is to follow the instructions that the Mojarra team have posted @ https://weblogs.java.net/blog/edburns/archive/2014/02/14/how-overwrite-version-mojarra-wls-1212-and-beyond.

This will replace the JSF version within the WLS installation, setup to work correctly with CDI and other forms of DI.

Please not that this is unsupported but does provide you with an option to use JSF 2.2 on WLS for research/development purposes.