As I was preparing for my Devoxx presentation next Monday, I decided to look at the somewhat harder way of integrating a JPA based business tier into a JavaServer Faces web tier. The easy way – when using the ADF 11g framework in JDeveloper 11g is creating a Data Control for the Session Facade Bean. The Web Application can create data bindings for entities, entity collections and operations exposed in the Session Facade Bean that completely hide the injection or lookup details from the web tier developer. It’s the ADF responsibility to find the session bean and manage references to it.

However, if you do not use ADF, you need to establish the link between the Web Application and the JPA Business Service yourself.

The JEE 5 way of achieving this consists of a few simple steps – on top of the JPA entity definitions:

2. Publish the session bean face as Stateless (or Stateful) Session Bean using a few simple annotations (@Stateless, @Stateful, @Remote, @Local) and deployment to a JEE 5 compliant container; this session bean gets injected by the container with an EntityManager that is uses to perform operations on the Entities (annotated classes that map to database tables)

3. Have the container inject the reference to the (Stateless) Session Bean into the Web Application artefact; rely on the container to locate the session bean and through dependency injection set the reference on a private member in a class in the web application

The injection by the container into the Web Application can be achieved in a very simple way – in theory at least – using the @EJB annotation. The following code ties the application together across the tiers, all handled by the container:

In the doGet() method, the hrmFacade member is available, initialized by the container and ready to provide data and operations defined in the Session Bean using the EntityManager that leverages container specified data sources to connect to a database. With little effort and almost no configuration, the data-bound web application is created.

Ideally, in JSF applications, the injection of the Session Bean would be directly into Managed Beans. Unfortunately, that does not seem to work in JDeveloper 11g with WebLogic 10.3 and JSF 1.2. I have seen some indications on the internet that this used to be a known issue – injection for the @EJB annotation only worked for resources configured in the web.xml file – such as ServletListeners, ServletFilters, Servlets.

One way of working then would be to have the container inject the Session Bean reference(s) into for example a ServletListener and have the ServletListener store those references in the servlet context. Each managed bean could then, upon instantiation, retrieve the references it needs from the servlet context and from that moment on work with them as if they had been injected directly into the managed bean. This fairly elegant approach leaves the responsibility for locating the Session Beans entirely with the container. (note: this approach was descibed by Jocelyn Demoy in his article http://softquipeut.blogspot.com/2007/12/injection-dun-ejb-dans-un-back-bean-jsf.html). The steps:

public class HrmManagerBean {
private HRMFacade hrmFacade; // without the @EJB annotation as the WL 10.3 container does not seem to be able to inject the Session Bean (Facase) reference into a JSF managed bean
// have the HRMFacade reference established in the constructor
public HrmManagerBean() {
javax.faces.context.ExternalContext ex = javax.faces.context.FacesContext.getCurrentInstance().getExternalContext();
ServletContext sc = (ServletContext)ex.getContext();
hrmFacade = (HRMFacade)sc.getAttribute(&quot;HRMFacade&quot;);

Another approach is the slightly more old-fashioned way of getting the Session Bean reference from the Context inside the managed bean:

public class HrmManagerBean {
private HRMFacade hrmFacade; // without the @EJB annotation as the WL 10.3 container does not seem to be able to inject the Session Bean (Facase) reference into a JSF managed bean
// have the HRMFacade reference established in the constructor
public HrmManagerBean() {
final Context context;
try {
context = new InitialContext();
hrmFacade = (HRMFacade)context.lookup(&quot;HumanResourceManager-SessionEJB#nl.amis.hrm.model.HRMFacade&quot;);
} catch (NamingException e) {
}
}
.. make happy use of the hrmFacade in the methods of the (managed) bean class

Discussion on BEA forum on EJB DI into JSF and a workaround (replacing the jsf 1.2 jar files): forums.bea.com/thread.jspa (note: this entry seems no longer available, I had to get it from the Google Cache. Part of the content: "… – WL 10MP1 supports DI in JSF. The trick here is to use bundled JSF implementation. It looks like SUN RI 1.2, but contains an extra entity resolver which is WL10 specific. The easiest way to get DI working is to make a surgery on bundled war (I stress that it’s war not jar) of jsf 1.2 and cut jsf-api and jsf-imlp from there and put them into the libs of your app. Other solutions include putting them to lib of the server and linking via WL vendor specific descriptor. …"

meta

Subscribe to Blog via Email

Enter your email address to subscribe to this blog and receive notifications of new posts by email.

Join 206 other subscribers

Email Address

About

AMIS is internationally recognized for its deep technological insight in Oracle technology. This knowledge is reflected in the presentations we deliver at international conferences such as Oracle OpenWorld, Hotsos and many user conferences around the world. Our AMIS Technology Blog, the most referred Oracle technology knowledge base outside the oracle.com domain. However you arrived here, we appreciate your interest in AMIS. Link to our Google+ Profile AMIS