This tutorial on the Enterprise JavaBeans™ -EJB- component model is based on the Java Enterprise Edition -Java EE- 8 Application Programming Interface -API- ☛ and EJB version 3.2. Java EE 8 tutorial ☛
Note that Java EE will no longer exist with the emergence of Java 9. Jakarta EE ☛ 8 is a rewritten (iso-functional) version of Java EE 8. Jakarta EE ☛ 9 is the next version of Java EE 8
Case studies are provided as Maven/Apache NetBeans projects; they have also been tested by means of this Integrated Development Environment -IDE-
- Rich open framework (standard) for the implementation, the deployment and the running of business Internet applications
- Support of low-level mechanisms with orthogonal facilities like transaction management, security, naming, messaging…
- Separation of concerns: QoS-based, administrative… tasks are instrumented and dissociated from business logic programming
- Canonical programming framework: patterns, prefabricated components (containers, composition facilities…), services…
Java EE technologies
- Servelts, JavaServer Pages -JSP-, JavaServer Faces -JSF-, Java Message Service -JMS-, Java Connector Architecture -JCA-, Java Transaction Service -JTS-/Java Transaction API -JTA-…
- Java EE component model: Enterprise JavaBeans™ -EJB-
- Java EE service computing: Web Services
- WebSockets
- JavaScript Object Notation -JSON- processing
- Etc.
Java EE products (Java EE application servers)
- GlassFish ☛
- Oracle Fusion Middleware ☛
- Payara ☛
- Apache TomEE ☛
- WebSphere ☛
- Wildfly ☛
- Further detail: Java EE application servers ☛
Java EE key challengers
Java EE Application Model ☛
Java EE 8 API ☛
- EJB is the core technology of Java EE with several key versions: EJB 1.0 (1999), EJB 2.1 (2003), EJB 3.0 (2006), EJB 3.1 (2009) and EJB 3.2 (2013)
- Initially created by IBM with initial Java Specification Request -JSR- ☛ in 1999 and key players: Oracle, IBM, SAP…
Principles
- Enterprise Beans are business components, i.e., they implement business functions as Java methods
- Enterprise Beans are server-side (shared!) components within a Java EE Virtual Machine -VM- called in this case a Java EE application server
- Enterprise Beans are configurable components through XML (EJB 2.x) and/or Java annotations ☛ (EJB 3.x)
- Enterprise Beans have predefined (strict, EJB 2.x) or (more relaxed, EJB 3.x) formats in order to be in particular handled in a certain way by the Java EE application server on which they are deployed
- Enterprise Beans are distributable, i.e., they are mobile from one Java EE VM to another in order to possibly scale up applications through load balancing
Characteristics
- Integrative support for persistence (Java Persistence API -JPA- ☛), transaction management (Java Transaction API -JTA-), messaging (Java Message Service -JMS-), etc.
- Federating technology: a place where (sometimes heterogeneous) Java technologies can meet together: JNDI, JMS, JDBC, JDO, JPA, JTS/JTA, JCA…
- Underlying support for Web Services
- Rigorous development framework (ease of reuse, QoS management like load balancing, transaction management, security…). However, Enterprise Beans are sometimes intelligible with difficulty!
- Natural support for Software as a Service -SaaS- in cloud computing
Benefits
Entity Beans
- Bean-Managed Persistence -BMP- ⤳ J2EE 1.4, JDBC
BMP is an old EJB style pertaining to J2EE 1.4. Nonetheless, it is also supported in Java EE 5, 6, 7 & 8. In this case,
ejbCreate
andejbPostCreate
are two mandatory methods. They can be empty or they can be populated in a mutually consistent manner.ejbCreate
matches to theINSERT
SQL statement whileejbPostCreate
may invokegetPrimaryKey
andgetEJBObject
via Entity Beans' execution context (or “container” ☛) whose type isEJBContext
(it is set up via thesetEntityContext
mandatory method). As forejbRemove
, it corresponds to theDELETE
SQL statement.ejbLoad
andejbStore
match to theSELECT
andUPDATE
SQL statements. Finally,unsetEntityContext
is dedicated to the possible release of resources- Container-Managed Persistence -CMP- ⤳ J2EE 1.4, EJB QL ver. 2
- Container-Managed Persistence -CMP- ⤳ Java EE 5, 6, 7 & 8
JPA Query Language -JPQL- ☛ replaces EJB QL ver. 3. Database accesses occur through each “container” ☛ of each Entity Bean. Mapping between tables in databases and Entity Beans are set up by means of annotations
Example (including JPQL code)
@javax.persistence.Entity(name = "MY_PRISONER") @javax.persistence.Table(name = "PRISONER") @javax.persistence.SecondaryTable(name = "INCARCERATION", pkJoinColumns = {@javax.persistence.PrimaryKeyJoinColumn(name = "PRISON_FILE_NUMBER")}) @javax.persistence.NamedNativeQuery(name = "Prisoner.Under_remand_SQL", query = "SELECT * FROM Prisoner WHERE prison_file_number NOT IN (SELECT prison_file_number FROM Conviction)") @javax.persistence.NamedQueries({@javax.persistence.NamedQuery(name = "Prisoner.All_JPQL", query = "SELECT p FROM Prisoner"), @javax.persistence.NamedQuery(name = "Prisoner.Under_remand_JPQL", query = "SELECT p FROM Prisoner WHERE p._conviction IS EMPTY") }) public class Prisoner implements java.io.Serializable { …
Example (
Customer_management
Stateless Session Bean deals withCustomer
Entity Bean)@javax.ejb.Stateless(mappedName = "Customer_management+", name = "Customer_management") @javax.ejb.Remote({Customer_managementRemote.class}) public class Customer_managementBean implements Customer_managementRemote { @javax.persistence.PersistenceContext(name = "FranckBarbier") // Check 'persistence.xml' file... private javax.persistence.EntityManager _entity_manager; @Override public void insert_customer(final String bank_code, final String customer_PIN, final String name, final String address) { Customer client = new Customer(bank_code, customer_PIN); client.set_name(name); client.set_address(address); _entity_manager.persist(client); } @Override public void delete_customer(final String bank_code, final String customer_PIN) { Customer client = new Customer(bank_code, customer_PIN); _entity_manager.remove(_entity_manager.merge(client)); } @Override public String view_customer(final String bank_code, final String customer_PIN) { String result = ""; Customer client = _entity_manager.find(Customer.class, new CustomerPK(bank_code, customer_PIN)); result += client != null ? "Found: " + client : "Not found: " + bank_code + "-" + customer_PIN; return result; } }
Session Beans
- Stateless Session Beans, J2EE 1.4 (Bean-Managed Transaction versus Container-Managed Transaction)
- Stateful Session Beans, J2EE 1.4 (Bean-Managed Transaction versus Container-Managed Transaction)
- Session Beans, from Java EE 5
- Singleton Session Beans (from Java EE 6, a kind of Stateless Session Beans)
- Stateless Session Beans
- Stateful Session Beans
Message-Driven Beans
- Bean-Managed Transaction -BMT- versus Container-Managed Transaction -CMT-
In the UML metamodel above, one shows that an Enterprise Bean is embodied by one and only one Java implementation class (
1..1
cardinality). By default, the Enterprise Bean name is the name of that class
- In EJB, a Java class is built by a developer to create some business functionality through a given set of business methods. Business methods differ from one category of EJB to another
- Entity Beans only offer data read/write/query methods plus a redefinition of the
hashCode
andequals
methods inherited fromjava.lang.Object
- Message-Driven Beans have one business method whose name is fixed once and for all:
public void onMessage(javax.jms.Message message);
- Session Beans offer one or more business methods; these methods are the atomic business functionality of a “wrapping” service or an application
- In EJB ver. 2.x, Enterprise Beans must own additional “technical” methods (which may be empty) to comply with what is expected by the Java EE application server; in other words, the absence of such technical methods may create errors at deployment time. Technical methods are in essence not exposed in components' interfaces because they are not called by other components. Instead, they are automatically called by the Java EE application server at precise moments within the components' lifecycle ☛. For example, the imposed format of a Message-Driven Bean in EJB ver. 3.x is ☛
- In Java,
this
embodies the current instance. Such a self-reference must be avoided in EJB because it is not a valid reference across Java EE VMs. Indeed, a given object representing in memory a/some component(s) is, by definition, stationary in its Java EE VM (i.e., not mobile across Java EE VMs). Instead ofthis
, a self-reference on any “current” component is required when, for instance, one wants to pass the component as argument of a business functionGetting a reference on “current” component (instead of using
this
)@javax.ejb.Stateful(mappedName = "My_terminal", name = "Railcar_control_system_terminal") public class TerminalBean implements Terminal { @javax.annotation.Resource private javax.ejb.SessionContext _ejb_context = null; Terminal _self = null; … _self = _ejb_context.getBusinessObject(Terminal.class); …
Key features
- Stateless Session Beans are the most common Enterprise Beans
- They are “shared” between client programs. In reality, in terms of Java instances, they are cloned. Several clones (Java instances) may represent the same component. So, between two business method calls, Stateless Session Beans do not keep a persistent state. Typically, one call uses a Java instance representing the called component while the second call uses another Java instance representing the same component
Creation and deletion
- Stateless Session Beans are created and deleted by the Java EE application server. More precisely, they are pooled and delivered to client programs (in terms of identities) according their availability. Access (implying either creation or recycling by the server) occurs either through dependency injection with the
@javax.ejb.EJB
annotation or through a JNDI lookupTransaction management
- Bean-Managed Transaction -BMT- versus Container-Managed Transaction -CMT-. In CMT mode, a transaction is started when a business method is called. It is closed when this business method ends
Design patterns
- Stateless Session Beans are the preferred means to deal with Entity Beans
- Stateless Session Beans play the role of façades according to the Façade ☛ design pattern
- They are the support for Web Services
Example
@javax.jws.WebService(serviceName = "Railcar_new_destination") @javax.ejb.Stateless public class Railcar_new_destination { …
Example
@javax.ejb.Remote public interface Customer_managementRemote { // Business methods… @javax.ejb.Stateless(mappedName = "Customer_management+", name = "Customer_management") // @javax.ejb.Remote({Customer_managementRemote.class}) // Alternative to using '@javax.ejb.Remote' above public class Customer_managementBean implements Customer_managementRemote { …
Illustration: complementarity between Entity Beans and Stateless Session Beans
A simple Java EE application is based on a Stateless Session Bean named
Customer_management
interacting with an Entity Bean namedCustomer
While Banking_system.JavaDB.sql
is the database schema, Customer_management.zip
is the “server” program, and Customer_management_client.zip
is the “client” program
Illustration consists in extending this application so that it supports Create, Read, Update, Delete -CRUD- functions for the
Logical_card
table in the database (please keep the database schema “as is”)
Key features
- Singleton Session Beans are designed for concurrent access (thread-safe); concurrent access is managed by their container (to be preferred) or manually (i.e., bean-managed)
Creation and deletion
- By definition, a singleton component has one and only instance, which is automatically created by the Java EE application server at deployment time
Transaction management
- Bean-Managed Transaction -BMT- versus Container-Managed Transaction -CMT-
Design patterns
- In general, Singleton Session Beans act as orchestrators, typically a control center receiving multiple concurrent requests and re-dispatching orders/jobs according to a centralized business logic ⤳ Singleton ☛ design pattern
Other features
@javax.ejb.Startup
is dedicated to Singleton Session Beans; it allows the immediate initialization (i.e., the method annotated by@javax.annotation.PostConstruct
is executed at application installation time instead of, when the Enterprise Bean is for the first time accessed)Example (EJB 3.x)
@javax.ejb.Local public interface Control_center_local { // Business methods locally accessed… @javax.ejb.Remote public interface Control_center_remote { // Business methods externally accessed… @javax.ejb.Singleton @javax.ejb.Startup public class Control_center implements Control_center_local, Control_center_remote { …
Key features
- Stateful Session Beans are created and deleted by client programs. These programs automatically own these components; they are unshared
- Stateful Session Beans are subject to passivation and activation by the Java EE application server. These two actions allow the server to carry out a load balancing strategy
Creation and deletion
- They are created once and for all by their clients (i.e., their owners; there is no sharing). Accordingly, the client is in charge of deletion. There is no default way of passing parameters at creation time. For that, the
@javax.ejb.Init
annotation is required. Creation occurs either through dependency injection with the@javax.ejb.EJB
annotation or through a JNDI lookup. Contrary to Stateless Session Beans, each lookup results in the creation of a new component!Transaction management
- Bean-Managed Transaction -BMT- versus Container-Managed Transaction -CMT-
Design patterns
- Stateful Session Beans record client program session data like, for instance, an e-commerce basket
Example (EJB 3.x)
@javax.ejb.Stateful public class Frontend_service { private int _counter = 0; @javax.ejb.EJB private Backend_service _backend_service; @javax.ejb.PrePassivate public void passivate() { _counter--; } @javax.ejb.PostActivate public void activate() { _counter++; } public void service(int i) { assert (_backend_service != null); _counter += i; System.out.println(this + "... " + _counter); _backend_service.service(_counter); } @javax.ejb.Remove public void remove() { // Called by the owner! // Resource release, if any... } }
Another example ☛
JMS
JMS ☛ is fully part of Java EE. JMS package is
javax.jms
. Middleware-oriented messaging like JMS enables the offer of additional services such as fault tolerance, load balancing, message persistence, transaction management…. Benefits are numerous
- Message-oriented programming means that receivers are not synchronized with senders. As a result, senders send messages in a broadcast mode to queues or topics
- Accountability of messages with persistence features (failure recovery through re-emission for instance), transaction management, priority and durability setup, consumption acknowledgment…
- Underlying support for “less abstract” technologies, namely JavaMail, which is fully integrated within Java EE
“Common messaging” versus broker-based messaging
![]()
JMS message types
TextMessage
BytesMessage
: raw dataObjectMessage
: it imposes serialization and Java-to-Java communicationMapMessage
: hashtableStreamMessage
: collection with data orderMessage
: empty messageExample (
javax.jms.MapMessage
)javax.jms.MapMessage order = _session.createMapMessage(); order.setString("entrée","foie gras"); order.setString("plat principal","magret"); order.setBoolean("dessert du jour ?",false); _sender.send(order);
Example (
javax.jms.ObjectMessage
, Java world only!)javax.jms.ObjectMessage ambient_temperature_changed = _session.createObjectMessage(); ambient_temperature_changed.setObject(_temperature); // '_temperature' is an instance of a type, which implements 'java.io.Serializable'... _sender.send(ambient_temperature_changed);
Key features
- The direct use of JMS in EJB is impossible. For this specific reason, Message-Driven Beans have been introduced in EJB to leverage a controlled utilization of JMS
- Message-Driven Beans must in essence by associated with JMS resources. Although JMS offers queue-based or topic-based communication, these two kinds of message repository have no difference in the EJB technology while native JMS programs handle queues and topics in a different way
- Message-Driven Beans cannot be accessed by other Enterprise Beans. In other words, Message-Driven Beans do not offer local or remote interfaces. More precisely, Session Beans or “external” programs (servelts, Java SE client programs, third-party client components…) send messages to JMS queues; these messages are consumed by Message-Driven Beans in an automated way
Creation and deletion
- Similar to Stateless Session Beans, Message-Driven Beans are replicated by the server without developer control. Creation and deletion can be synchronized
Transaction management
- Message-Driven Beans are either BMT or CMT. In CMT mode, only the
Required
orNotSupported
attributes are possible because no client program can access to Message-Driven Beans through interfacesDesign patterns
- Message-Driven Beans may cope with Entity Beans, Session Beans, even send messages to other JMS queues or topics
Example (message sending)
@javax.ejb.Singleton @javax.ejb.Startup public class Starter { private javax.jms.QueueConnectionFactory _queue_connection_factory; private javax.jms.Queue _queue; private javax.jms.QueueConnection _queue_connection; private javax.jms.QueueSession _queue_session; private javax.jms.QueueSender _queue_sender; @javax.annotation.PostConstruct public void create() { try { System.out.println("One starts immediately because of '@javax.ejb.Startup'..."); javax.naming.Context _jndi_context = new javax.naming.InitialContext(); _queue_connection_factory = (javax.jms.QueueConnectionFactory) _jndi_context.lookup("jms/MY_QUEUE_FACTORY"); _queue = (javax.jms.Queue) _jndi_context.lookup("jms/MY_QUEUE"); _queue_connection = _queue_connection_factory.createQueueConnection(); _queue_session = _queue_connection.createQueueSession(false, javax.jms.Session.AUTO_ACKNOWLEDGE); _queue_sender = _queue_session.createSender(_queue); _queue_sender.send(_queue_session.createTextMessage("0")); _queue_sender.send(_queue_session.createTextMessage("1")); _queue_sender.send(_queue_session.createTextMessage("1")); Thread.sleep(1000); _queue_sender.send(_queue_session.createTextMessage("Stop...")); } catch (Exception e) { // Error... } } }
Example (message reception and processing - EJB 3.x)
@javax.ejb.MessageDriven(mappedName = "jms/MY_QUEUE", activationConfig = { @javax.ejb.ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge"), @javax.ejb.ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue") }) public class Receiver implements javax.jms.MessageListener { @javax.annotation.Resource private javax.ejb.MessageDrivenContext _ejb_context; // Optional, but necessary for getting a transaction object (BMT mode) @javax.annotation.PostConstruct public void construct() { // Resource acquisition } @Override public void onMessage(javax.jms.Message message) { if (message instanceof javax.jms.TextMessage) … } @javax.annotation.PreDestroy public void destroy() { // Resource release } }
Key features
- Entity Beans are exact (synchronized) images of rows in SQL tables. CRUD actions in databases amount to acting on Entity Bean instances in memory. Entity Beans are constructed on the top of the JPA technology, which is (also) runnable in the Java SE world
Creation and deletion
- Entity Beans are comparable to Stateless Session Beans. Accordingly, client programs (or client components) get access to, and handle Entity Bean instances by requesting data in databases
- Entity Bean instances are transparently shared by clients. Several Entity Bean instances may represent, in the middleware, the same row in a table. The middleware (the Java EE application server) delivers these instances according to the current load (client programs' requests)
Additional information on Entity Beans requires a survey of the JPA technology ☛
Transaction management
- Entity Beans are CMT Enterprise Beans
Design patterns
- In general, an Entity Bean type matches to a table in database, e.g., the
Invoice
Entity Bean matches to theInvoice
table. However, a one-to-one matching is not always a good solution in the sense that one table may lead to several Entity Bean types while, differently, several tables may match to a single Entity Bean typeExample ☛
Lifecycle management
@javax.annotation.PostConstruct
(ejbCreate
in EJB ver. 2.x): it is triggered after dependency injectionPassivation and activation
Because resources on Java EE application servers decrease performance, developers must take care of releasing these resources when unused. This may occur when Enterprise Beans are destroyed. This may also occur when Enterprise Beans like Stateful Session Beans are passivated
Example (how to optimally handle a naming context)
private javax.naming.Context _jndi_context; …
@javax.ejb.PrePassivate public void passivate() { if (_jndi_context != null) _jndi_context.close(); // This code may raise an exception if the resource has been obtained through dependency injection _jndi_context = null; // Safer in case of dependency injection }
@javax.ejb.PostActivate public void activate() { _jndi_context = new javax.naming.InitialContext(); }
Note: in general, resources acquired by dependency injection must not be managed by developers. In other words, the best solution when releasing such resources is to assign
null
to the variable embodying the resource
An Enterprise Bean container is a kind of controller. Effectively, a container is an instance of a Java class generated by the application server at deployment time. This class mixes the Java code released by the EJB's developer with the configuration attribute values assigned by this developer to its EJB. For example, an Enterprise Bean container opens and closes transactions (CMT mode) on the behalf on the Enterprise Bean, which delegates this charge to its container. For various reasons, Enterprise Beans must sometimes access to their execution context materialized by their container in order to access resources/facilities. As an illustration, the BMT mode requires the access to the current transaction ☛
Interacting with a container (a.k.a. execution context)
- The
javax.ejb.SessionContext
interface is dedicated to Session Beans- The
javax.ejb.EntityContext
interface is dedicated to Entity Beans- The
javax.ejb.MessageDrivenContext
interface is dedicated to Message-Driven BeansIn EJB ver. 2.x, one may, for instance, access to the execution context of a Session Beans instance
Example (EJB ver. 2.x)
public class X_bean implements SessionBean { private SessionContext _ejb_context; public void setSessionContext(SessionContex ejb_context) { _ejb_context = ejb_context; } …
The access to the Session Bean itself (then avoiding
this
) is as followsExample (EJB ver. 2.x)
X_remote x_remote = _ejb_context.getEJBObject(); // 'X_remote' is a Java interface that is declared in a XML file as the remote interface of 'X_bean'
In EJB ver. 3.x, one accesses to the execution context of a Session Bean instance through dependency injection ☛
Dependencies are links at run-time so that Enterprise Beans are able to interact. Dependencies are also concerned by links between software components and services on one side and, resources (databases, JMS queues/topics…) on another side
From Java 5, resource injection (or dependency injection) is a key mechanism to set up dependencies between Enterprise Beans. From Java 6, the Context and Dependency Injection -CDI- mechanism is a more powerful mechanism. Historically, the EJB technology uses the Java Naming and Directory Interface -JNDI- technology to dynamically create references embodying dependencies between Enterprise Beans
Dependency design patterns
- Entity Beans may be accessed by Session Beans and Message-Driven Beans. Typically, accessing to Entity Beans occurs through an entity manager as follows
@javax.persistence.PersistenceContext(name = "My_persistence_unit") // 'My_persistence_unit' is a symbolic name; it must be associated with a Java EE application server's database resource in the 'persistence.xml' file private javax.persistence.EntityManager _entity_manager;
- Session Beans may be accessed by Session Beans and Message-Driven Beans as follows
- Dependency injection that supposes that Enterprise Beans are in the same virtual machine
- Dependency based on implicit naming
@javax.ejb.Stateless public class Customer_managementBean implements Customer_managementRemote { … // In another EJB: @javax.ejb.EJB Customer_managementRemote cm = null;
- Dependency based on explicit naming
@javax.ejb.Stateless(mappedName = "Customer_management+", name = "Customer_management") // 'name' attribute is information only; it is not used in resource injection! public class Customer_managementBean implements Customer_managementRemote { … // In another EJB: @javax.ejb.EJB(mappedName = "Customer_management+") Customer_managementRemote cm = null;
- JNDI
- // Normalized form from EJB 3.1 only
@javax.ejb.Stateless(mappedName = "Customer_management+", name = "Customer_management") public class Customer_managementBean implements Customer_managementRemote { … // Later on: javax.naming.Context jndi_context = new javax.naming.InitialContext(); Customer_managementRemote cm = (Customer_managementRemote)jndi_context.lookup("java:global/My_EJB_module/Customer_management+"); // 'My_EJB_module' is the name of the deployment file, say 'My_EJB_module.jar' or 'My_EJB_module.ear'
- // Non-portable (across Java EE application servers) even common form
@javax.ejb.Stateless(mappedName = "Customer_management+", name = "Customer_management")
public class Customer_managementBean implements Customer_managementRemote { … // Later on: javax.naming.Context jndi_context = new javax.naming.InitialContext(); Customer_managementRemote cm = (Customer_managementRemote)jndi_context.lookup("Customer_management+");- Reminder: Message-Driven Beans are not accessible by other EJB types!
Resource dependency management
<resource-ref>
: coupling with JDBC connection pool, JMS connection factory…<resource-env-ref>
: coupling with ready-to-use resource, e.g., JMS queue- Reenforcing the checking of component-to-component dependencies at deployment time ☛
Local, remote or no interface at all?
- The no-interface view is quite similar to a local view (caution: all public methods are then locally exposed!). Either
@javax.ejb.LocalBean
or no interface declaration allows a no-interface view. Such an interface configuration is not appropriate when, for instance, one wants to access to the Session Bean from a client programNo interface declaration
Alternatively@javax.ejb.Singleton public class Control_center { …
@javax.ejb.Singleton @javax.ejb.LocalBean public class Control_center { …
@javax.ejb.Local
. This annotation is the way to define a local business interface. Assigning a local business interface to a Session Bean is as followsSimple way
Alternatively@javax.ejb.Stateful @javax.ejb.Local(Railcar.class) public class RailcarBean implements Railcar { … // The implementation of the Java interface is not mandatory but it greatly reinforces Java type checking
@javax.ejb.Local public interface Railcar { … @javax.ejb.Stateful public class RailcarBean implements Railcar { …
@javax.ejb.Remote
. This annotation is the way to define a remote business interfaceSimple way
Alternatively@javax.ejb.Singleton @javax.ejb.Remote(Control_center_remote.class) public class Control_center implements Control_center_remote { … // The implementation of the Java interface is not mandatory but it greatly reinforces Java type checking
@javax.ejb.Remote public interface Control_center_remote { … @javax.ejb.Singleton public class Control_center implements Control_center_remote { …
- Sophisticated cases are when one needs both local and remote accesses to the Session Bean depending upon varied client program types. This approach may be extended by creating multiple local interfaces and/or multiple remote interfaces for the same Session Bean
@javax.ejb.Local public interface Control_center_local { … @javax.ejb.Remote public interface Control_center_remote { … @javax.ejb.Singleton public class Control_center implements Control_center_local, Control_center_remote { …
- Further detail on the way of accessing Session Beans ☛
The case of “home” interfaces being local or remote
Local or remote “home” interfaces are a concept from older EJB versions, prior to 3.x especially. However, they remain useful in certain cases, namely when one want to initialize Session Beans with specific values at creation time. For that, the
javax.ejb.Init
annotation may be used
@javax.ejb.Remote
annotationEnterprise Beans are located (packaged) in an EJB module. An EJB module is a unit of deployment. An instance of an EJB of type
A
in an EJB module can access to an instance of an EJB of typeB
in another EJB module only if and only ifB
is annotated with@javax.ejb.Remote
.@javax.ejb.Remote
has to be used sparingly. It is especially useful when one distributes EJB modules to different Java EE VMs (i.e., Java EE application server running instances)Illustration: “local” versus “remote” interface for Stateless Session Beans
A simple Java EE application Test_Asterix_Obelix.zip
relies on
Asterix
Asterix.zipand
Obelix
Obelix.zipas two collaborative Session Beans.
Asterix
has a business method namedstrength
, which itself calls a business method offered byObelix
also namedstrength
The issue of about the exposure of
Obelix
betweenjavax.ejb.LocalBean
,javax.ejb.Local
, andjavax.ejb.Remote
- Implement
Asterix
andObelix
in the same EJB module as follows:
- Both are Stateless Session Beans (use the following annotation value for
Obelix
:mappedName = "OBELIX"
)- Dependency injection in
Asterix
toObelix
as follows:@javax.ejb.EJB(mappedName = "OBELIX") Obelix o = null;
- Call of
Obelix
strength
inAsterix
strength
:o.strength();
- Implement
Asterix
andObelix
in two different EJB modules. Change the code in bothAsterix
andObelix
so thatstrength
inAsterix
is still able to callstrength
inObelix
From EJB 3.x, it exists two major mechanisms to deal with concurrency, more precisely, to control the concurrent access to a component
@javax.ejb.Singleton
is an annotation devoted to Singleton Session Beans (intra-parallelism)@javax.ejb.Asynchronous
is an annotation dedicated to Session Beans (inter-parallelism) only (further detail from Java EE 8 tutorial ☛)
- Asynchronous methods return values having either the
void
or thejava.util.concurrent.Future<T>
type; the latter case allows full control on the asynchronous called method- Asynchronous methods for Stateless Session Beans and Singleton Session Beans are useful when one wants to immediately pick up the control after the call of the asynchronous method; in other cases, it is useless because Stateless Session Beans are duplicated while Singleton Session Beans are thread-safe by construction
- Asynchronous methods for Stateful Session Beans are illustrated within the Railcar control system case study ☛
Example
@javax.ejb.Remote({Obelix.class}) @javax.ejb.Stateless(mappedName = "ejb/Obelix") public class Obelix_implementation implements Obelix { @javax.ejb.Asynchronous // The result is returned to the Enterprise Bean container, not directly to the client component... @Override public java.util.concurrent.Future<String> complain() { return new javax.ejb.AsyncResult<>("Arrrrrgggglllll"); } @Override public String strength() { return "I'm really the strongest... "; } }
@javax.ejb.EJB(mappedName = "ejb/Obelix", lookup = "ejb/Obelix") Obelix o = null; @Override public void strength() { java.util.concurrent.Future<String> result = o.complain(); try { System.out.println(o.strength() + (result.isDone() ? result.get() : "not yet available, operation canceled: " + result.cancel(false))); } catch (InterruptedException | java.util.concurrent.ExecutionException ex) { java.util.logging.Logger.getLogger(Asterix.class.getSimpleName()).log(java.util.logging.Level.SEVERE, null, ex); } }
Enterprise Beans are by default not reentrant. This means that an Enterprise Bean involved in a business method cannot receive at the same time a request from elsewhere demanding the execution of the same, or another offered, business method. Reentrance is firstly linked to transactions. If the executing business method is configured such that it is included within a transaction, calling at the same time the Enterprise Bean is incompatible with the ongoing transaction, which handles the Enterprise Bean as an exclusive resource
Otherwise, reentrance is also not possible even if the transaction mode is set to BMT (
@javax.ejb.TransactionManagement(javax.ejb.TransactionManagementType.BEAN)
) or is not supported (@javax.ejb.TransactionAttribute(javax.ejb.TransactionAttributeType.NOT_SUPPORTED)
). In this case, no transaction is in progress but the Enterprise Bean is nevertheless active for the execution duration of a given business method![]()
Reentrance is mainly concerned with Stateful Session Beans because references to other Enterprise Beans do not require to be kept. Reentrance issues have been better addressed in EJB ver 3.x with the arrival of Singleton Session Beans
Key features
- A great advantage of Java EE is the availability of an internal transaction manager based on Java Transaction Service -JTS-. From a utilization viewpoint, Java Transaction API -JTA- ☛ is the entry point with
javax.transaction.Transaction
as main interface- Transactions allow the cancellation or the validation of data in DBMS. JTS is independent of most of DBMSs. Using JTS imposes the abort of the provided, specific or not, mechanism of DBMSs for managing transactions. Typically, JTS excludes mechanisms supported by other Java technologies like JDBC, which enables
COMMIT
orROLLBACK
through thejava.sql.Connection
interface. Furthermore, JTS does not support nested transactions as follows (Oracle DBMS SQL code)So, JTS promotes a canonical transaction management framework in Java EE in general and EJB in particular. Namely, transactions are associated with business method calls only (Session Beans) orsavepoint transaction1; insert into …; savepoint transaction2; /* Nesting here */ insert into …; commit transaction2; /* One may validate, if desired, from the beginning of 'transaction2' only */
onMessage
(Message-Driven Beans). By default, a transaction starts and stops in relation with the execution time of a business method oronMessage
The general functioning of a transaction is as follows
In this example, one may imagine that step 2 fails (a raised exception materialized such a failure). The overall business logic is such that step 3 must not success. Having a transaction associated with step 1 guarantees a consistent (collaborative) functioning between step 2 and step 3
Container-Managed Transaction -CMT-
- This is the default mode for Session Beans and Message-Driven Beans (Entity Beans are by definition CMT Enterprise Beans)
- This mode greatly lightens EJB developers' code since they are not in charge of starting, stopping… transactions. However, despite these nice facilities, in subtle cases, they must analyze and/or handle the result of transactions' progress with great care
- CMT transaction types and their resulting basic behaviors are detailed ☛
Required
is the default mode. Typically, for a business method namedmy_business_method
- No transaction in progress ⤳ a new one is started,
- or a transaction is in progress ⤳ the behavior of
my_business_method
is viewed as the continuation of the caller business method in the existing transaction (no nesting!)- Other modes can be setup on demand. For example, business methods that do not change the state of components (similar to
const
functions in C++) may be annotated as follows@javax.ejb.Stateful public class TerminalBean implements Terminal { @javax.ejb.TransactionAttribute(javax.ejb.TransactionAttributeType.NOT_SUPPORTED) public String get_name() { … …
Containers roll back transactions in case of “system” failures, namely when a
javax.ejb.EJBException
is raised. However, there are some tricky cases when such an exception is not raised. At the same time, one wants to roll back the transaction because of a local business dysfunction, which is not captured by the container. In this specific case, one rolls back the current transaction while the CMT mode is active@javax.annotation.Resource private javax.ejb.SessionContext _ejb_context = null; … assert(_ejb_context != null); javax.transaction.UserTransaction ut = _ejb_context.getUserTransaction(); … if(/* some test */) ut.setRollbackOnly();
Bean-Managed Transaction -BMT-
In this case, the developer must setup the Enterprise Bean so that it may benefit from the BMT status
@javax.ejb.Stateful @javax.ejb.TransactionManagement(javax.ejb.TransactionManagementType.BEAN) public class RailcarBean implements Railcar { …
Next, she/he must catch the ongoing transaction, start it, stop it through the
COMMIT
orROLLBACK
facilities@javax.annotation.Resource private javax.ejb.SessionContext _ejb_context = null; … assert(_ejb_context != null); javax.transaction.UserTransaction ut = _ejb_context.getUserTransaction(); ut.begin(); … if(/* some test */) ut.commit(); else ut.rollback();
Transactions in Message-Driven Beans
Message consumption is associated with an acknowledgement mechanism. Message acknowledgement is automatic unless specific settings. By default, acknowledgment leads to
COMMIT
while other situations lead toROLLBACK
(e.g., failure withinonMessage
)Fine-grain transaction control
There is a support for managing transactions with higher accuracy (CMT Stateful Session Beans only): namely, when transactions are to be started, they are to be completed and have just completed. The
javax.ejb.SessionSynchronization
☛ interface is devoted to this job
The deep nature of Enterprise Beans is the possibility of configuring deployment values. These values are that of parameters, which are interpretable by a Java EE application server. The latter transforms the developer's values into code in order to match to the execution environments characteristics, constraints, etc. Application server administration allows the introduction of homemade parameters but, it is outside the scope of this tutorial. Configuration preferably occurs through XML files (EJB 2.x and older versions) or annotations (EJB 3.x). The last approach does not exclude the utilization of XML files in tricky cases. The core configuration file is the
ejb-jar.xml
file. So, for example, in aged EJB versions (2.x), transaction attributes may be setup inejb-jar.xml
as follows (one declares that all (*
) business methods ofMy_bean
have theRequiresNew
transaction attribute)<ejb-jar …> <!--EJB ver. 2.x--> … <assembly-descriptor> … <container-transaction> <method> <ejb-name>My_bean</ejb-name> <method-name>*</method-name> </method> <trans-attribute>RequiresNew</trans-attribute> </container-transaction> </assembly-descriptor> </ejb-jar>
There are some other important configurations files like
persistence.xml
-JPA- orglassfish-resources.xml
. The latter is a proprietary file of the Glassfish Java EE application server. Any configured value within this file is not portable across application servers. For example, one may force Glassfish to create no more than 1 instance of a given Message-Driven Bean with<max-pool-size>1</max-pool-size>
EJB dependencies in
ejb-jar.xml
file<?xml version="1.0" encoding="UTF-8"?> <ejb-jar xmlns="http://xmlns.jcp.org/xml/ns/javaee" version="3.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/ejb-jar_3_2.xsd"> <!--EJB ver. 3.x--> <enterprise-beans> <session> <ejb-name>My_Asterix</ejb-name> <business-remote>Asterix.Asterix</business-remote> <ejb-class>Asterix.Asterix_implementation</ejb-class> <session-type>Stateless</session-type> <transaction-type>Container</transaction-type> <ejb-ref> <ejb-ref-name>ejb/Obelix</ejb-ref-name> <ejb-ref-type>Session</ejb-ref-type> <remote>Obelix.Obelix</remote> </ejb-ref> </session> </enterprise-beans> </ejb-jar>
EJB applications are packaged in EJB modules or in EJB applications (
.ear
or.jar
files). Files including source files and configuration data must be located in precise directories with a special tree structure
Asterix_V2.jar > Asterix > Asterix.class
Asterix_V2.jar > Asterix > Asterix_implementation.class
Asterix_V2.jar > META-INF > MANIFEST.MF
Asterix_V2.jar > META-INF > ejb-jar.xml
Security features can be setup at design to be experienced at run-time
- EJB 2.x
- Design time
<role-name>FranckBarbier</role-name>
- Run-time
if(_ejb_context.isCallerInRole("FranckBarbier")) { … // Client program has appropriate role java.security.Principal principal = _ejb_context.getCallerPrincipal(); // Current authentified client program
- EJB 3.x
@javax.ejb.Stateless @javax.ejb.Remote(CurrencyConverter.class) @javax.jws.WebService(serviceName = “CurrencyConverter”) @javax.annotation.security.DeclareRoles(“FranckBarbier”, “MireilleMathieu”) public class CurrencyImplementation implements CurrencyConverter { @javax.annotation.security.RolesAllowed(“FranckBarbier”) double convert(double amount, Currency source_currency, Currency target_currency, RoundingType rounding /*, etc.*/) …
Service computing in EJB
The big picture: the Java EE platform itself provides “technical” services as provided by any middleware. The major Java EE services are transaction management, security, performance (load balancing), persistence, naming, messaging… Most of them often come from the Java EE sublayer. As an illustration, practically, the Glassfish Java EE application server may be built on the top of CORBA ☛ that itself supports technical services: COS naming, CORBA Object Transaction Service -OTS-… OSGi is another candidate for Java EE application server implementation. In EJB, there are also business services that are the primary way of modularizing applications through the sharing of these software components among several enterprise applications. Endowing these business services with Internet interoperability leads to giving the status of Web services to Stateless Sessions Beans
Support for Web services
Stateless Sessions Beans (including Singleton Sessions Beans) annotated with
@javax.ejb.WebService
can be accessed as a Web service ☛CDI
The
beans.xml
file is dedicated to CDI. It can be empty
Quiz 1
Soit le code EJB qui suit.
S1
etS2
sont dans le même EJB module@javax.ejb.Stateless public class S1 { private int _i; public void increment() { _i++; } public int get_i() { return _i; } }
@javax.ejb.Singleton @javax.ejb.Startup public class S2 { @javax.ejb.EJB private S1 _s1; @javax.ejb.EJB private S1 _s1_bis; @javax.annotation.PostConstruct public void g() { int result = 0; _s1.increment(); result += _s1.get_i(); _s1.increment(); result += _s1.get_i(); System.out.println("result (g): " + result); } public void h() { int result = 0; _s1.increment(); result += _s1.get_i(); _s1_bis.increment(); result += _s1_bis.get_i(); System.out.println("result (h): " + result); } }
- Au déploiement de l’EJB module, que se passe-t-il ? Répondre en choisissant parmi les hypothèses suivantes :
- rien n’est affiché
- est affiché un entier positif ou nul
- est affiché un entier ne pouvant varier que dans l’intervalle [0..3]
- est affiché 3 exactement dans tous les cas d’exécution
- est affiché 2 exactement dans tous les cas d’exécution
- L’annotation
@javax.annotation.PostConstruct
est placée sur la méthodeh
dansS2
(et supprimée sur la méthodeg
). Au déploiement de l’EJB module, que se passe-t-il ? Répondre en choisissant parmi les hypothèses suivantes :
- rien n’est affiché
- est affiché un entier positif ou nul
- est affiché un entier ne pouvant varier que dans l’intervalle [0..2]
- est affiché un entier ne pouvant varier que dans l’intervalle [0..3]
- est affiché 3 exactement dans tous les cas d’exécution
- est affiché 2 exactement dans tous les cas d’exécution
- L’annotation
@javax.ejb.Stateless
surS1
est remplacée par@javax.ejb.Stateful
et l’annotation@javax.annotation.PostConstruct
est mise sur la méthodeg
dansS2
. Au déploiement de l’EJB module, que se passe-t-il ? Répondre en choisissant parmi les hypothèses suivantes :
- rien n’est affiché
- est affiché un entier positif ou nul
- est affiché un entier ne pouvant varier que dans l’intervalle [0..2]
- est affiché un entier ne pouvant varier que dans l’intervalle [0..3]
- est affiché 3 exactement dans tous les cas d’exécution
- est affiché 2 exactement dans tous les cas d’exécution
- L’annotation
@javax.ejb.Stateless
surS1
est remplacée@javax.ejb.Stateful
et l’annotation@javax.annotation.PostConstruct
est sur la méthodeh
dansS2
. Au déploiement de l’EJB module, que se passe-t-il ? Répondre en choisissant parmi les hypothèses suivantes :
- rien n’est affiché
- est affiché un entier positif ou nul
- est affiché un entier ne pouvant varier que dans l’intervalle [0..2]
- est affiché un entier ne pouvant varier que dans l’intervalle [0..3]
- est affiché 3 exactement dans tous les cas d’exécution
- est affiché 2 exactement dans tous les cas d’exécution
Quiz 2
Dans le code EJB qui suit MDB.EJB.zip
,
Starter
etDispatcher
sont dans le même EJB module alors queService
est dans un autre EJB moduleLe développeur souhaite voir affiché dans le log du serveur : « To be or not to be, this is the question… ». Malheureusement, ce n'est pas le cas. Modifier le programme pour obtenir ce résultat
Note : création de ressources JMS avec
asadmin
☛public class My_message implements java.io.Serializable { final String _word; public String getWord() { return _word; } final int _order; public int getOrder() { return _order; } My_message(String content, int order) { _word = content; _order = order; } } /***************************************/ public interface Service { void construct_sentence(My_message my_message); void display_sentence(); boolean stop(); } /***************************************/ @javax.ejb.Local({Service.class}) @javax.ejb.Stateful public class Service_implementation implements Service { private final java.util.Vector<String> _sentence = new java.util.Vector<>(); public void construct_sentence(My_message my_message) { if (my_message.getOrder() + 1 > _sentence.size()) _sentence.setSize(my_message.getOrder() + 1); _sentence.set(my_message.getOrder(), my_message.getWord()); } public void display_sentence() { String sentence = ""; for (String word : _sentence) sentence += word; System.out.println(sentence); } public boolean stop() { int n = 0; for (String word : _sentence) if (word != null) n++; return n == Starter.Number; } } /***************************************/ @javax.ejb.MessageDriven(activationConfig = {@javax.ejb.ActivationConfigProperty(propertyName = "destinationLookup", propertyValue = "jms/MY_QUEUE"), @javax.ejb.ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue")}) public class Dispatcher implements javax.jms.MessageListener { @javax.ejb.EJB private Service _service = null; @Override public void onMessage(javax.jms.Message message) { try { My_message my_message = (My_message) ((javax.jms.ObjectMessage) message).getObject(); _service.construct_sentence(my_message); if (_service.stop()) _service.display_sentence(); } catch (Exception e) { // Error... } } } /***************************************/ @javax.ejb.Singleton @javax.ejb.Startup public class Starter { public static final int Number = 10; private javax.jms.QueueConnectionFactory _queue_connection_factory; private javax.jms.Queue _queue; private javax.jms.QueueConnection _queue_connection; private javax.jms.QueueSession _queue_session; private javax.jms.QueueSender _queue_sender; @javax.annotation.PostConstruct public void create() { try { javax.naming.Context _jndi_context = new javax.naming.InitialContext(); _queue_connection_factory = (javax.jms.QueueConnectionFactory) _jndi_context.lookup("jms/MY_QUEUE_FACTORY"); _queue = (javax.jms.Queue) _jndi_context.lookup("jms/MY_QUEUE"); _queue_connection = _queue_connection_factory.createQueueConnection(); _queue_session = _queue_connection.createQueueSession(false, javax.jms.Session.AUTO_ACKNOWLEDGE); _queue_sender = _queue_session.createSender(_queue); int i = 0; _queue_sender.send(_queue_session.createObjectMessage(new My_message("To ", i++))); _queue_sender.send(_queue_session.createObjectMessage(new My_message("be ", i++))); _queue_sender.send(_queue_session.createObjectMessage(new My_message("or ", i++))); _queue_sender.send(_queue_session.createObjectMessage(new My_message("not ", i++))); _queue_sender.send(_queue_session.createObjectMessage(new My_message("to ", i++))); _queue_sender.send(_queue_session.createObjectMessage(new My_message("be, ", i++))); _queue_sender.send(_queue_session.createObjectMessage(new My_message("this ", i++))); _queue_sender.send(_queue_session.createObjectMessage(new My_message("is ", i++))); _queue_sender.send(_queue_session.createObjectMessage(new My_message("the ", i++))); _queue_sender.send(_queue_session.createObjectMessage(new My_message("question...", i++))); assert (i == Number); } catch (Exception e) { // Error... } } }
Quiz 3
Dans le code EJB qui suit, toute instance d’EJB
My_stateful
maintient une liste de références (champ_collection_of_My_stateless_remote
) sur une collection d’EJBsMy_stateless
public interface My_stateless_remote { void business(); } … @javax.ejb.Stateless public class My_stateless implements My_stateless_remote { @Override public void business() { // Any business code here } }
public interface My_stateful_remote { void business(); } … @javax.ejb.Stateful @javax.ejb.Remote(My_stateful_remote.class) public class My_stateful { private java.util.Collection<My_stateless_remote> _collection_of_My_stateless_remote; // Le code des questions s’ajoute ici… }
- Est-ce que ce lien (cette liste de réf.) est susceptible de causer des erreurs à l’exécution ?
- Est-ce que ce lien est susceptible d’améliorer la performance à l’exécution ?
- En EJB, il n’est pas possible de faire une injection de ressource sur une collection. En d’autres termes, ce code ne fonctionne pas :
Bien que ce code fonctionne, quelle est une meilleure alternative ?// '@javax.ejb.EJB' est mise en commentaires car ne fonctionne pas... private java.util.Collection<My_stateless_remote> _collection_of_My_stateless_remote;
Pour pallier le problème, on « capture » les composants différemment (ce code s'ajoute au code préalable) :
My_stateful() throws Exception { javax.naming.Context jndi_context = new javax.naming.InitialContext(); for (int i = 0; i < 10; i++) { My_stateless_remote msr = (My_stateless_remote) jndi_context.lookup("java:global/My_EJB_module/My_stateless"); // 'My_EJB_module' is the name of the deployment file _collection_of_My_stateless_remote.add(msr); } }
- Soit la méthode
business
dans la classeMy_stateful
(ce code s'ajoute au code préalable) :Bien que ce code fonctionne, quelle est une meilleure alternative ?public void business() { for (My_stateless_remote msr : _collection_of_My_stateless_remote) msr.business(); }
Quiz 4
Implémenter le programme Lotto! ☛ en EJB Tirage_loto.EJB.zip
sous les contraintes suivantes :
Tirer_un_chiffre
est un composant assurant un seul servicetirer
retournant un chiffre dans un intervalle[1-borne]
Tirer_tous_les_chiffres
(dont lemappedName
est"Loto"
) est un composant assurant un servicetirer
établissant un tirage de 48 chiffres différents dans l'intervalle[1-49]
. Une autre business methodstocker
envoie le résultat du tirage dans une file d'attente JMS.Tirer_tous_les_chiffres
utiliseTirer_un_chiffre
- Faire un programme de test qui appelle
tirer
puisstocker
sur"Loto"