This tutorial on the Enterprise JavaBeans™ (EJB) component model is based on the Java Enterprise Edition (Java EE) 8 API (Application Programming Interface) and EJB version 3.2. Java EE 8 tutorial is here…
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, database synchronization…
- 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, JSP (JavaServer Pages), JSF (JavaServer Faces), JMS (Java Message Service), JCA (Java Connector Architecture), JTS (Java Transaction Service)/JTA (Java Transaction API)…
- Java EE component model: Enterprise JavaBeans™ (EJB)
- Java EE service computing: JWS (Java Web Services)
- WebSockets
- JSON (JavaScript Object Notation) processing
- Further details: Java EE 8 key technologies and APIs
Java EE products (Java EE application servers)
- GlassFish
- Oracle Fusion Middleware
- Payara
- TomEE
- WebSphere
- Wildfly
- Further details: Java EE application servers
Java EE challengers: Django, Drupal, .NET, Spring, Node.js…
Java EE Application Model is here…
Java EE 8 API (here)
- 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 first 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 VM (Virtual Machine) 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 or JPA), transaction management (Java Transaction API or JTA), messaging (Java Message Service or 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 the Software as a Service (SaaS) idea in cloud computing
Benefits
- The EJB technology is a Java standard in the sense it is a JSR and therefore, a vendor-free technology
- Maturity, high availability, credibility… and nice facilities in famous IDEs like Apache NetBeans
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 setup 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
JPQL (Java Persistence Query Language, which replaces EJB QL ver. 3). All database accesses occur through the Entity Bean container. Mapping between tables in databases and Entity Beans are setup 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. Otherwise:
- 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 (see this section). For example, the imposed format of a Message-Driven Bean in EJB ver. 3.x is as follows.
- In Java,
this
embodies the current instance. Such a self-reference must be avoided in EJB because a given object representing in memory a/some component(s) is not a portable reference across Java EE VMs. Instead ofthis
, a self-reference on the current component is required when, for instance, one wants to pass the component as argument of a business function. Here is the way of getting a reference on the “current” component instead of usingthis
:@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 JNDI lookups.Transaction 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 { …
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. See also 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 JNDI lookups. 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 here…
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:
- 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, etc.
- Underlying support for “less abstract” technologies, namely JavaMail, which is fully integrated within Java EE.
- Intuitive messaging versus broker-based messaging (right-hand side):
- 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 interfaces.Design patterns
- Message-Driven Beans may cope with Entity Beans, Session Beans, even send messages to other JMS queues.
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 (here).
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 type.Example here…
Lifecycle management
@javax.annotation.PostConstruct
(ejbCreate
in EJB ver. 2.x): it is triggered after dependency injection.Passivation 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 (example).
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
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 follows:Example
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 (example here).
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 setup 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 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+");- 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 setup is not appropriate when, for instance, one wants to access to the Session Bean from a client program.No 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 follows:Simple 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 interface:Simple 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 { …
- More details 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).
From EJB 3.x, it exists two major mechanisms to deal with concurrency, more precisely, to control the concurrent access to a component. These are:
@javax.ejb.Singleton
, an annotation devoted to Singleton Session Beans (intra-parallelism);@javax.ejb.Asynchronous
, an annotation dedicated to Session Beans (inter-parallelism) only (further details 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 the DBMS providers. Using JTS imposes the abort of the DBMS' own mechanism 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 operation 2 fails (a raised exception materialized such a failure). The overall business logic is such that operation 3 must not success. Having a transaction associated with operation 1 guarantees a consistent (collaborative) functioning between operation 2 and operation 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 here…
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
functions:@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. For example:
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 (example here).Timer service
For reliability reasons, the Java SE API for timers (i.e.,
java.util.Timer
andjava.util.TimerTask
…) has to be avoided in EJB applications because of distribution especially across Java VMs. Moreover, since Stateful Session Beans can be passivated, timer services are not allowed for this kind of Enterprise Beans. This book (§ 8.5.6) briefly explains how to implement timer services in Stateful Session Beans. Otherwise, a concise example of using timer services in Enterprise Beans may be found here…CDI
The
beans.xml
file is dedicated to CDI. It can be empty.