Developing an Enterprise Bean with EJB 3.0 Technology







Let's look at what a developer does to create enterprise beans using EJB 3.0 technology. Note that the material in this section reflects the technology as documented in the early draft of the EJB 3.0 Specification. The specification might change over time, and so some aspects of what a developer codes to create enterprise beans might also change.



A Stateless Session Bean











To create a session bean using EJB 3.0 technology, a developer only needs to code a bean class, annotated with appropriate metadata annotations, and a business interface. The business interface can be generated by default. The bean class is coded as a plain old Java object (POJO).






Let's examine what a developer needs to do to develop a stateless session bean using EJB 3.0 technology. Once again, let's develop a bean named Converter that converts currency -- from dollars to yen, and from yen to euros-- and that can be accessed remotely. This is the same stateless session bean presented in Developing an Enterprise Bean with EJB 2.1 Technology. You'll see how much easier it is to develop the bean using EJB 3.0 technology.


To create the session bean, a developer only needs to code a bean class and annotate it with appropriate metadata annotations:



@Stateless @Remote public class ConverterBean {

BigDecimal yenRate = new BigDecimal("121.6000");
BigDecimal euroRate = new BigDecimal("0.0077");

public BigDecimal dollarToYen(BigDecimal dollars) {
BigDecimal result = dollars.multiply(yenRate);
return result.setScale(2,BigDecimal.ROUND_UP);
}

public BigDecimal yenToEuro(BigDecimal yen) {
BigDecimal result = yen.multiply(euroRate);
return result.setScale(2,BigDecimal.ROUND_UP);
}
}


In this example, the metadata annotations are @Stateless and @Remote.
Significantly, there's no home interface, remote interface, or deployment descriptor to code. All that's required in addition
to the bean class is a business interface, and that can be generated by default (as is the case here).



The bean class is coded as a plain old Java object ("POJO") rather than a class that implements an interface such as javax.ejb.SessionBean. Because the bean class doesn't implement an interface such as javax.ejb.SessionBean, a developer no longer has to implement methods such as ejbRemove, ejbActivate, or ejbPassivate in the bean class. However a developer can implement any or all of these callbacks if they are needed. If the bean class implements one of these callbacks, the EJB container calls it just as it does for EJB 2.1 technology.


Metadata Annotation



Metadata annotation is a new Java Language feature in Java 2 Platform Standard Edition (J2SE) 5.0. It's designed to give developers a way to annotate code at appropriate points in a program. A developer can define an annotation type, for example:



public @interface Copyright {
String value ();
}


An annotation type is defined with an @ sign preceding the interface keyword. The annotation type includes one or more elements -- in this case, value. (In annotations with a single element, the element should be named value to avoid having to specify the name when the annotation is used.) After an annotation type is defined, a developer can use it to annotate declarations in code:


