660 likes | 851 Views
Tal Cohen tal@forum2.org. Enterprise Java Beans (part II). Outline of Part II. Developing EJB Clients Transactions EJB Query Language Exceptions in EJBs EJB Security. Developing EJB Clients. Reminder: Clients can be Applications or Servlets. JDBC (over TCP/IP?). RMI/IIOP.
E N D
Tal Cohen tal@forum2.org Enterprise Java Beans (part II)
Outline of Part II • Developing EJB Clients • Transactions • EJB Query Language • Exceptions in EJBs • EJB Security
Reminder: Clients can be Applications or Servlets JDBC (over TCP/IP?) RMI/IIOP Web server (running servlets, JSPs) Acts as EJB client EJBserver Database/legacyserver HTTP RMI/IIOP Bank clerk, running a Java app (using Swing, etc.) that acts as an EJB client Home user Runs Internet Browser
Who Can Act as an EJB Client? • Other EJBs • Servlets • Java Applications • Require a special launcher (which provides services such as JNDI, etc.), or else a very careful setup (classpath, JVM version, etc.) • Java Applets • Given the proper security permissions • Non-Java Clients • EJBs are compatible with CORBA
Reminder: How an EJB Client Should Act • 1. Client looks up a bean home object using JNDI • 2. Client creates or finds EJB • 3. Client uses EJB business methods from the component interface
Sample Code Step 1: JNDI Lookup Hashtable values are vendor- specific; read from configuration file if possible. // Obtain an Initial Context: Hashtable properties = new Hashtable(); properties.put(INITIAL_CONTEXT_FACTORY, "com.ibm.websphere.naming.WsnInitialContextFactory"); properties.put(PROVIDER_URL, "iiop://"); InitialContext iCtx = new InitialContext(properties); // Lookup, and narrow the object: Object homeRef = iCtx.lookup("AccountHome"); // JNDI name AccountHome home = (AccountHome) PortableRemoteObject.narrow(homeRef, AccountHome.class); In practice, a parameter-less version of this constructor can often be used. CORBA narrowing required since the object passed over an IIOP connection. For local home interfaces, a simple downcast can be used.
Sample Code Step 2: Using the Home Interface // Use the home interface to create new EJBs: Account acc1 = home.create("Joe", "Average"); // Or use the finder methods to locate existing EJBs: Account acc2 = home.findByPrimaryKey(12345); Collection fatAccounts = home.findClientsByMinimalBalance(100000); Any find/create method, defined in the home interface and implemented in the bean class (or with EJB QL), can be used to create/locate EJBs.
Sample Code Step 3: Using the EJB References // Simply invoke business methods: acc1.setBalance(acc1.getBalance() - 100); acc2.setBalance(acc2.getBalance() + 97); // Commission... for (Iterator i = facAccounts.iterator(); i.hasNext(); ) { Account fatAccount = (Account) i.next(); fatAccount.setMaxCredit(1000000); }
Remember Possible Exceptions... • Finders can throw FinderException • Create methods can throw CreateException • Business methods can throw business-related exceptions • Any of them could throw RemoteException • Use proper try/catch blocks
Serializing EJB References • Be careful when using EJB references in contexts that could require serialization • e.g., HttpSession objects are often serializable • Use getHandle to obtain a handle to the EJB reference • Handle object is serializable • Use getEJBObject method to recover EJB reference from the handle.
The Home Factory Pattern • The first step for every EJB client is JNDI lookup • Common pattern: create a home factory • Usage: ClientHome = (ClientHome) HomeFactory.lookup("JNDI_Name", "ClientHome"); • The factory class provides a single static method -- lookup • Narrows the result and returns an Object to be downcast • The second parameter is the class name, used for narrowing • Using "class.forName(name)" • Internally, the factory caches the InitialContext object • Can also provide an API for obtaining it
The Session Facade Pattern • Used for minimizing: • Client/entity bean coupling • Risk of client using unapproved business methods • Or using approved business methods in unapproved ways • Network delays • Points of change if high-level business operations are modified • The idea: create a Session EJB that provides high-level business methods • Client should only work with the session bean(s) • Entity EJBs provide (possibly only) a local interface • Session EJB accesses entity EJBs locally
Session Facade Example: Transferring funds • Client code without the facade: • Find Account home • Find accounts a1, a2 by primary keys k1, k2 • a1.setBalance(a1.getBalance() - amount); • a2.setBalance(a2.getBalance() + amount); • Client code with the facade: • Find TransferBean home, create TransferBean t1 • t1.transfer(k1, k2, amount);
Resulting Benefits • Faster operation • 1 JNDI lookup, 1 remote object lookup and 1 remote business method vs. 1 JNDI lookup, 2 remote object lookups and 4 remote business methods in the old code • Easier maintenance • If we have two different clients (servlet, application) and we wish to change the transfer semantics (e.g., add logging), there's only one place to change • Increased security • Client can't invoke Account.setBalance directly, since Account has no remote component interface
Other Recommended Practices • Avoid calling EJB methods directly from JSP • The need to catch remote exceptions would complicate the JSP code • Use wrappers or 'access objects' • Some can be generated automatically by WebSphere AD • Avoid hard-coding JNDI properties • Store configuration hashtable values in a file • Avoid hard-coding JNDI resource names
What is a Transaction? • A transaction is a set of operations that moves data from one consistent state to another • The set of operations is considered indivisible • Allows the bundling of discrete operations • If one or more operations fail, the entire set is undone • Success: the transaction "commits" • Failure: the transaction "rolls back" • The effect of the transaction preserves data invariants • The effects of a committed transaction are persistent • Transactions seem to execute serially • For example: transferring funds from one account to another
Transaction Definitions • Transactional Object: An object which is used (methods invoked) within a transaction • Can only be associated with one transaction at a time • EJBs can be transactional objects • Transactional Client: A problem which invokes methods on transactional objects • Transaction Manager: A program that coordinates transaction processing
The Transaction Context • A single transaction can involve multiple objects and operations • A transaction context represents the transaction shared by all these participants • By default, it is automatically propagated between transactional objects (EJBs).
Java APIs for Transactions • The Java Transaction API (JTA) is used by application developers • Specifies the interface between the transaction manager and all involved objects • Main class: the UserTransaction interface. • The Java Transaction Service (JTS) is used by developers of transaction managers • Developers of application servers, EJB containers, etc. • Not used by application developers
Transaction Demarcation with EJBs • Normally, you simply do nothing: use container-managed transaction demarcation (CMT) • The EJB container manages transactions automatically • Interaction with databases • Starting and ending transactions • Creating and propagating the transaction context • Even two-phase commit (2PC) • For databases with JDBC drivers that support XA • You can dictate the transactional behavior of specific methods • No programming required -- just edit the deployment descriptor XML • In addition, bean-managed transaction demarcation (BMT) and client-managed transaction demarcation are also available.
Transaction Attribute Values • When using CMT, beans (or specific methods within beans) have a transaction attribute • One of six possible values: • NotSupported • Supports • Required • RequiresNew • Mandatory • Never
Transaction Attribute Values: Supports and NotSupported • Supports: • If the invoker (client, or a different method) has a transaction context, it is propagated to the bean • If not, no transaction context is used • Use this for "don't care" situations • NotSupported: • If the invoker has a transaction context, it is suspended for the duration of this method's execution • If not, no transaction context is used • Either way, the method executes without transaction context
Transaction Attribute Values: Required and RequiresNew • Required: • If the invoker has a transaction context, it is propagated to the bean • If not, the container creates a new transaction context • I.e., the method always executes within a transaction context, but does not create a new transaction needlessly • This is the default value • RequiresNew: • If the invoker has a transaction context, it is suspended for the duration of this method's execution • Either way, a new transaction context is created • Use when you want the method to execute within a transaction, but you do not want failure to cause failure in a wider transaction
Transaction Attribute Values: Mandatory and Never • Mandatory: • If the invoker has a transaction context, it is propagated to the bean • Otherwise, an exception is thrown • TransactionRequiredException or TransactionRequiredLocalException • Use when you want the invoker to provide the transaction • Does not necessarily imply BMT or client managed transactions: the invoker can be a different method in the same EJB • Never: • If the invoker has a transaction context, an exception is thrown • RemoteException or EJBException • Otherwise, the method proceeds normally, without a context • Used for non-transactional resources
Aborting a Transaction • If a business method wishes to abort a transaction, it should invoke setRollBackOnly on its EJB context object • Usually done before throwing an application exception • Use getRollBackOnly to find out if you're "running on empty"
Bean-Managed Transactions • This feature is available for session and message-driven EJBs only • A business method can use JTA create a new UserTransaction object (effectively initiating a transaction), and use it as its own transaction context • UserTransaction methods of note: begin, commit, rollback, setRollbackOnly • This method will be propagated when invoking method on other EJBs (depending on the invoked methods' settings) • The bean that created the transaction is responsible for committing/rolling it back • In stateless session beans, the method that initiated the transaction must end it. • An instance that starts a transaction must complete it before starting a new one.
Client-Managed Transactions • Don't.
Concurrent Access to Entity Beans • Concurrent access by multiple clients is allowed if: • Each client has its own transaction, or • Clients share a transaction and all calls are local • i.e., all clients access the entity bean via its local interface • Concurrent access by multiple clients might fail if clients share a transaction, use remote calls • Support is not required by the EJB specification • If the container does not support this, RemoteException will be thrown
Loopbacks and Reentrancy • An entity bean may not be entered twice simultaneously from within the same transaction: • Note that the client can itself be an EJB, and the transaction could have been automatically initiated by the container • To detect and prevent this, entity EJBs are normally marked as non-reentrant. Session Entity Client (initiates transaction) Exception thrown Session
Loopbacks and Reentrancy (cont.) • But sometimes reentrancy is required, for valid loopbacks: • To enable such loopbacks, you should mark the entity bean as reentrant • In the deployment descriptor • Problem is, now illegal concurrent access will not be detected • Try to avoid algorithms that require loopbacks. Client Session Entity
The SessionSynchronization Interface • Stateful session EJBs (only) that use container-managed transactions can request notifications for transaction events • Enables the bean to maintain a cache that will remain synchronized with the DB • To do this, the bean should simply implement SessionSynchronization • There are three methods in this interface: • afterBegin • beforeCompletion • Your chance to abort the transaction by calling setRollbackOnly on the session context • afterCompleteion(boolean) • The parameter indicates commit (true) or rollback
Recommended Practices for Using Transactions • Always prefer container-demarcated transactions. • Prefer Required, RequiresNew and Mandatory over other options • Supports, NotSupported and Never are not implemented by all containers - compromises portability • WebSphere implements them all
What is EJB QL • A query language used with CMP mappings • For finders and select methods • (Note: We did not cover entity EJB select methods; details later) • Technically, a "modified subset" of SQL • More portable than SQL • Supported by all J2EE servers • Normally compiled to the application server's native query language • In other words, compiled to the app server's SQL variant
An EJB QL Query • EJB QL includes only SELECT queries • Each query includes three parts: • SELECT • FROM • WHERE (optional) • The query may have parameters • The parameters passed to the finder methods
EJB QL Example 1 • SELECT DISTINCT Object(c) FROM Customer c • Finds all customers • Returns a collection • Will not return duplicates (because of DISTINCT) • "Object" is required for all stand-alone identification variables in a SELECT clause • "Customer c" declares the identification variable "c" of type "Customer" • Type defined by abstract schema • "Customer AS c" has the same meaning
EJB QL Example 2 • SELECT DISTINCT Object(c) FROM Customer c, IN (c.accounts) a WHERE a.balance < 0.0 • Returns all customers with at least one account in overdraft • "IN (c.accounts) a" follows Customer's container-managed relationship "accounts" • "WHERE a.balance < 0.0" has the same semantics as a regular SQL WHERE clause, limiting the result set
EJB QL Example 3 • SELECT DISTINCT Object(c) FROM Customer c WHERE (c.address.country = ?1) AND (c.address.city = ?2) • This SQL query accepts two parameters • Appear as "?1" and "?2" in the code • Can be used to implement a finder method that accepts two parameters • Would return all customers from a given city in a given country
Select Methods • Select methods are similar to finders: • In entity bean class, must begin with "ejbSelect" • In CMP entity beans, define as abstract • And provide relevant EJB QL statement in deployment descriptor • In BMP entity beans, implement manually • Return type is the bean's component interface, or a collection • Unlike finders, select methods are not reflected in the home interface • They are for the bean's own use
Exception Types • In J2SE, there are two types of exceptions: • Runtime exception • Checked exceptions • For EJBs, we use a completely different distinction: • Application exceptions • Business-logic related • System exceptions • Represent system-level problems • Note that J2SE Errors still loom in the background (JVM-level problems)
Application Exceptions • Normal exceptions to report business-logic problems • e.g., public void withdraw(float amount) throws OverdraftException • It is the client's role to recover (or just report) such exceptions • "The client" here doesn't refer to the client application, but to whomever invoked the method -- client application, or just another EJB method • Application exceptions must be subclasses of Exception, but must not be subclasses of RuntimeException (i.e., must be checked)
Application Exceptions (cont.) • If an application exception is thrown, and not caught, on the server, it is send to the client • As with regular RMI, the client simply invokes a method and gets an exception in return -- completely transparent. • CreateException, FinderException and RemoveException are all considered application exceptions
System Exceptions • Used to report system-level problems • Failure to locate a JNDI context • Failure to obtain a database connection • Communications problem • ... etc. • Clients are not supposed to handle system exceptions • In case of a system exception, the bean should: • Runtime exceptions: propagate the exception to the container • All other cases: wrap in a new EJBException, and rethrow
Exceptions and Transactions • An application exception does not abort the transaction • However, note that if the exception causes the method that initiated the transaction to end, than the transaction will be stopped • If the client invokes m1, m1 initiates the transaction (due to its Requires attribute) and invokes m2, and m2 throws an application exception, then m1 can try to continue the transaction • If m1 throws (or does not catch) an application exception, the transaction will roll back • A system exception aborts the transaction • The container will log the error and mark the transaction "rollback only" • Any attempt to proceed with the transaction would be futile
The "Generic Application Exception" Pattern • A common pattern suggests defining a superclass for all your application exceptions • "MyAppException" or whatever • All business methods should be declared as "throws MyAppException" in the bean class and the component interface • Even if they throw no exception whatsoever • This way, the clients will have to be written with proper try/catch block surrounding all business calls • Should your beans evolve and methods suddenly do throw exceptions, the clients need not be modified • Through they could be modified to be aware of the specific possible exception • In practice, makes all application exceptions work like runtime exceptions.