ibm labs in haifa enterprise java beans (part i) tal cohen [email protected]
Post on 19-Dec-2015
222 views
TRANSCRIPT
IBM Labs in Haifa
Outline of Part I
What are Enterprise Java Beans Types of EJBs EJB Views
Creating and Working with Session EJBs Components of a Session EJB Lifecycle and lifecycle methods Sample code
Creating and Working with Entity EJBs Components of an Entity EJB Lifecycle and lifecycle methods Sample code
IBM Labs in Haifa
What are Enterprise Java Beans
IBM Labs in Haifa
EJB Design Goals
A standards-based component model. Common services
Multithreading Transaction management Resource management
e.g., connection pooling Persistence management Security services
Distribution and scalability “Throw money at it” solution
Unrelated to (non-Enterprise) JavaBeans Except that both are component models.
IBM Labs in Haifa
Types of EJBs
IBM Labs in Haifa
Session EJBs
A session bean instance is: A non-persistent object Implements some business logic Runs on the server
Not shared among multiple clients
IBM Labs in Haifa
Stateful Session EJBs
A stateful session bean maintains a state The state is relevant only for a single client
Cannot be seen by other clients The state is not persistent
Expires after a certain timeout
Canonical example: Shopping cart
IBM Labs in Haifa
Stateless Session EJBs
Conceptually, the same as stateful session EJBs No state
Can have fields, but they are not unique to any client Basically, it’s an optimization trick: Since the container knows the bean has no state, it can:
Use a single bean instance (While each client thinks it has its own copy)
Destroy/re-instantiate on the fly Redirect requests to different instances (load balancing)
Client does not care on which server the bean is stored And migration is cheap, since there’s no data to move around
Example: Currency conversion bean
IBM Labs in Haifa
Message-Driven EJBs
New in EJB 2.0 standard Built on top of JMS Each instance is an asynchronous message consumer Have no client visibility
IBM Labs in Haifa
Entity EJBs
Object-oriented view of entities stored in persistent storage Normally, each instance represents a row in a relational DB table
Persistence code can be written manually (bean-managed persistence, BMP) or automatically (container-managed persistence, CMP)
A single bean instance (on the server) can be accessed by multiple clients Unlike stateful session EJBs
Each instance must be uniquely identifiable by means of a primary key.
IBM Labs in Haifa
CMP Entity EJBs
Container is responsible for saving the persistent state You specify the container-managed attributes
In EJB 2.0, they do not appear as actual class variables Persistence is independent of the data source
The mapping can be applied to other DBs Makes the beans very portable
Several additional benefits Container can manage caching, locking strategies
Can only be used with data sources supported by JDBC 2.0
IBM Labs in Haifa
BMP Entity EJBs
The bean writer must provide code for storing/restoring persistent state Less adaptable Can exploit any persistence framework
Not limited to databases Manual tuning can result in performance benefits
At the price of portability and hard work
IBM Labs in Haifa
EJB Views
Session and entity EJBs have two possible views: The local view
Used by local clients (only EJBs in the same container) Includes a local Home interface and a local component interface
The remote view Used by remote clients (not limited to EJBs; can include Servlets, etc.) Can also be used by clients in the same container Includes remote Home and component interfaces
A bean an implement both local and remote views Message-drive beans have no views
IBM Labs in Haifa
The Home and Component Interfaces
The component interface allows access to the EJB object Defines the business methods callable by the client Extends javax.ejb.EJBObject or EJBLocalObject
The home interface provides bean management facilities Factory and lifecycle services
Create, remove and find EJB instances ‘Static’ methods: the home interface can include services (methods)
that are not specific to a particular bean instance For entity EJBs only
Extends javax.ejb.EJBHome or EJBLocalHome
IBM Labs in Haifa
The Local View
New in EJB 2.0 spec Parameters are passed by reference The client and the EJB must reside in the same container
The client itself must be an EJB Much faster than remote view
No network latency No marshalling/unmarshalling
No need to worry about remote exceptions
The expectation is that Entity EJBs will mostly be accessed through the local view Using the Session Facade pattern
IBM Labs in Haifa
The Local View (cont.)
1. Client looks up a bean home object using JNDI 2. Client creates or finds EJB 3. Client uses EJB business methods from the local interface
IBM Labs in Haifa
The Remote View
Based on Java RMI Uses remote interface, stub, and tie (skeleton) Works with RMI/IIOP (“RMI over IIOP”) Vendor-specific protocols are also possible
Parameters are passed by value All parameter and return-value types must be serializable
Provides location independence and flexibility APIs should be coarsely-grained
One method that does several related tasks is more effective than several smaller methods
IBM Labs in Haifa
The Remote View (cont.)
Same 3 steps as before, but taken over the network:
IBM Labs in Haifa
Sample Usage: EJBs in a Banking Environment
Web server (running servlets, JSPs)
Acts as EJB clientEJB server Database/legacy server
Home user
Runs Internet Browser
Bank clerk, running a Java app (using
Swing, etc.) that acts as an EJB client
RMI/IIOP
RMI/IIOP
JDBC(over
TCP/IP?)
HTTP
IBM Labs in Haifa
Sample Usage: Details
Web server, terminal programs both act as EJB clients Do not have to know about DB structure
DB can be changed, upgraded etc. Have an object-oriented abstraction of the DB information Can invoke remote operations
Including high-level operations using Session EJBs Each client has a different access level/privileges
Home user cannot do some things that a bank clerk can Decreased load on web server, bank terminals EJB server can be the same machine as the DB server
Alternatively, it can be a whole cluster of machines EJBs provide and maintain the model; clients manage view/control
IBM Labs in Haifa
Creating and Working with Session EJBs
IBM Labs in Haifa
Components of a Session EJB
To define session EJB X, you must create three classes: The remote (local) component interface, called X (or XLocal)
Extends EJBObject (or EJBLocalObject) (All extended types are from javax.ejb)
The home interface, called XHome (or XLocalHome) Extends EJBHome (or EJBLocalHome)
The bean class itself, called XBean Extends SessionBean Should implement java.io.Serializable (for stateful beans) Implements business methods from the component interface Implements lifecycle methods (ejbXXX)
The class names are (strong) conventions
IBM Labs in Haifa
The Session EJB Lifecycle
IBM Labs in Haifa
Lifecycle Methods
Lifecycle methods are defined in the XBean class They are named ejbXXX
ejbCreate, ejbActivate, etc. plus setSessionContext No other method name should begin with ‘ejb’
Some lifecycle methods also appear in the XHome interface For session beans, only the create methods appear in the home
interface In the home interface, the ‘ejb’ prefix is not used
i.e., method should be named ‘create’ Lifecycle methods are invoked by the container when changing state
during the bean’s life
IBM Labs in Haifa
ejbCreate Methods in Stateful Session Beans
A stateful session bean can contain several ejbCreate methods The methods can have zero or more parameters They can be called be ejbCreate(...) or ejbCreateXXX(...), for more
descriptive names e.g., ejbCreateByName(String name)
Must be public void Should throw javax.ejb.CreateException if creation fails for
whatever reason (invalid arguments, etc.) Must be reflected in the XHome interface (local or remote) by a method
with identical parameters, that is called ‘create’ or ‘createXXX’ Returns the bean component interface type (X) For remote homes, throws java.rmi.RemoteException e.g., public X createByName(String name) throws ...
IBM Labs in Haifa
ejbCreate Methods in Stateless Session Beans
For stateless session beans, there can be only one ejbCreate method Called ‘ejbCreate’ Accepts zero parameters Reflected normally in the home interface
IBM Labs in Haifa
The Birth of a New Session Bean
1. Client obtains home interface via JNDI lookup 2. Client calls home.create(...) 3. EJB object, session context and EJB instance are created in the
container 4. EJB instance is provided with the session context 5. Corresponding variant of ejbCreate is invoked on EJB instance 6. create method returns a stub that the client can use.
IBM Labs in Haifa
The EJB Session Context
During creation, the EJB instance is handed a Session Context object An instance of javax.ejb.SessionContext
setSessionContext should keep a copy of the context in a field The context object contains:
Security-related information getCallerPrinciple, isCallerInRole
Transaction-related information and methods getUserTransaction, get/setRollbackOnly
Home-related information getEJBHome, getEJBLocalHome
EJB Object-related information getEJBObject, getEJBLocalObject The former must be returned instead of this, whenever required
IBM Labs in Haifa
The EJB Session Context (cont.)
WSAD generates all EJBs with: SessionContext field setSessionContext method that stores the provided context in
this field getSessionContext method
IBM Labs in Haifa
Activation and Passivation
During the bean’s lifecycle, the container may decide to passivate it Normally done to free up memory and other resources Bean is notified immediately before passivation by lifecycle method
ejbPassivate() In this method, the bean should:
Release any resources it might be holding Open files, database connections, etc.
Nullify fields that should not be serialized (cache, etc.) If the bean is referenced by client while passivated, the container
activates it. Bean is notified by ejbActivate() immediately after de-serialization
Its chance to restore all field values, resources, etc.
IBM Labs in Haifa
One Last Lifecycle Method
ejbRemove() is called before the container destroys a bean instance Should release all resources Normally empty.
IBM Labs in Haifa
The Lifecycle of Stateless Session EJBs
Session EJBs have no state, so activation and passivation are meaningless The container simply destroys instances when low on memory, and
creates new ones as needed Still, ejbActivate and ejbPassivate must be implemented in
XBean (as empty methods) The resulting lifecycle diagram is somewhat simplified:
IBM Labs in Haifa
Business and Utility Methods
Other than lifecycle method, the bean class can include business methods
Business methods are those that appear in the remote (or local) component interface i.e., can be invoked by clients
Utility methods are those that do not appear in the component interface Cannot be invoked by clients -- even if defined as public methods
There are some limitations on business methods All parameters and return types must be serializable Must not return ‘this’ etc.
IBM Labs in Haifa
Sample code: Stateless Session Bean (1/4)
The component interface:
public interface CurrencyConverter extends javax.ejb.EJBObject {
public double convertUsdToNis(double usd) throws java.rmi.RemoteException;
}
Code in green was automatically generated by WSAD Code in dark green was automatically generated upon request
Request for “promoting” the convertUsdToNis method
IBM Labs in Haifa
Sample code: Stateless Session Bean (2/4)
The home interface:
public interface CurrencyConverterHome extends javax.ejb.EJBHome {
public CurrencyConverter create()throws javax.ejb.CreateException,
java.rmi.RemoteException;}
Entirely auto-generated All auto-generated comments were removed
IBM Labs in Haifa
Sample code: Stateless Session Bean (3/4)
The bean class itself:
public class CurrencyConverterBean implements javax.ejb.SessionBean {private static final double NIS_PER_USD = 4.6;
private SessionContext mySessionCtx;public SessionContext getSessionContext() {
return mySessionCtx;}public void setSessionContext(SessionContext ctx) {
mySessionCtx = ctx;}
(more...)
IBM Labs in Haifa
Sample code: Stateless Session Bean (4/4)
public void ejbCreate() throws CreateException {}public void ejbActivate() {}public void ejbPassivate() {}public void ejbRemove() {}
public double convertUsdToNis(double usd) {return usd * NIS_PER_USD;
}}
In such simple cases, one has to implement only the business logic. Sadly, it isn’t always so...
IBM Labs in Haifa
Session Bean Deployment Descriptors
EJBs are distributed in JAR (“Java Archive”) files Each JAR contains a Deployment Descriptor, listing details for every
EJB it contains Sample XML fragment for a single EJB from a JAR file:
<session id="CurrencyConverter"><ejb-name>CurrencyConverter</ejb-name><home>demo.j2ee.CurrencyConverterHome</home><remote>demo.j2ee.CurrencyConverter</remote><ejb-class>demo.j2ee.CurrencyConverterBean</ejb-class><session-type>Stateless</session-type><transaction-type>Container</transaction-type>
</session>
IBM Labs in Haifa
Session Bean Deployment Descriptors (cont.)
For stateful session beans:<session-type>Stateful</session-type>
The deployment descriptor is normally generated by WSAD If you need to change it, you can edit the XML or use a GUI
IBM Labs in Haifa
Creating and Working with Entity EJBs
IBM Labs in Haifa
Components of an Entity EJBs
As per Session EJBs: Component interface (local and/or remote) Home interface (local and/or remote) The bean class
Implements javax.ejb.EntityBean And a Primary Key class
Can be an existing class String, Integer, Date, etc.
Can be a new class (e.g., for composite keys) Must properly override hashCode and equals Must be serializable Naming convention: XKey
IBM Labs in Haifa
Entity Bean Lifecycle
Does not exist
Ready
Pooled
newInstance()setEntityContext()
unset-EntityContext()
ejbRemove() or
ejbPassivate()
ejbCreate()or ejbActivate()
ejbLoad()business method
ejbStore()
IBM Labs in Haifa
The Bean Pool
The EJB container maintains a pool of available beans Pooled beans are not associated with any specific row When a bean becomes ready, it is provided with an identity
Possibly its own previous identity (if it was passivated) Possibly a different one
When a bean instance is required, the container will pick a bean from the pool rather than create a new instance
IBM Labs in Haifa
The Bean’s Start and End of Life
setEntityContext is called only once Even if the identity changes; the context object will be modified by
the container unsetEntityContext is called only once
When the instance is removed from memory Use this pair for initializing/finalizing fields that do not depend on the
bean’s identity e.g., finding a connection pool via JNDI
Use ejbCreate/ejbActivate and ejbRemove/ejbPassivate to initialize fields that do depend on the bean’s identity
IBM Labs in Haifa
Lifecycle Methods
As with Session Beans, each ejbCreate method is reflected in the Home interface
In addition, for every ejbCreate method there’s a corresponding ejbPostCreate method PostCreate is invoked after the bean has an EJB object, and is
represented in the persistent data storage Allows you to pass references to the bean to other EJBs
e.g., relationships Other lifecycle methods include ejbActivate, ejbPassivate,
ejbLoad, ejbStore, ejbFindXXX and ejbRemove The exact semantics vary between container-managed and bean-
managed persistence
IBM Labs in Haifa
Lifecycle Methods in BMP Entity EJBs
The bean creation sequence:
IBM Labs in Haifa
Managing Storage in BMP EJBs
Assuming each bean represents a row in a relational table:
The ejbCreate methods should add a row to the database The ejbRemove method should remove the row represented by the
bean instance ejbLoad should assume nothing about the instance variables mapped
to table fields, and reload their values from the database You can find the primary key by invoking getPrimaryKey on the EntityContext reference
ejbStore should update the table row to reflect the current bean state
If you’re using JDBC to connect to the data source, use connection pooling
IBM Labs in Haifa
The role of ejbLoad and ejbStore in BMP EJBs
Conceptually, ejbLoad is called before every business method So the method is sure to work with up-to-date values from the
database Likewise, ejbStore is called after every business method
Storing any changes made to the instance variables As a result, beans can survive container crashes Serious performance hit
Common practice: maintain a ‘dirty’ flag
Note that according to the spec, the container may invoke ejbLoad and ejbStore arbitrarily, and does not have to call them before/after every business method invocation
IBM Labs in Haifa
Activation and Passivation
Bean instances are managed in a pool Like we said, the same bean instance, after created, can be used for
different table rows at different times Saves instantiation costs
When a bean is returned to the pool (detached from a given row), it is passivated
When a bean is re-attached to a row, it is activated
Persistence data should not be stored/reloaded during activation/passivation
Use ejbPassivate/ejbActivate to release/reacquire other resources
IBM Labs in Haifa
Putting It All Together
IBM Labs in Haifa
Finder Methods
Given the home interface, a client can create new entity EJBs using the various create methods Remember that each create method in the home interface has a
corresponding ejbCreate and ejbPostCreate method in the bean class
But what if the client wants to locate existing beans? The home interface also includes finder methods.
Named findXXX Must return either java.util.Collection, or the component
interface type Throws FinderException (and RemoteException for remote
homes) Always defined: findByPrimaryKey(keytype)
IBM Labs in Haifa
Finder Methods in the BMP Bean Class
For each findXXX method in the home interface, a corresponding ejbFindXXX method must be implemented in the bean class
ejbFindByPrimaryKey is required Finder methods can find a single record
This includes ejbFindByPrimaryKey Value returned must be the primary key of the found record
which is the parameter in ejbFindByPrimaryKey’s case Throw FinderException if no record was found
Finder methods can find a set of records Signature must define java.util.Collection as return type Return a collection of primary keys Return an empty collection if no records were found
IBM Labs in Haifa
Removing a Row
The last lifecycle method, ejbRemove, must include code to remove the row corresponding to the current bean instance from the persistent data store
Can throw javax.ejb.RemoveException if removal failed.
IBM Labs in Haifa
Letting the Container Do the Work
Entity beans, as defined so far, must include a lot of SQL statements if they use a database as their data source SELECT for ejbLoad and finder methods INSERT for create methods UPDATE for ejbStore DELETE for ejbRemove
The work is repetitive, tedious, and error-prone Why not automate it? Enter CMP: Container Managed Persistence for Entity EJBs
IBM Labs in Haifa
CMP Entity Beans
CMP EJBs work just like BMP EJBs Same lifecycle
However, the mapping between persistent bean attributes and table columns is defined in a declarative manner. You tell the container which attribute corresponds to which column The container generates deployment code that handles loading,
finding, deleting, etc. In the EJB 1.x spec, persistent attributes are simply class variables. Starting with EJB 2.0, persistent attributes are not reflected as class
variables Only defined by getter/setter methods Allows the container to manage a ‘dirty’ flag automatically, thus
saving needless updates
IBM Labs in Haifa
Lifecycle Methods in CMP Entity Beans
Each CMP entity bean must include the same lifecycle methods as BMP beans
However, some of the semantics are slightly different: ejbLoad is called immediately after the data is loaded
Allows you to calculate values for any class variables that depend on field values
Should not attempt to load the data by itself ejbStore is called immediately before the data is stored
Does not store the data by itself ejbRemove is called immediately before the row is removed
Does not actually remove the row by itself All are normally empty.
IBM Labs in Haifa
Bean Field Getter and Setter Methods
For each persistent attribute A in the bean, there must be a getA and/or a setA method
The getters and setters are defined in the bean class as abstract methods
Their actual implementation is included in a subclass generated by the container.
Implication: the bean class itself is abstract.
IBM Labs in Haifa
Finder Methods in CMP Entity Beans
Finder methods are defined normally in the home interface However, no corresponding ejbFindXXX methods are defined in the
bean class Each finder method is associated (in the deployment descriptor) with an
EJB QL query The query should return one row (at most) if the finder is defined to
return a single bean The query should return zero or more rows if the finder is defined to
return a collection EJB QL is a modified subset of SQL
Details later
IBM Labs in Haifa
Object-Relational Mapping
The key point in creating CMP EJBs is mapping objects with relational database tables
IBM Labs in Haifa
Object-Relational Mapping (cont.)
For example...
IBM Labs in Haifa
Approaches to Object-Relational Mapping
There are three different ways to define a mapping:
Top down Mapping Create a database schema given an object model
Bottom up Mapping Define an object model given a database schema
Meet-in-the-Middle Mapping Map existing model and schema
IBM Labs in Haifa
Top-Down Mapping
Start with a group of EJBs, each with its own attributes Generate a new database schema
One table per entity bean, one column per field Instance variables representing object relationships are mapped to
foreign keys Very simple
Schema is generated automatically by WSAD Not very useful
Does not allow connection to existing databases Database administrators prefer to have control over the table
definitions Useful mainly when there’s no existing data and no constrains on
database design
IBM Labs in Haifa
Bottom-Up Mapping
The exact opposite of top-down Given a database schema, generates a class definition per table and a
class variable per column Equally simple
EJB classes generated by WSAD Even less useful
Rarely satisfactory from an OO point of view Particularly when the tables have been optimized
IBM Labs in Haifa
Meet-in-the-Middle Mapping
Used when both the object model and the database schema already exist
Each persistent field in the EJBs must be mapped to a table column Object relationships can be mapped to foreign-key relationships
between tables Good tool support
WSAD can provide an initial ‘intelligent guess’ based on similar field/column names
The most useful approach
IBM Labs in Haifa
Relationships
Relationships between EJBs are similar to foreign-key relationships in databases
There can be one-to-one, one-to-many, many-to-one and many-to-many relationships
With EJB 2.0, CMP EJBs can have container-managed relationships (CMR)
Supports cascading deletes
IBM Labs in Haifa
Sample Code: CMP Entity EJB (1/7)
Our sample EJB class is Account, which represents a client’s bank account
Persistent attributes: number (primary key; java.lang.Integer) balance (float)
Relationships: owner, a many-to-one relationship with the Client EJB
Business methods: deposit withdraw
Finders By account number (primary key) All overdraft accounts
IBM Labs in Haifa
Sample Code: CMP Entity EJB (2/7)
The home interface:
public interface AccountHome extends javax.ejb.EJBHome {public Account create(java.lang.Integer number)
throws CreateException, RemoteException;public Account findByPrimaryKey(Integer primaryKey)
throws FinderException, RemoteException;public java.util.Collection findOverdraftAccounts()
throws FinderException, RemoteException;}
IBM Labs in Haifa
Sample Code: CMP Entity EJB (3/7)
The component interface:
public interface Account extends EJBObject {public float getBalance()
throws RemoteException;public void setBalance(float newBalance)
throws RemoteException;public void deposit(float amount)
throws RemoteException;public void withdraw(float amount)
throws RemoteException;}
IBM Labs in Haifa
Sample Code: CMP Entity EJB (4/7)
The bean class itself:
public abstract class AccountBean implements EntityBean {private EntityContext myEntityCtx;public void setEntityContext(EntityContext ctx) {
myEntityCtx = ctx;}public javax.ejb.EntityContext getEntityContext() {
return myEntityCtx;}public void unsetEntityContext() {
myEntityCtx = null;}
(more...)
IBM Labs in Haifa
Sample Code: CMP Entity EJB (5/7)
public java.lang.Integer ejbCreate(Integer number)throws javax.ejb.CreateException {setNumber(number);return null;
}
public void ejbPostCreate(Integer number) {}public void ejbActivate() {}public void ejbLoad() {}public void ejbPassivate() {}public void ejbRemove() {}public void ejbStore() {}
(more...)
ejbCreate should always return null.
Most lifecycle methods
are often empty.
IBM Labs in Haifa
Sample Code: CMP Entity EJB (6/7)
public abstract Integer getNumber();public abstract void setNumber(Integer newNumber);public abstract float getBalance();public abstract void setBalance(float newBalance);
public abstract ClientLocal getOwner();public abstract void setOwner(ClientLocal anOwner);
(more...)
The attribute accessors
are automatically generated
as abstract methods
The relationship
management methods are also
automatically generated.
IBM Labs in Haifa
Sample Code: CMP Entity EJB (7/7)
public void deposit(float amount) {setBalance(getBalance() + amount);
}
public void withdraw(float amount) {setBalance(getBalance() - amount);
}}
IBM Labs in Haifa
The Deployment Descriptor
To support CMP EJBs, the container needs to know: How to map attributes and relationships to columns What queries to use for finders
All this is detailed in the Deployment Descriptor XML file Normally generated/edited using GUI tools.
IBM Labs in Haifa
Sample Deployment Descriptor (1/2)
<entity id="Account"><persistence-type>Container</persistence-type><cmp-version>2.x</cmp-version><ejb-name>Account</ejb-name><home>demo.AccountHome</home><remote>demo.Account</remote><ejb-class>demo.AccountBean</ejb-class><prim-key-class>java.lang.Integer</prim-key-class><abstract-schema-name>Account</abstract-schema-name>
<cmp-field id="CMPAttribute_1051003252984"><field-name>number</field-name>
</cmp-field>(more...)
(This is a slightly
simplified version.)
IBM Labs in Haifa
Sample Deployment Descriptor (2/2)
<primkey-field>number</primkey-field><ejb-local-ref id="EJBLocalRef_1051002993438">
<local-home>demo.ClientLocalHome</local-home><local>demo.ClientLocal</local><ejb-link>Client</ejb-link>
</ejb-local-ref><query>
<query-method><method-name>findOverdraftAccounts</method-name>
</query-method><ejb-ql>select object(o) from Account o where (o.balance < 0)</ejb-ql>
</query></entity>