@Copyright("2004 My Corporation")
public class Converter {
...


An annotation consists of the @ sign preceding the annotation type, followed by a parenthesized list of element-value pairs. When an annotation processing tool (there's one in J2SE 5.0) encounters the annotation, it generates the code for the annotation -- here, a copyright notice that includes the string "2004 My Corporation".



The EJB 3.0 Specification defines a variety of annotation types such as those that specify a bean's type (@Stateless, @Stateful, @MessageDriven, @Entity), whether a bean is remotely or locally accessible (@Remote, @Local), transaction attributes (@TransactionAttribute), and security and method permissions (@MethodPermissions, @Unchecked, @SecurityRoles). (There are many more annotations defined in the specification than these.) Annotations for the EJB 3.0 annotation types generate interfaces required by the class as well as references to objects in the environment.



In many cases, defaults can be used instead of explicit metadata annotation elements. In these cases, a developer doesn't have to completely specify a metadata annotation to obtain the same result as if the annotation was fully specified. For example, by default, an entity bean (annotated by @Entity) has a default entity type of CMP, indicating that it has container-managed persistence. These defaults can make annotating enterprise beans very simple. In fact, in many cases, defaults are assumed when an annotation is not specified. In those cases, the defaults represent the most common specifications. For example, container-managed transaction demarcation (where the container, as opposed to the bean, manages the commitment or rollback of a unit of work to a database) is assumed for an enterprise bean if no annotation is specified. These defaults illustrate the "coding by exception" approach that guides EJB 3.0 technology. The intent is to simplify things for developers by forcing them to code things only where defaults are not adequate.



Business Interface











A business interface is a plain old Java interface (POJI).






No component interface or home interface is required for a session bean. The one interface a session bean needs is a business interface. A business interface is a plain old Java interface ("POJI"). It does not have to extend or implement anything, and it does not throw java.rmi.Remote Exception or java.rmi.CreateException. A developer has the option of implementing the business interface or letting the interface be generated. In the previous example, a business interface named Converter is generated for ConverterBean by default. The generated interface is defined with the methods dollarToYen and yenToEuro. Generating business interfaces demonstrates that metadata annotation isn't the only place where defaults are assumed.


If a developer wanted to implement the business interface, the code would look like this:



@Stateless @Remote public class ConverterBean
implements Converter {

BigDecimal yenRate = new BigDecimal("121.6000");
BigDecimal euroRate = new BigDecimal("0.0077");

public BigDecimal dollarToYen(BigDecimal dollars) {
BigDecimal result = dollars.multiply(yenRate);
return result.setScale(2,BigDecimal.ROUND_UP);
}

public BigDecimal yenToEuro(BigDecimal yen) {
BigDecimal result = yen.multiply(euroRate);
return result.setScale(2,BigDecimal.ROUND_UP);
}
}

public interface Converter {
BigDecimal dollarToYen(BigDecimal dollars);
BigDecimal yenToEuro(BigDecimal yen);
}

The Session Bean Client



Here's part of what a remote client (in this case, a session bean) for the EJB 3.0 technology version ConverterBean might look like:


import converter.Converter;
import java.math.BigDecimal;

@Session public class ConverterClient {
@Inject Converter

Converter currencyConverter;

BigDecimal param = new BigDecimal("100.00");
BigDecimal amount = currencyConverter.dollarToYen(param);

...
}










JNDI is no longer required to get references to resources and other objects in an enterprise bean's context. Instead, a developer can use resource and environment reference annotations in the bean class.






Notice that there's no JNDI lookup code in the client. JNDI is no longer required to get references to resources and other objects in an enterprise bean's context. Instead, a developer can use resource and environment reference annotations in the bean class. These annotations are known as dependency annotations, because a developer uses them to declare the dependency of the enterprise bean on a resource or other object in the environment. The container then takes care of obtaining the references and providing them to the enterprise bean. Notice the @Inject annotation. It identifies a dependency injection, that is, it "injects" a dependency that the enterprise bean has on a resource or other object in the environment. Dependency injection can dramatically simplify what a developer has to code to obtain resource and environmental references.



Although JNDI lookup is not required, it can still be used if desired.



An Entity Bean With the EJB 3.0 Persistence Model











EJB persistence technology is currently being updated for the entire Java platform as part of the EJB 3.0 specification. The new Java Persistence API will define a new single model for implementing persistence in the Java platform. The new model will take effect when J2EE 5.0 ships, which is currently planned for the first quarter of 2006. In the meantime, developers should continue to use container-managed persistance with enterprise beans. Existing container-manged persistence applications will continue to work unchanged because the current container-managed persistence functionality in EJB technology will continue to be supported (and will be improved as well). There is no need to migrate existing applications to this new API. The EJB expert group is also working hard to ensure that developers can make use of EJB technology and this new API in the same application.






Now let's see what a developer does to develop an entity bean using EJB 3.0 technology. Once again, let's develop an entity bean named PlayerBean that represents a player on a sports team. PlayerBean the new lightweight persistence model, and has a many-to-many relationship to TeamBean, which represents a sports team. This is the same entity bean presented in Developing an Enterprise Bean with EJB 2.1 Technology. Here too you'll see how much easier it is to develop the bean using EJB 3.0 technology.











To create an entity bean, a developer only needs to code a bean class and annotate it with appropriate metadata annotations. The bean class is coded as a POJO.






To create the entity bean, a developer only needs to code a bean class and annotate it with appropriate metadata annotations. Here's what part of the bean class looks like:



@Entity public class PlayerBean {

private Long playerId;
private String name;
private String position;
private double salary;
private Collection teams;

public PlayerBean() {}

@id(generate=AUTO) public Long getPlayerId() {
return id;
}

public String setPlayerId(Long id) {
this id=id;
}

public String getName() {
return name;
}

public String setName() {
this name= name;
}

...

public Collection getTeams() {
return teams;
}

public Collection setTeams(Collection teams) {
this teams=teams;
}

...


The @Entity metadata annotation marks this as an entity bean. As is the case for a session bean in EJB 3.0 technology, there's no home interface, remote interface, or deployment descriptor to code. In fact, you don't even need a business interface for an entity bean. The bean class is coded as a POJO rather than a class that implements an interface such as javax.ejb.EntityBean. This means, among other things, that instances of an entity bean can be created simply through a new() operation. In addition, a developer no longer has to implement methods such as ejbRemove, ejbActivate, ejbPassivate, or ejbLoad in the bean class.



In EJB 3.0 technology, an entity bean class is a concrete class. It's no longer an abstract class. Notice that an entity bean, as illustrated by PlayerBean, has non-abstract, private instance variables, such as PlayerID. These variables represent the bean's persistent fields. The persistent fields are accessible through access methods such as getPlayerID and setPlayerID. Access methods were also used in this way in EJB 2.1 technology. However in EJB 3.0 technology, access methods are concrete, not abstract. In addition, these get and set methods can include logic, something that wasn't possible previously. This is useful for actions such as validating fields. Another improvement is that access to the persistence fields is not limited to the get and set methods. The persistence fields are also accessible through a bean class's business methods. One restriction however is that in EJB 3.0 technology, only methods within the class can access persistence fields -- in other words, you can't expose the instance variables outside of the class. That's why the instance variables are private (they can also be protected). Also notice the constructor in the code. Entity beans in EJB 3.0 technology must define a constructor with no parameters.



The @Id metadata annotation is used for the primary key. The element-value pair generate=AUTO tells the EJB container to pick a strategy for generating a primary key that's most appropriate for the database used by this application. @Id is one of the annotation types for object-relational mapping that's defined in the EJB 3.0 specification.


The Entity Bean Client



Here's what part of RosterBean, the session bean that locally accesses PlayerBean, might look like using EJB 3.0 technology:



@Stateless public class RosterBean {

@Inject EntityManager em;

public Long createPlayer(PlayerBean player) {
em.create(player);
return player.getPlayerID();

public PlayerBean findByPlayerId(Long playerId) {
return (PlayerBean) em.find("Player", playerID);
}
...

}


This version of the entity bean client is much smaller and easier to code than the version that uses EJB 2.1 technology. What makes the EJB 3.0 technology version smaller and simpler to code are two new features introduced in EJB 3.0 technology: dependency injection and the EntityManager.



Dependency Injection



As mentioned earlier, the @Inject metadata type identifies a dependency injection -- it injects a dependency that the enterprise bean has on a resource or other object in the environment. The container then takes care of obtaining the reference to the resource or object and provides it to the enterprise bean. Dependency injection reflects a fundamental change in philosophy in the EJB architecture. Previous versions of the EJB architecture forced the developer into complying with the requirements of the EJB container in terms of providing classes and implementing interfaces. By comparison, dependency injection reflects the fact that the bean tells the EJB container what it needs, and then container satisfies those needs.











Dependency injection, a new feature introduced in EJB 3.0 technology,
reflects a fundamental change in philosophy
in the EJB architecture. Previous versions of the EJB architecture
forced the developer into complying with the requirements of the EJB
container in terms of providing classes and implementing interfaces. By
comparison, dependency injection reflects the fact that the bean tells
the EJB container what it needs, and then container satisfies those
needs.







In the RosterBean class the @Inject annotation tells the EJB container that the session bean needs the EntityManager object. In general, a dependency annotation identifies a needed resource or other object in the class's environment, and the name that is used to access that resource or object. The @Inject annotation is used when all the needed elements of the annotation can be inferred. Two other annotations that can be used for dependency injection are @Resource, which identifies a dependency on a resource, and @EJB, which identifies a dependency on a session bean. A developer can specify a dependency injection on a setter method of a bean class or on an instance variable in a bean class.



It's the responsibility of the EJB container to inject the reference to the needed resource or object before the session bean is made available to handle a business method. This is typically at the time that the EJB container invokes the setSessionContext method.


Dynamic Lookup



Dependency injection is not the only way to locate resources. The EJB 3.0 specification also includes a dynamic lookup capability. This capability is offered through a lookup method in the javax.ejb.EJBContext interface. This provides the ability to dynamically look up a needed resource. In the following example, the setSessionContext subinterface of EJBContext is injected into the client code and then used to dynamically look up a session bean named myShoppingCart:



...
@Inject
private void setSessionContext(SessionContext ctx) {
this.ctx = ctx;
}
...
myShoppingCart = (ShoppingCart)ctx.lookup
("shoppingCart");


EntityManager











The persistence model in EJB 3.0 technology has been simplified for entity beans with container-managed persistence.






The persistence model in EJB 3.0 technology has been simplified for
entity beans with container-managed persistence. A significant aspect
of this simplified persistence model is the EntityManager, a new API in the EJB 3.0 architecture. The EntityManager is much like a home interface (but without a type). It is used to manage an entity bean's state. Various lifecycle methods are defined in the API, such as create, which puts an entity bean in a managed state (that is, what's termed a "persistence context") and remove, which removes an entity bean from the persistence context. When a bean instance is in a managed state, the data it represents is inserted into a database at the end of a transaction. The EntityManager also provides a flush method which synchronizes the persistence context with the underlying database. The data represented by a managed entity bean instance is inserted into a database when flush is issued, that is, before the end of the transaction. What gets inserted at the end of a transaction or through flush, and where in the database it gets inserted, depends on Object/Relational mapping specifications -- another new feature in EJB 3.0. When a bean instance is removed through remove, it's no longer in a managed state -- the data it represents is removed from the database at the end of a transaction, or sooner if flush is specified.



Some other important methods provided by the EntityManager include find, which finds an entity bean instance by primary key, and merge, which merges the state of a detached entity bean instance into the current persistent context. The entity bean model in the EJB 3.0 architecture allows for detaching entity beans instances. An entity bean instance becomes detached at the end of a transaction. Detached instances can exist outside of the transaction context in which they were created. This allows a developer to do things such as serialize the bean instance to another application tier. This is a significant improvement over older versions of the entity bean model. Previously, entity beans were not serializable. Developers had to resort to a Data Transfer Object (DTO) to export an entity bean's state. In general, DTOs are not viewed positively. They're seen as "antipatterns," that is, bad solutions to a problem. The merge method brings the state of a detached instance into the persistence context.


Looking back at the client code, RosterBean first requests the EJB container to inject a reference to the EntityManager:



@Inject EntityManager em;


Then RosterBean invokes the EntityManager's create method to put PlayerBean in a managed state:



public Long createPlayer(PlayerBean player) {
em.create(player);
return player.getPlayerID();


It then invokes the EntityManager's find method to find an instance of PlayerBean by its primary key.



public PlayerBean findByPlayerId(Long playerId) {


Other Improvements







In addition to the simplifications highlighted in Developing an Enterprise Bean with EJB 3.0 Technology, the technology includes other ease-of-development improvements. Chief among these improvements are:



  • Support for testing enterprise beans outside of the EJB container

  • Support for Object-Relational mapping

  • Enhanced EJB QL



Let's briefly examine each of these improvements.



Support for Testing Outside of the EJB Container



It's now much easier to test entity beans outside of an EJB container. Previously, the entity bean component model, with its requirements for home and component interfaces, abstract entity bean classes, and virtual persistent fields, made it difficult to test entity beans outside of the container. The entity bean model in the EJB 3.0 architecture removes the requirement for these interfaces. The only thing required for an entity bean is a concrete bean class that has non-abstract persistent fields. In addition, an entity bean's lifecycle is controlled through the EntityManager API, not through a home interface whose lifecycle methods are implemented by the EJB container. All of this makes entity beans less dependent on intervention by the EJB container, and so, can be more easily tested outside of the container.











Entity beans are now less dependent on intervention by the EJB container, and so, can be more easily tested outside of the container.






The difficulty of testing outside a container was compounded in the past by container-managed relationships. Because a container automatically manages these relationships, there's no assurance that a bean tested outside of the EJB container will behave the same and produce the same results as inside the EJB container. In supporting the testing of enterprise beans outside of an EJB container, the EJB 3.0 architecture removes support for container-managed relationships -- but still maintains support for bean-managed relationships. Dropping support for container-managed relationships was a difficult decision to make by the Expert Group responsible for the architecture. But the need to support entity bean testing outside of the EJB container is a very important requirement -- one that needed to be met.



Support for Object/Relational Mapping



The EJB 3.0 specification defines metadata annotations for Object/Relational (O/R) mapping, that is, the mapping of an entity bean to the relational database structure that underlies it. Or put another way, O/R mapping is the mapping of an object schema to a database schema. An O/R mapping specification was not part of the EJB architecture in the past. By providing it, the EJB architecture gives developers a lot more control over the data model than in the past.











An Object/Relational (O/R) mapping specification has been added in the EJB 3.0 architecture. The O/R mapping supports inheritance and polymorphism.






Significantly, O/R mapping support in the EJB 3.0 architecture supports inheritance and polymorphism. This means that a hierarchy of entity beans, where one entity bean subclasses another, can be mapped to a relational database structure, and the same queries or methods can be used against the different classes and subclasses in the hierarchy to produce results that are specific to that class or subclass.



Metadata annotations include those for table mappings, column mappings, and associations (such as many-to-one and one-to-many). For example, here is a metadata annotation that maps an entity bean named Customer to a database table named CUST:



@Entity
@Table(name="CUST")

public class Customer {...}


Here's an example that specifies a one-to-many relationship between the Customer entity bean and an Order entity bean:



@Entity
@Table(name="CUST")

public class Customer {
private Setorders = new Hashset();
...

@OneToMany(cascade=ALL)
public Set getOrders() {
return orders;
}

public void setOrders(Set orders) {
this.orders = orders;
}
...


The cascade=ALL specification means that actions are cascaded through the relationship. So when a Customer instance is created and its data is stored in the database, all the orders for that instance are also stored in the database.



Here's an example of mapping with inheritance. In the following example, ValuedCustomer is an entity bean that extends the Customer entity bean. The hierarchy is mapped to the CUST table:



@Entity
@Table(name="CUST")
@Inheritance (strategy=SINGLE_TABLE,
discriminatorType=STRING,
discriminatorValue="CUST")
public class Customer {...}

@Entity
@Inheritance (discriminatorValue="VCUST")
public class ValuedCustomer extends Customer {...}


The @Inheritance metadata annotation identifies an inheritance strategy for a class hierarchy. In this example, the strategy specified by the value of the strategy element is SINGLE_TABLE. This means that all the bean instances are mapped to a single table. This type of strategy requires a discriminator column in the table to identify one type of bean instance from another. The value in the column indicates the class for a specific bean instance. In the example, discriminatorType specifies that the discriminator column contains strings. The discriminatorValue element specifies that instances of Customer are identified by the value CUST, and instances of ValuedCustomer are identified by the value VCUST.



As mentioned earlier, defaults can be used in many places throughout the EJB architecture. Relying on defaults, the inheritance example can be as simple as this:



@Entity
public class Customer {...}

@Entity
public class ValuedCustomer extends Customer {...}


Enhanced EJB QL



EJB QL has been a very popular facet of EJB technology. However, despite its popularity, EJB QL has lacked some of the features of a full SQL query language, such as bulk update and delete operations, outer join operations, projection, and subqueries. EJB 3.0 technology adds those features to EJB QL.











EJB QL adds support for operations such as bulk update and delete, outer join, projection, and subqueries. It also adds support for outer join-based prefetching.






For example, here's an EJB QL query that requests a bulk delete operation. It requests deletion of all customers whose status is inactive.



DELETE
FROM Customer c
WHERE c.status= 'inactive'


Here's an example of an EJB QL subquery. It's a correlated subquery that requests employees whose spouse is also an employee:



SELECT DISTINCT emp
FROM EMPLOYEE emp
WHERE EXISTS (
SELECT spouseEmp
FROM EMPLOYEE spouseEmp
WHERE spouseEmp = emp.spouse)


Another important addition to EJB QL is support for outer join-based prefetching
(termed a "FETCH JOIN"). A FETCH JOIN for a query returns a result and the prefetched data. For this to work, there must be an association between the entity that the query returns as a result and the prefeteched data. This gives developers a way of bringing in data that an application immediately needs, and related data that it will later need. Prefetching can improve application performance by reducing the number of EJB QL queries that need to be invoked (and the subsequent database transmissions that need to be made). For example, here is an outer join with a fetch that requests all customers in California and all the orders for those customers:



SELECT DISTINCT c
FROM CUSTOMER c LEFT JOIN FETCH c.orders
WHERE c.address.state = 'CA'


Beyond EJB QL enhancements, the EJB 3.0 architecture also adds a Query API to create dynamic queries and named queries (named queries are similar to static queries in EJB-SQL). Here's an example that creates a dynamic query. The query produces a result set of customers whose name is like a name that's dynamically supplied to the query.



@Inject public EntityManager em;

public List findWithName (string Name) {
return em.CreateQuery {
"SELECT c FROM Customer c" +
"WHERE c.name LIKE :custName")
.setParameter("custName", name)
.setMaxResults(10)
.listResults();
}
...


The CreateQuery method is a factory method of the EntityManager for creating queries. This example uses the Query API on the entity manager to generate the dynamic query. Like dynamic queries in SQL, the query is specified as a string. Notice the named parameter :custName. Named parameters have a colon (:) prefix. This is another enhancement to EJB QL. Named parameters can be used in addition to positional parameters in EJB QL queries. There are three method calls in the example. The setParameter method dynamically binds a specific name to the query at run time. The setMaxResults and listResults methods limit the result set to 10, and list the results, respectively.



Here's an example that creates a named query. The named query in the example does essentially the same thing as the dynamic query in the previous example, that is, find customers who have a specific name. To create a named query, a developer first uses a metadata annotation (@NamedQuery) to define the named query:



@NamedQuery {
name="findAllCustomersWithName",
queryString=
"SELECT c" +
"FROM Customer c" +
"WHERE c.name LIKE :custName"
}


Next, the developer creates the named query that was previously defined:



@Inject public EntityManager em;

customers = em.createNamedQuery("findAllCustomersWithName")
.setParameter("custName", "Smith")
.setMaxResults(10)
.listResults();
}
...


There's Even More







This article only highlights some of the simplifications made to EJB technology in the EJB 3.0 Specification. You'll find even more improvements to the technology, and more detailed information, by reviewing the specification. Your feedback on the EJB 3.0 Specification is also very important in ensuring that EJB technology meets its objectives of simplifying the developer's experience while maintaining its power and sophistication.



For More Information







About the Author







Ed Ort is a staff member of java.sun.com and developers.sun.com. He has written extensively about relational database technology, programming languages, and web services.






Posted by 아름프로
BLOG main image

카테고리

분류 전체보기 (539)
이야기방 (19)
토론/정보/사설 (16)
IBM Rational (9)
U-IT (0)
SOA/WS/ebXML (110)
개발방법론/모델링 (122)
J2SE (34)
J2EE (60)
DataBase (39)
Open Projects (30)
BP/표준화 (50)
Apache Projects (15)
Web/보안/OS (22)
Tools (7)
AJAX/WEB2.0 (1)
Linux/Unix (1)
영어 (0)
비공개방 (0)

최근에 올라온 글

최근에 달린 댓글

최근에 받은 트랙백

달력

«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31

글 보관함

Total :
Today : Yesterday :