Thursday, 23 September 2010

Basic EJB References, Injection and Lookup

Table of Contents


In the first part of this series we've introduced the mechanisms provided by the Enterprise JavaBeans v. 3.0 Specification to define EJB components, declare a reference to an EJB and wiring them up both by dependency injection or programmatic JNDI lookup.

In this blog post we'll examine some basic examples to understand how to use the EJB API.

A Basic EJB

An EJB is basically a POJO with some extra EJB metadata. The required metadata to deploy it as an EJB component can be provided both by using the EJB annotations or by the standard deployment descriptor. The following class implements a very basic stateless session EJB:

package es.reacts;

import javax.ejb.Stateless;

@Stateless(name = "UniqueLocalSessionEJB")
public class UniqueLocalSessionEJBBean implements UniqueLocalBusinessInterface {
    public UniqueLocalSessionEJBBean() {
    }
    
    public String sayLocalHello() {
      return this.getClass().getName() + "::" + "Local hello.";
    }
}

As you may recollect from our previous blog post, the @Stateless annotation is used to define a stateless session bean. The optional name element is used to define the session bean name. This element is analogous to the <ejb-name/> element of the standard deployment descriptor. This element defaults to the unqualified name of the bean class (UniqueLocalSessionEJBBean in the example above), and the example above uses it to rename the bean to UniqueLocalSessionEJB.

Since we're using the @Stateless annotation, there's no further need to declare the EJB in the deployment descriptor.

In this example, we're assuming that the EJB is packaged in an EJB module that depends on the module containing the definition of its business interface (as explained in the following section.)

Business interfaces

Every EJB implements one or more business interfaces. Business interfaces can be local or remote. The most important differences between the two types of business interfaces can be summarized as follows:
  • Local business interfaces use pass-by-reference semantics for their methods and method invocations cannot cross the JVM boundary. Local business interfaces are available only to callers in the same application and JVM instance of the callee.
  • Remote business interfaces use pass-by-value semantics for their methods and method invocations can cross the JVM boundary. Remote business interfaces are available to callers outside the application of the callee.

In the previous example, the business interface UniqueLocalBusinessInterface is declared as follows:

package es.reacts;

import javax.ejb.Local;

@Local
public interface UniqueLocalBusinessInterface {
    String sayLocalHello();
}

In the EJB v. 3.0 world a business interface is just a plain old Java interface annotated with either the @Local or @Remote annotation.

Packaging Business Interfaces

In this example we're assuming that the EJB business interface is packaged in a JAR file that the EJB module depends on. Since EJB clients only depend on an EJB business interface, it's a good practice to package the business interfaces in a separate library in order to ease the interface distribution and to decouple them from their implementations.

Injecting an EJB into a Java Servlet

Now that we've defined an EJB, we're ready to use it from a servlet in a Java EE web module. Assuming that there's only one EJB implemented the UniqueLocalBusinessInterface in our application, we can inject it using an empty @EJB annotation:

package es.reacts;

import java.io.IOException;
import java.io.PrintWriter;

import javax.ejb.EJB;

import javax.servlet.*;
import javax.servlet.http.*;

public class ServletTest1 extends HttpServlet {
  @EJB
  UniqueLocalBusinessInterface lc;

