Writing an EJB
For all types of EJBs, you need to provide three Java interfaces/classes
to fully describe the EJB to an EJB container:
- Home Interface
- Remote Interface
- Bean Class
Home Interface
The home interface exists for each EJB and allows:
- The creation of all EJB Objects
- The removal of all EJB Objects
- Finding of Entity Beans
It extends the EJBHome interface which provides the following methods:
public interface EJBHome extends Remote
{
EJBMetaData getEJBMetaData();
// Obtain the EJBMetaData interface for the enterprise Bean.
HomeHandle getHomeHandle();
// Obtain a handle for the remote home object.
void remove(Handle handle);
// Remove an EJB object identified by its handle.
void remove(java.lang.Object primaryKey);
// Remove an EJB object identified by its primary key.
}
|
The remote home interface is defined by the enterprise Bean provider
and implemented by the enterprise Bean container.
import javax.ejb.*;
import java.rmi.RemoteException;
public interface MyHomeInterface extends EJBHome
{
public MyRemoteInterface create()
throws RemoteException;
....
}
|
Remote Interface
The EJBObject interface is extended by all enterprise Beans' remote
interfaces. An enterprise Bean's remote interface provides the remote
client view of an EJB object. An enterprise Bean's remote interface
defines the business methods callable by a remote client.
public interface EJBObject extends Remote
{
EJBHome getEJBHome()
// Obtain the enterprise Bean's remote home interface.
Handle getHandle()
// Obtain a handle for the EJB object.
java.lang.Object getPrimaryKey()
// Obtain the primary key of the EJB object.
boolean isIdentical(EJBObject obj)
// Test if a given EJB object is identical to the invoked
// EJB object.
void remove()
// Remove the EJB object.
}
|
The enterprise Bean's remote interface is defined by the enterprise
Bean provider and implemented by the enterprise Bean container.
import javax.ejb.*;
import java.rmi.RemoteException;
public interface MyRemoteInterface extends EJBObject
{
// business method definitions all of which throw
// a RemoteException
}
|
Bean Class
The bean class provides implementations for business methods. The
bean class does not have to implement the remote interface. If it
does then be careful not to export references to this
outside fo the class. Some developers will write a business interface
that the Bean class implements and the remote interface extends.
Restrictions:
- The bean class must define a default constructor.
- The bean class must not define the finalize method.
- The EJB specification prohibits use of the synchronized keyword.
- EJB prohibits beans from creating their own threads.
For Session Beans:
The SessionBean interface is implemented by every
session enterprise Bean class.
public interface SessionBean extends EnterpriseBean
{
void ejbActivate()
// The activate method is called when the instance is activated
// from its "passive" state.
void ejbPassivate()
// The passivate method is called before the instance enters the
// "passive" state.
void ejbRemove()
// A container invokes this method before it ends the life of the
// session object.
void setSessionContext(SessionContext ctx)
// Set the associated session context.
}
|
The container uses the SessionBean methods to notify
the enterprise Bean instances of the instance's life cycle events.
An enterprise bean must have one or more ejbCreate methods. Typically,
it method initializes the state of the enterprise bean. There must
be a bean create method corresponding to every create
method in the Home,
import javax.ejb.*;
import java.rmi.RemoteException;
public class MyBean implements SessionBean
{
// required methods
// used to create Bean isntances
public void ejbCreate(..) {}
// from SessionBean interface
public void ejbRemove() {}
public void ejbActivate() {}
public void ejbPassivate() {}
public void setSessionContext() {}
// business method implementations
}
|
For Entity Beans:
The EntityBean interface is implemented by every entity enterprise
Bean class.
public interface EntityBean extends EnterpriseBean
{
void setEntityContext(EntityContext ctx)
// Set the associated entity context.
void unsetEntityContext()
// Unset the associated entity context.
void ejbActivate()
// A container invokes this method when the instance is taken
// out of the pool of available instances to become associated
// with a specific EJB object.
void ejbPassivate()
// A container invokes this method on an instance before the instance
// becomes disassociated with a specific EJB object.
void ejbLoad()
// A container invokes this method to instruct the instance to
// synchronize its state by loading it state from the underlying
// database.
void ejbStore()
// A container invokes this method to instruct the instance to
// synchronize its state by storing it to the underlying database.
void ejbRemove()
// A container invokes this method before it removes the EJB object
// that is currently associated with the instance.
}
|
The container uses the EntityBean methods to notify the enterprise
Bean instances of the instance's life cycle events.
import javax.ejb.*;import java.rmi.RemoteException;
public class MyBean implements EntityBean
{
// entity bean methods
}
|
Primary Key Class
The Primary key class is optional, and only used by Entity Beans.
There are two ways to specify a primary key class for an entity
bean with container-managed persistence:
- Primary key that maps to a single field in the entity bean class.
- Primary key that maps to multiple fields in the entity bean
class.
The second method is necessary for implementing compound keys,
and the first method is convenient for single-field keys. Without
the first method, simple types such as String would have to be wrapped
in a user-defined class.
The first method requires that the the bean provider uses the primkey-field
element of the deployment descriptor to specify the container-managed
field of the entity bean class that contains the primary key. The
field's type must be the primary key type.
The second method requires the use of a primary key class which
must be public, and must have a public constructor with no parameters.
All fields in the primary key class must be declared as public.
The names of the fields in the primary key class must be a subset
of the names of the container-managed fields. (This allows the container
to extract the primary key fields from an instance’s container-managed
fields, and vice versa.)
The Enterprise JavaBeans architecture allows a primary key class
to be any class that is a legal Value Type in RMI-IIOP, subject
to the some restrictions. The primary key class may be specific
to an entity Bean class (i.e., each entity bean class may define
a different class for its primary key, but it is possible that multiple
entity beans use the same primary key class).
A primary key must implement the Serializable interface. EJB 1.1
requires that the hashCode and equals methods be overridden and
allows the PK to be defined by the bean developer or its definition
can be deferred until deployment.
import javax.ejb.*;
public class MyBeanPK implements java.io.Serializable
{
public String someFieldToUseAsPK;
public MyBeanPK() { someFieldToUseAsPK = null; }
public MyBeanPK(String s) { someFieldToUseAsPK = s; }
public int hashCode() { ... }
public boolean equals(Object obj) { ... }
}
|
Every entity object has a unique identity within its home. If two
entity objects have the same home and the same primary key, they
are considered identical.
Types of EJB
Session or Entity Beans
There are two types of beans in the EJB specification, Session
and Entity beans.
Session beans represent business logic, rules, and workflow. They
perform some sort of work for the client that is calling them. Important
features of Session beans:
- Never used by more than one client at a time
- Lifetime is roughly the same as the period during which the
client interacts with the bean
Entity beans represent data that is stored in a database or some
persistent storage. Important features of Entity beans:
- Persistent across client sessions and the lifetime of the server
- Have a unique identity used for lookup
- Multiple clients can access at once the container manages
this concurrency.
- Persistence of the data the bean represents is either container
or bean - managed
Message Driven Beans
New in the EJB2.0 spec. Probably not in the test, but here for
completeness:
When to Use Messaging
- For better DB performance. Reduce load by putting request onto
queue and DB will process later.
- Quick response. For methods that return void, dont keep
client waiting by blocking.
- Smooth load balancing. Have servers pull for the message instead
of load balancer push to the ones they guess are least burdened.
- Prioritize requests.
- Integrate disparate systems because many legacy systems use
messaging.
- Loosely coupled systems so that applications dont have
to know about each other at compile time.
- Geographically disperse systems
- Parallel processing by launching a series of messages and continue
processing.
- Reliability by using persistent queues and topics.
- Many-to-many communications.
When Not to Use Messaging
- When youre not sure if the operation will succeed. Synchronous
calls can throw exceptions.
- When you need a return value on the method.
- When you need an operation to be part of a larger transaction.
- When you need to propagate the clients identity to the
server.
- When you are concerned about request performance. Messaging
takes a hit because of messaging middleman such as queue or topic.
- When you need strongly-typed OO system.
- When you want a tighter, more straightforward system.
Can offer better performance because client does not block waiting
for server to process request. However, may take performance hit
from messaging middleman.
Can offer better reliability because messages can be stored in
persistent queue and you can define quality of service.
Supports multiple sends and receivers.
Publish/Subscribe: Many to many. Uses a topic.
Point-to-Point: One to one???.
many consumers can register
with the queue but message is consumed only once.
Session: Stateful or Stateless
Session beans can be either stateless of stateful.
Stateless Session beans do not maintain state across method calls.
The Session bean returns to the same state after each successive
call to one of its methods from a client. This makes a stateless
Session bean more poolable for performance and accessible from multiple
clients (one at a time) without fear of conflict. Stateless Session
beans are never passivated, but just destroyed (or removed from
the pool) when no longer needed. Stateless beans cannot participate
in any transaction synchronization (e.g. implement interface SessionSynchronization).
A stateless session bean is only dedicated to an EJB object for
the duration of the method.
Stateful Session beans maintain a state that can be accessed and
changed across multiple client interactions with the beans
methods. Stateful Session beans are accessed by only a single client
and can be passivated by the container.
At deployment time, you indicate to the container whether a Session
bean is stateful or stateless with an identifier in the deployment
descriptor.
Which to use?
Entity beans do not contain business process logic; they model
data. Examples of persistent data include things like account,
customer, order line, etc.
Session beans model business processes such as performing a credit
card verification, reserving a room, etc. Some processes require
a single method call (stateless) to complete, while other processes
may require repeated calls that require storing state information
across these calls (stateful). An example of a stateful process
would be a bean that tracks an on-line shoppers cart, the
contents of which must be maintained across multiple calls to the
bean. Code that represents a bank teller interacting with a customer
might also need to track account balance or credit limit across
multiple banking transactions in a single interaction with the customer.
Recognizing the type of bean to use begins by asking, is
this a process or a persistent thing Im working with
(session versus entity) and if it is a process, asking is
this a single method call with no need to reference prior state
or do I need multiple transactions with a stored state to accomplish
this process? (stateless versus stateful).
Container Managed Persistence
An Entity Bean comes in two forms.
- Container Managed Persistence (CMP)
- Bean Managed Persistence (BMP)
1. Container Managed Persistence
The term container-managed persistence means that the EJB container
handles all database access required by the entity bean. The bean's
code contains no database access (SQL) calls. As a result, the bean's
code is not tied to a specific persistent storage mechanism (database).
Because of this flexibility, even if you redeploy the same entity
bean on different J2EE servers that use different databases, you
won't need to modify or recompile the bean's code. In short, your
entity beans are more portable.
Benefits:
- Portability: Database Independence - No need to hard code against
a specific database API to accomplish these things (although JDBC
may give you this anyway)
- Portability: Container Independence - Although the deployment
descriptors will change the code shouldn't need to - although
this may also be true with BMP
- Code Reduction CMP performs all data access logic without
the need to write any JDBC code, reducing the amount of code needed
and hence development time for the bean.
- Enhances Software Quality JDBC code is not type-safe
and is frequently buggy because it cannot be verified until runtime.
The developer who wrote the container likely writes better data
access code than you do and usually provides contained tools that
allow detecting of errors at compile time. The better the container,
the more your Entity bean code improves in quality.
- Productivity dont have to write/debug tedious database
mapping code
- Performance the container can implement caching, although
the lack of specialism for a particular task may adversely affect
performance
Costs:
- Portability: Databases portability - across databases is not
yet perfect. Specifying persistence semantics is not standardized
yet and what BEA requires you to do to map your objects to relational
fields may be inconsistent with another container vendor. If mapping
your objects to relational tables is not 1:1 or you need complicated
SQL joins in finder methods, some containers lack the ability
to handle this.
- Portability: Container - not all containers require you to write
absolutely zero persistence code. Most containers at least require
you to navigate a wizard to specify persistent fields and that
you specify the logic for your finder methods. In EJB1.x, deployment
of CMP wasnt portable [to investigate]
- Lack of Control - if there is a bug, it is hard to see what
database operations the container is actually executing in order
to troubleshoot the problem.
- Simplistic Mapping - some containers may not support mapping
of complex field types to underlying storage. Example: your entity
bean class has a vector as a persistent member field. You may
have to convert this vector to some other type that the container
can persist for you.
EJB 1.1 allows the CMP fields to include remote references to
EJB objects (remote interface types) and EJB homes (home interface
types). EJB 1.0 only allowed Java primitives and serializable
types.
- Legacy support not every data store is a database but
most vendors only support DB mapping
CMP has the following considerations:
- Data Aliasing - An update of a data item done through a container-managed
field of one entity bean may not be visible to another entity
bean in the same transaction if the other entity bean maps to
the same data item.
- Eager Loading of State The container loads the entire
object stateinto the container-managed fields before invoking
the ejbLoad method.
2. Bean Managed Persistence
Bean Managed Persistence (BMP) required the Application Developer
to write logic to persist and restore data to a backing store. This
is typically done using JDBC, potentially through the use of Data
Access Objects.
Transactions
A transaction is an atomic set of steps which must either all complete
(commit) or none of which must complete (rollback).
After a rollback everything is as it was before the transaction
started.
Transactions are said to have the ACID properties (Atomic, Consistent,
Isolation, and Durable) : [taken from nusphere.com]
- Atomicity
- A transaction allows for the grouping of one or more changes
to tables and rows in the database to form an atomic or indivisible
operation. That is, either all of the changes occur or none of
them do. If for any reason the transaction cannot be completed,
everything this transaction changed can be restored to the state
it was in prior to the start of the transaction via a rollback
operation.
- Consistency
- Transactions always operate on a consistent view of the data
and when they end always leave the data in a consistent state.
Data may be said to be consistent as long as it conforms to a
set of invariants, such as no two rows in the customer table have
the same customer id and all orders have an associated customer
row. While a transaction executes these invariants may be violated,
but no other transaction will be allowed to see these inconsistencies,
and all such inconsistencies will have been eliminated by the
time the transaction ends.
- Isolation
- To a given transaction, it should appear as though it is running
all by itself on the database. The effects of concurrently running
transactions are invisible to this transaction, and the effects
of this transaction are invisible to others until the transaction
is committed.
- Durability
- Once a transaction is committed, its effects are guaranteed
to persist even in the event of subsequent system failures. Until
the transaction commits, not only are any changes made by that
transaction not durable, but are guaranteed not to persist in
the face of a system failure, as crash recovery will rollback
their effects.
Within a container transactions can either be:
- Container Managed Transactions
- Bean Managed Transactions
1. Container Managed Transactions
In an enterprise bean with container-managed transactions, the
EJB container sets the boundaries of the transactions. You can use
container-managed transactions with any type of enterprise bean:
session, entity, or message-driven. Container-managed transactions
simplify development because the enterprise bean code does not explicitly
mark the transaction's boundaries. The code does not include statements
that begin and end the transaction.
Typically, the container begins a transaction immediately before
an enterprise bean method starts. It commits the transaction just
before the method exits. Each method can be associated with a single
transaction. Nested or multiple transactions are not allowed within
a method.
Container-managed transactions do not require all methods to be
associated with transactions. When deploying a bean, you specify
which of the bean's methods are associated with transactions by
setting the transaction attributes. [from Sun
J2EE Tutorial]
In EJB1.0 CMT, it was possible to control transaction further by
setting the transaction isolation level in the deployment descriptor
on a per method basis. In EJB1.1 CMT, its still possible to
change the isolation level but its container dependent. [need
to check EJB2.0]
A transaction attribute controls the scope of a transaction, and
so defines which transaction a method called by another method is
run in. The options are: [from Sun
J2EE Tutorial]
- Required
- If the client is running within a transaction and invokes the
enterprise bean's method, the method executes within the client's
transaction. If the client is not associated with a transaction,
the container starts a new transaction before running the method.
The Required attribute will work for most transactions. Therefore,
you may want to use it as a default, at least in the early phases
of development. Because transaction attributes are declarative,
you can easily change them at a later time.
- RequiresNew
- If the client is running within a transaction and invokes the
enterprise bean's method, the container takes the following steps:
- Suspends the client's transaction
- Starts a new transaction
- Delegates the call to the method
- Resumes the client's transaction after the method completes
If the client is not associated with a transaction, the container
starts a new transaction before running the method.
You should use the RequiresNew attribute when you want to ensure
that the method always runs within a new transaction.
- Mandatory
- If the client is running within a transaction and invokes
the enterprise bean's method, the method executes within the client's
transaction. If the client is not associated with a transaction,
the container throws the
TransactionRequiredException.
Use the Mandatory attribute if the enterprise bean's method must
use the transaction of the client.
- NotSupported
- If the client is running within a transaction and invokes the
enterprise bean's method, the container suspends the client's
transaction before invoking the method. After the method has completed,
the container resumes the client's transaction.
If the client is not associated with a transaction, the container
does not start a new transaction before running the method.
Use the NotSupported attribute for methods that don't need transactions.
Because transactions involve overhead, this attribute may improve
performance.
- Supports
- If the client is running within a transaction and invokes the
enterprise bean's method, the method executes within the client's
transaction. If the client is not associated with a transaction,
the container does not start a new transaction before running
the method.
Because the transactional behavior of the method may vary, you
should use the Supports attribute with caution.
- Never
- If the client is running within a transaction and invokes the
enterprise bean's method, the container throws a
RemoteException.
If the client is not associated with a transaction, the container
does not start a new transaction before running the method.
In summary:
| Requires |
RequiresNew |
Mandatory |
NotSupported |
Supports |
Never |
| uses existsing or creates new |
suspends existing and creates |
uses existing otherwise throws exception |
suspends any existing |
uses if existing |
throws exception if existing |
2. Bean Managed Transactions
In a bean-managed transaction, the code in the session or message-driven
bean explicitly marks the boundaries of the transaction. An entity
bean cannot have bean-managed transactions; it must use container-managed
transactions instead. Although beans with container-managed transactions
require less coding, they have one limitation: When a method is
executing, it can be associated with either a single transaction
or no transaction at all. If this limitation will make coding your
bean difficult, you should consider using bean-managed transactions.
When coding a bean-managed transaction for session or message-driven
beans, you must decide whether to use JDBC or JTA transactions.
The sections that follow discuss both types of transactions.
A JDBC transaction is controlled by the transaction manager of
the DBMS. You may want to use JDBC transactions when wrapping legacy
code inside a session bean. To code a JDBC transaction, you invoke
the commit and rollback methods of the java.sql.Connection interface.
The beginning of a transaction is implicit. A transaction begins
with the first SQL statement that follows the most recent commit,
rollback, or connect statement. (This rule is generally true, but
may vary with DBMS vendor.)
JTA is the abbreviation for the Java Transaction API. This API
allows you to demarcate transactions in a manner that is independent
of the transaction manager implementation. The J2EE SDK implements
the transaction manager with the Java Transaction Service ("JTS").
But your code doesn't call the JTS methods directly. Instead, it
invokes the JTA methods, which then call the lower-level JTS routines.
A JTA transaction is controlled by the J2EE transaction manager.
You may want to use a JTA transaction because it can span updates
to multiple databases from different vendors. A particular DBMS's
transaction manager may not work with heterogeneous databases. However,
the J2EE transaction manager does have one limitation--it does not
support nested transactions. In other words, it cannot start a transaction
for an instance until the previous transaction has ended.
Entity beans should not use bean-managed transactions because you
need to do ejbLoad() before a transaction and an ejbStore() after
a transaction but the bean itself can never explicitly call those
methods.
Transaction Management
- Dirty Read
- A dirty read occurs when the first transaction reads uncommitted
changes made by a second transaction. If the second transaction
is rolled back, the data read by the first transaction becomes
invalid because the rollback undoes the changes.
- Repeatable Read
- A repeatable read is when the data read is guaranteed to look
the same if read again during the same transaction.
- Phantom Read
- Phantom reads occur when new records added to the database are
detectable by transactions that started prior to the insert. Queries
will include records added by other transactions after their transaction
has started.
Isolation levels are commonly used in database systems to describe
how locking is applied to data within a transaction.
- Read Uncommitted
- The transaction can read uncommitted data. Dirty reads, nonrepeatable
reads, and phantom reads can occur.
- Read Committed
- The transaction cannot read uncommitted data. Dirty reads are
prevented; nonrepeatable reads and phantom reads can occur. Bean
methods with this isolation level cannot read uncommitted data.
- Repeatable Read
- The tx cannot change data that is being read by a different
tx. Dirty reads and nonrepeatable reads are prevented; phantom
reads can occur. Bean methods with this isolation level have the
same restrictions as Read Committed and can only execute repeatable
reads.
- Serializable
- The transaction has exclusive read and update privileges to
data; different transactions can neither read nor write the same
data. Dirty reads, nonrepeatable reads, and phantom reads are
prevented. Most restrictive isolation level.
Security
The standard Java security features apply (see the Security
section). J2EE also had additional security mechanisms.
Within an EJB component security roles are defined - a role is
a logical user (e.g. admin, customer). When the component is deployed,
the role is mapped to real J2EE users/groups (e.g. PJC
is able to assume the admin role).
To access secure resources, the Subject (client) must be authenticated
and authorized :
- Authentication.
- To authenticate, the Subject must present their Credentials
(e.g. username/password) to the
container. If the authentication is successful, the Subject is
associated with one or more Principal objects.
Authentication is not currently part of the EJB specification
e.g. the credentials may be
passed as properties to an InitialContext, JAAS or JNDI may be
used, etc.
- Authorisation (access control).
- Once authenticated, the Principal(s) can be checked against
the Role to decide if the client is authorised to access the secure
resource.
Role based authorisation is fully supported by J2EE security
constraints in web.xml, method level security in EJB deployment
descriptor, runAs in deployment descriptor.
Instance based authorisation (e.g. PJC is only allowed access
to PJCs account) isnt yet
specified
EJB supports declarative security (programmatic security is also
supported) by setting the appropriate values in the deployment descriptor
:
<method-permission>
<role-name>admin</role-name> <method>
<ejb-name>Account</ejb-name> <method-name>*</method-name>
</method>
</method-permission>
|
Not very portable at the moment authentication and runAs
are container specific; container to container security propagation
is undefined.
J2EE also has other built-in security features :
- web-tier authentication via HTTP authentication, forms,
client certificates
- secure communications SSL; web-tier authentication can
use SSL for HTTP/FORM authenticaton
- security packages digests, digital signatures, ciphers,
certificates, etc.
Data Access Objects
EJBs are remote objects that consume significant system resources
and network bandwidth. You can use Data Access Objects to encapsulate
the logic required to access databases.
The intent of DAOs is to decouple business logic from data access
logic and adapt the resource being accessed, so that the type of
resource can change easily and independently.
Advantages.
- transparency specifics of data access are hidden from
the entity bean
- modular the DAO could be swapped for another with little
disruption to the entity bean code
- cleaner code - data access factored out so simplifies entity
bean code
- reusable DAO could be re-used in a Fast Lane Reader
- future-proof - provide an easier migration path to CMP
Disadvantages.
- only suitable for BMP
- extra code - have to write DAO class, DAO wrapper calls in entity
bean, maybe some DAO factories
|