Survey
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
Enterprise Java Beans (part I) Tal Cohen [email protected] IBM Labs in Haifa 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 What are Enterprise Java Beans IBM Labs in Haifa 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 JDBC (over TCP/IP?) RMI/IIOP Web server (running servlets, JSPs) Acts as EJB client Home user Runs Internet Browser EJB server Database/legacy server Bank clerk, running a Java app (using Swing, etc.) that acts as an EJB client 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 Creating and Working with Session EJBs IBM Labs in Haifa 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 public public public void void void void ejbCreate() throws CreateException {} ejbActivate() {} ejbPassivate() {} 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 Creating and Working with Entity EJBs IBM Labs in Haifa 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 Pooled newInstance() setEntityContext() ejbRemove() or ejbPassivate() unsetEntityContext() ejbLoad() business method ejbStore() Ready ejbCreate() or ejbActivate() 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 beanmanaged 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; ejbCreate should always return null. } public public public public public public void void void void void void ejbPostCreate(Integer number) {} ejbActivate() {} ejbLoad() {} Most lifecycle methods ejbPassivate() {} are often empty. ejbRemove() {} ejbStore() {} (more...) IBM Labs in Haifa Sample Code: CMP Entity EJB (6/7) public public public public abstract abstract abstract abstract Integer getNumber(); void setNumber(Integer newNumber); float getBalance(); void setBalance(float newBalance); The attribute accessors are automatically generated as abstract methods The relationship management methods are also automatically generated. public abstract ClientLocal getOwner(); public abstract void setOwner(ClientLocal anOwner); (more...) 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> (This is a slightly simplified version.) <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...) 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>