  public void doGet(HttpServletRequest request,
    HttpServletResponse response)
    throws ServletException, IOException {
    [...]
    lc.sayLocalHello();
    [...]
  }

The first thing to note is that the EJB is injected into our servlet by the application server since the bean interface alone is sufficient to identify the target EJB. In this case the beanInterface element of the @EJB annotation takes on its default value, as explained in our previous post, that is the type of the injected field: UniqueLocalBusinessInterface. Since there's just one EJB in the application that implements this business interface, the lc field of the servlet is injected with a reference to an instance of such a class.

The second thing worth pointing out is that we're injecting an EJB into a servlet field safely because the EJB is stateless. Since servlet are stateless by default, you should not inject stateful resources into servlet fields properties otherwise you may run into concurrency-related problems. If you needed to use a stateful EJB into a servlet, you should retrieve a reference by programmatic JNDI lookup since that will guarantee that a new instance is returned for every lookup operation.

Let's deploy and run our application and we'll see that the servlet is injected its target EJB and the method invocation to the sayLocalHello() method of its business interface is carried out correctly.

If we wanted to inject a reference to a remote interface the client code would not be affected. If you try and change the UniqueLocalBusinessInterface from @Local to @Remote, you'll see that the servlet sees no change and continues to work correctly.

What Happens If More Than One EJB Implements the Same Interface?

Let's suppose that the we add another EJB in our EJB module in this application that implements the same interface as the previous one, UniqueLocalBusinessInterface. In this case, since the bean interface is not sufficient any longer to determine the target bean for injection, you'll be returned an error. Deploying such an application in the WebLogic Application Server, for example, results in the following error being thrown:

[08:46:25 PM] Caused by: weblogic.deployment.EnvironmentException: [J2EE:160199]Error resolving ejb-ref 'es.reacts.ServletTest1/lc1' from module 'WebTest0' of application 'EJBTestApp'. The ejb-ref does not have an ejb-link and the JNDI name of the target bean has not been specified. Attempts to automatically link the ejb-ref to its target bean failed because multiple EJBs in the application were found to implement the 'es.reacts.UniqueLocalBusinessInterface' interface. Please specify a qualified ejb-link for this ejb-ref to indicate which EJB is the target of this ejb-ref.

Injecting a Reference to a Specific EJB Instance

To solve the problem occurred in the previous section we need to provide the application server with the required information to identify the target EJB. As explained in our previous post, we can use the following two methods:
  • Either we use the name element of the @EJB annotation (or the corresponding <ejb-ref-name/> element of the deployment descriptor) to declare an EJB reference in the private namespace of the application and link it to the target bean using the deployment descriptor.
  • Or we use the beanName element of the @EJB annotation (or the corresponding <ejb-link/> element of the deployment descriptor) to do it directly in our code.

Mapping an EJB into the Private Namespace

Using the first method we'll end up with the following code in our servlet:

@EJB(name = "ejb/bean-name")
UniqueLocalBusinessInterface lc;

and the following element in the deployment descriptor (web.xml) of our Java EE web module that acts as an EJB client:

<ejb-local-ref>
  <ejb-ref-name>ejb/bean-name</ejb-ref-name>
  <ejb-ref-type>Session</ejb-ref-type>
  <local>es.reacts.UniqueLocalBusinessInterface</local>
  <ejb-link>UniqueLocalSessionEJB</ejb-link>
</ejb-local-ref>

The <ejb-link/> element contains the bean name that we defined at the beginning of our example with the annotation:

@Stateless(name = "UniqueLocalSessionEJB")

in the EJB implementation class.

Please note that, in this example, we used the @EJB name element explicitely but we could have established the link using its default value. The default value of the name element is:

[qualified class name]/[property or field name]

that, in this case, would be:

es.reacts.ServletTest1/lc

The disadvantage of using the default auto-generated name together with EJB linking using <ejb-link/> is that every time you refactor your code you'll have to check the deployment descriptors. Although developers sometimes think otherwise, the Java EE Specification defines some other roles such as the assambler and the deployer. In large corporate environments, it's not uncommon for such profiles to override developers' annotations to "plumb" the components used by the applications. Annotation override is one of the reasons why standard deployment descriptors still exist. This is especially true when references are to remote components, inside or outside your application. For this reason I suggest you do not rely on auto-generated names and use custom well documented names instead.

Linking an EJB to a Reference in the Private Namespace

The second method provides a direct way to link the reference to its target bean using the beanName element of the @EJB annotation. The servlet code will use the following EJB reference:

@EJB(beanName = "UniqueLocalSessionEJB")
UniqueLocalBusinessInterface lc;

and we need no additional information in the deployment descriptor.

Although this method allows the developer to link a reference to an EJB without relying on the deployment descriptor, the suggestion given at the end of the previous section is still valid. Remember that annotations can be overridden at deployment time! Do not link an EJB to a reference if you know beforehand that such a reference is eligible for override. In such cases, prefer assigning a name to the reference instead, as explained in the previous section.

Next Steps

In the following post we'll make a quick overview of how the EJB 3.0 API can be used to perform EJB programmatic lookups.


An Introduction to EJB 3.0 Injection and Lookup

Table of Contents


Introduction

The Enterprise JavaBeans Specification v. 3.0 introduces a simplified, annotation based API for EJB injection and lookup. EJB 3.0 are now POJOs and can be injected in other components (such as EJBs and Servlets) using simple annotations. EJB 3.0 is one of many other POJO-based specifications that made it to Java EE 6, such as JSR-229 "Contexts and Dependency Injection for the Java EE Platform" (formerly known as "Web Beans"). Java EE has never been so easy!

Nevertheless, while EJB 3.0 annotations hide away from the programmer the complexities of assembling a Java EE application and wiring all of its components, there are some subtleties that you should be aware of. Some of them, such as "global JNDI names", were address by the Enterprise JavaBeans Specification v. 3.1. Meanwhile, until Java EE 6 application servers are widely deployed, you might be exposed to the risk of writing code that relies upon non-portable application server specific behaviour.

To make things worse, some of the problems you might encounter show up when using an EJB local interface, which supposedly is an application-scoped interface of a bean of your own. Since local business interfaces actually imply a local method call (they use a pass-by-reference semantics and are restricted to the same JVM instance) such interfaces are the preferred choice when accessing the business interfaces of the components in your application. Often, this use case will make up most of the EJB calls in your Java EE application.

Declaring an EJB

According to the EJB v. 3.0 Simplified API Specification, when declaring a session bean you may use two annotations, depending on the session bean type:
  • @Stateless
  • @Stateful

Both annotations share two common annotation elements: name and mappedName.

name

The annotation element name defines the bean "name" and defaults to the unqualified name of the bean class. The bean name must be unique in the scope of the module containing the EJB.

mappedName

The EJB 3.0 Specification defines mappedName as a "product-specific name that the session bean should be mapped to." Often, application server use mappedName to map a session bean to a global JNDI name. The EJB 3.1 specification sort of deprecates the mappedName element and introduces the concept of "portable global JNDI name".

We'll soon see how and when to use such metadata.

EJB References

To establish a reference to an EJB, you may use the @EJB annotation or the standard deployment descriptors (via <ejb-ref/> and <ejb-local-ref/>). The @EJB annotation is defined as follows:

@Target({TYPE, METHOD, FIELD}) @Retention(RUNTIME)
public @interface EJB {
  String name() default "";
  Class beanInterface() default Object.class;
  String beanName() default "";
  String mappedName() default "";
  String description() default "";
}


name

The name element defines the injected EJB name "in the application environment". The EJB name, then, is the location of the injected object in the private namespace java:comp/env. Its default value it's the fully qualified name of the annotated class field or property. When the @EJB annotation is used at class level the name element is mandatory.

The name element is the equivalent of the <ejb-ref-name/> element in the deployment descriptor:

<ejb-ref>
  <ejb-ref-name>bean name</ejb-ref-name>
  [...]
</ejb-ref>

beanInterface

The beanInterface is the business interface type of the injected component. By default, it's the type of the annotated field or property. When the @EJB annotation is used at class level the beanInterface element is mandatory.

The beanInterface element is the equivalent of the <remote/> or <local/> elements in the deployment descriptor:

<ejb-ref>
  <ejb-ref-name>bean name</ejb-ref-name>
  <remote>bean interface</remote>
  [...]
</ejb-ref>

beanName

The beanName element specifies the bean "name" as declared in the @Stateful and @Stateless annotations via the name element or in the deployment descriptor via the <ejb-name/> element. The beanName element is most useful when more than one EJB implement the same business interface in an application: the beanName lets the developer reference a specific EJB in a specific module. The syntax to use in this case is:

<ejb module>#<ejb name>

The bean name is resolved automatically if there's only one EJB implementing the requested business interface in the application.

The beanName element is the equivalent of the <ejb-link/> element in the deployment descriptor:

<ejb-ref>
  <ejb-ref-name>bean name</ejb-ref-name>
  <remote>bean interface</remote>
  <ejb-link>linked ejb</ejb-link>
  [...]
</ejb-ref>

mappedName

As in the case of the mappedName element of the @Stateless and @Stateful annotations, the mappedName is a product-specific metadata whose use is not portable.

The mappedName element is the equivalent of the <mapped-name/> element in the deployment descriptor:

<ejb-ref>
  <ejb-ref-name>bean name</ejb-ref-name>
  <remote>bean interface</remote>
  <ejb-link>linked ejb</ejb-link>
  <mapped-name>mapped name</mapped-name>
  [...]
</ejb-ref>

What About Beans in Other Applications?

If you review the mechanisms described so far, you should notice that there's no (portable) way to declare a dependency (an EJB reference) to a bean outside the application. The EJB Specification v. 3.1 addresses this problem and defines portable global JNDI names. No changes will be required for a compliant EJB v. 3.0 to be assigned a portable global JNDI name in a compliant EJB v. 3.1 container.

Meanwhile, to wire a reference to an EJB outside your application, you should rely on the mechanisms provided by your application server.

Do Not Rely on Non-Portable Global JNDI Names to Lookup an EJB

As outlined in the previous sections, before EJB v. 3.1 there was no portable way to lookup an EJB with a global JNDI name and the deployer has to rely on application server specific tools and metadata to establish a link between an EJB reference and an EJB global JNDI name. Such a link, moreover, is necessary when establishing a reference to a bean outside your application.

Even if it's appealing to avoid using the @EJB annotation elements (or their corresponding deployment descriptor elements) and use global JNDI names instead, you should always rely on EJB references and lookup in your java:comp/env private namespace. Your private namespace and the mapping mechanism provide you the level of indirection that will isolate your code from configuration changes.

This also means that, if you're restricted to EJB v. 3.0, you should always use the beanName (<ejb-link/>) mechanism and performing lookups in your private java:comp/env namespace. Many times I've heard the story of some developer inspecting the global JNDI tree of an application server to deduce the application server global JNDI naming scheme for EJBs and then experiencing some NamingException here and there. For this reason, avoid using the @EJB mappedName element and rely on name and beanName instead.

Some application servers, for example, publish both remote and local EJB business interfaces with global JNDI names. Others simply don't. Oracle WebLogic is one of the latter. The EJB v. 3.0 specification, indeed, does not require a local business interface to be available in the global JNDI tree.

Looking Up Remote and Local Business Interfaces

As far as it concerns the caller, the process of acquiring a reference to a remote and to a local business interface should be identical. Unfortunately, that's not always the case if you don't rely only on portable mechanisms.

References to local interfaces of EJBs can always be resolved with the beanName mechanism. This is not always the case for references to remote interfaces since such EJB might live outside your application. Here's, then, another reason not to rely on global JNDI names in your code: not only such a code would be not portable, but it would require you to use different strategies to lookup remote and local business interfaces (depending on the application server.) The business interface type would not be transparent and a change in a business interface type could break your code.

An Easy Pattern to Establish EJB References

Although they might be necessary in some scenarios, avoid EJB lookups and rely on @EJB references "auto-wiring". Respecting some easy patterns guarantees that your EJB references will be declared and satisfied in a completely automatic way:
  • Try to reduce the number of EJB that share business interfaces: if just one EJB implement a specific business interface in an application, an EJB reference can be automatically declared and wired with a default @EJB annotation.
  • If sharing business interfaces improves your application design, define a clear naming policy for beans of your application and avoid duplications: if there's only one bean with a specific name, an EJB reference can be automatically declared and wired with a @EJB(beanName="[name]") annotation. If there's more than one bean with the same name, you'll be forced to use the @EJB(beanName="[ejb-module-path]#[ejb-name]") syntax when declaring references.
  • If you need to lookup EJB references programmatically, declare a location for your EJBs in your local namespace using the @EJB name element (or the <ejb-ref-name/> element) and link it to the target EJB with the @EJB beanName element (or the <ejb-link/> element.)

Next Steps

In the following blog post, we'll examine some example to clarify how to use the EJB v. 3.0 APIs to declare EJB references and use dependency injection and programmatic lookup to obtain a reference to an EJB business interface.



Thursday, 9 September 2010

No news... good news? Solaris 10 licensing terms have changed

Long time no blog. Partly because I enjoyed a(n almost) relaxing summer. Partly because I was standing by, sad and astonished, at what was happening to Solaris and OpenSolaris in the final stages of the Oracle and Sun Microsystems merger.

There's no need for me to blog about the well known changes that OpenSolaris and its communities underwent in the last months. I feel a little bit of sadness but things haven't changed so dramatically. The supported Sun's OpenSolaris distribution has been obliterated in favor of... yet another Solaris Express. Back to the old days. Ben Rockwood has written a good piece in his blog in which he analyses the leaked Oracle memo and makes some insightful considerations. I agree with his analysis.

Until Solaris 11 Express sees the light, I was thinking about upgrading my workstations to Solaris 10 09/10, which was released yesterday. As you'll notice when accepting the OTN license, Solaris 10 licensing terms have changed.

Except for any included software package or file that is licensed to you by Oracle under different license terms, we grant you a perpetual (unless terminated as provided in this agreement), nonexclusive, nontransferable, limited License to use the Programs only for the purpose of developing, testing, prototyping and demonstrating your applications, and not for any other purpose.

After so many fears and speculations, that's good news.



Sunday, 5 September 2010

Open Source Tools For Professional Photographers

Photography Camera

Professional photographers through their pictures capture the true essence involving people, places, or things. They take pictures to sell products, entertain people, report the news, or bring back memories. All this involves lots of graphic work such as editing for invites, posters, magazine covers, touch ups etc.

Did you know there is a good collection of open source software available at a professional photographer's disposal ?

Read more »

Thursday, 12 August 2010

Strace - The Sysadmin’s Microscope

Strace is a command line tool which can be used to figure out what is wrong with an errant application running in your Linux system. Some even look at strace as the Swiss army knife of a systems administrator.

Check out how I used strace to troubleshoot a multimedia problem in Ubuntu a long time back.

More recently, Greg Price at the Ksplice blog has written an informative article on strace which explains the use of this troubleshooting tool.

Thursday, 5 August 2010

Google Wave is destined to be a Dodo - Says Google

Remember Google Wave - the innovative way of communication which Google unveiled amidst much fanfare a year back ? When it was released, Google Wave was considered to be a potential replacement for the ubiquitous Email.
Read more »

Sunday, 1 August 2010

GNOME Census - A Glance Into Developer Participation In GNOME

As a GNOME user, have you ever wondered - How big is the GNOME project ? What is its make up ? How are decisions taken ? And how many GNOME developers are there ? If yes, then you need look no further. Because Neary Consulting - A Free software consultancy, has released the GNOME Census giving an overview of the GNOME project and its functions. The census report analyzes how developers participate in the GNOME project and looks for patterns within the project itself.

Read more »