EJB Design Patterns
EJB design patterns • Best practice solution to commonly reccuring problems. • Enable us to design efficient, scalable and maintainable systems
Benefits • Provides a high-level language to discuss design issues. • Provides much of the design. • Combinations of patterns form reusable architectures.
Categories • EJB Layer Architectural patterns: Architecture or partitioning of logic – – – – – –
Session Façade Message Façade EJB Command Data Transfer Object Factory Generic Attribute Access Business Interface
• Inter-tier Data Transfer Patterns: For transferring data from the client to the server and back. – Data Transfer Object • Domain DTO • Custom DTO
– Data Transfer Hashmap – Data Transfer Rowset
• Transaction and Persistence Patterns: transaction control, persistence and performance related – Version Number – JDBC for reading – Data Access Command Bean/Data Access Object – Dual Persistent Entity Bean
• Client-side EJB Interaction Patterns: maintainability and performance from client point of view. – EJB Home Factory – Business Delegate
Session Façade
Background • Fine-grained access through remote interfaces increases network traffic and latency. • Overhead of multiple network calls • Processes involve multiple business objects. • Data access and business logic scattered across clients. • Tight coupling between classes. • Decrease in flexibility and design clarity.
• Transactions not safe: When calling an entity beans methods directly, each method call is a separate unit of work, and a separate transaction. • Transaction not maintained across methods
Need • Invoke methods of multiple session or entity beans in one transaction and one bulk network call.
Solution 1 • Put extra logic into our entity beans to perform many operations on behalf of a single client call. • This solution introduces maintenance problems, because our entity bean layer will likely be used in many different ways over time. • Merging our application logic (verbs) with our persistence logic (nouns), which is poor application design.
Solution 2 • Client demarcates a large transaction via the Java Transaction API (JTA). – – – – – –
High network overhead. Poor concurrency. High coupling. Poor reusability. Other clients cannot reuse Mixing of presentation logic with business logic. Poor maintainability. Usage of the Java Transaction API
The Solution • A server-side abstraction that serves as an intermediary, and buffers calls to entity beans. • Session beans will contain application logic to fulfill use-cases. • Each session bean performs bulk operations on entity beans on behalf of a single client request. • Clients have access to session beans only, not entity beans.
Advantages • Low network overhead. • Lower overall overhead on client end. • Session bean is the transactional façade, localizes transactions to the server-side, and keeps them short, giving higher concurrency. • Lower coupling. • Entity beans remain reusabe. • Better maintainability: Clean separation of middleware (transaction) and application logic. • Clean verb-noun separation.
Role of Use Cases • Do not map every use case to a session façade. • Consolidate them into fewer session beans based on some logical partitioning. • Design session facades to aggregate a group of the related interactions into a single session façade.
• For a banking application, group the interactions related to managing an account. • The use cases Create New Account, Change Account Information, View Account information, and so on all deal with the coarse-grained entity object Account. • Group into a single session façade called AccountSessionFacade.
Message Façade • For asynchronous use cases.
EJB Home Factory
try { Properties properties = new Properties(); properties.put (javax.naming.Context.PROVIDER_URl, "some providers url"); properties.put (javax.naming.Context.INITIAL_CONTEXT_FACTORY, "some name service"); initContext = new InitialContext(properties); Object homeObject = initContext.lookup("aHomeName"); myHome = (MyHome) javax.rmi.PortableRemoteObject.narrow (homeObject, MyHome.class ); } catch (Exception e) {…} MyEJB anEJB = myHome.create();
Background • Multiple lookups of the same home are redundant. • Home is used only once • an EJBHome never goes stale and can be reused for the lifetime of the client application. • Requires a network call if JNDI server is on a different machine.
Solution • Place EJB Home lookup code into a reusable EJB Home Factory, which can cache EJB Homes for the lifetime of a client application. • Reuse the same EJB home instance throughout the life time of the client. • Plain java class. • Singleton
EJBHomeFactory - HashMap ejbHomes; - EJBHomeFactory aHomeSingleton - InitialContext ctx; + static getFactory() : EJBHomeFactory + lookUpHome(Class aHomeClass) : EJBHome
looks up/caches
uses singleton
EJBClient
<> EJBHome
uses
ParticularHome
Client code AccountHome anAccountHome = (AccountHome)EJBHomeFactory.getFactory(). lookUpHome(AccountHome.class);
import import import import
javax.ejb.*; java.rmi.*; java.util.*; javax.naming.*;
public class EJBHomeFactory { private Map ejbHomes; private static EJBHomeFactory aFactorySingleton; Context ctx;
private EJBHomeFactory() throws NamingException { ctx = new InitialContext(); this.ejbHomes = Collections.synchronizedMap (new HashMap()); } public static EJBHomeFactory getFactory() throws NamingException { if ( EJBHomeFactory.aFactorySingleton == null ) { EJBHomeFactory.aFactorySingleton = new EJBHomeFactory(); } return EJBHomeFactory.aFactorySingleton; }
public EJBHome lookUpHome(Class homeClass) throws NamingException { EJBHome anEJBHome = (EJBHome) this.ejbHomes.get(homeClass); if(anEJBHome == null) { anEJBHome = (EJBHome) javax.rmi.PortableRemoteObject.narrow (ctx.lookup(homeClass.getName()), homeClass); this.ejbHomes.put (homeClass, anEJBHome); } return anEJBHome; } }
Business Delegate
Background • When using Session and/or Message Façade, the client is coupled to the EJB layer, creating dependencies between client and server.
Problems • Complicates client logic with complex error handling. – NamingExceptions, RemoteExceptions, EJBException to be caught
• Couples the clients directly to EJB and JMS API’s. • Lookup and exception handling code
Cont… • Dependency of client and server programmers on availability of the complete and compiled session bean layer. • Client programmers depend on the implementation of the Session Façade in order to compile and test their code.
Cont… • Places recovery responsibility on clients. – When a transaction fails. – May not be necessary to propagate this error to the end application user and ask them to retry. – Instead, client code may automatically reexecute the transaction. – Client code needs to be explicitly aware of catching these transactions and re-trying them
Solution • Client-side Intermediary between a client and the Session Façade
Solution • Introduce intermediate class business delegate to decouple business components from the code that uses them. • Manages the complexity of distributed component lookup, exception handling and recovery • Adapts the business component interface to a simpler interface for use by views. • Plain java classes
How? • Clients locally invoke methods on the BD • BD delegates directly to a method with the same signature on the session façade, or populate a JMS message and send it to the Message Façade. • Maps one-to-one to session beans • Wrap multiple message driven beans.
Functions of BD • Delegate method calls to an EJB. • Hide EJB specific system exceptions. – RemoteException and EJBException – JMS exceptions are caught in the business delegate and re-thrown to the client as a non-ejb specific exceptions, such as a BusinessDelegateException. – Application level exceptions are passed to the client.
• Cache data locally. • Transparently re-try failed transactions. • Prototype business delegates can be written that simply return dummy data
public class ForumServicesDelegate { ForumServices sb; public ForumServicesDelegate() throws DelegateException { try{ PortalControllerHome home = (PortalControllerHome) EJBHomeFactory.getFactory().lookUpHome (PortalControllerHome.class, "ForumServices"); this.sb = home.create(); } catch (Exception e){ throw new DelegateException(); } }
public long addForum (long categoryPK, String forumTitle, String summary, String imageName) throws NoSuchCategoryException, DelegateException { try{ return sb.addForum(categoryPK, forumTitle, summary, imageName); } catch(CreateException e){ throw new DelegateException(); } catch(RemoteException e){ throw new DelegateException(); } } }
EJB Command
Problems with SF/BD • Slower development process. – Changing a use-case requires editing 3 different files (interface, bean class, deployment descriptor) plus redeployment – BD to be changed.
• Server resources often controlled by just one team in a large corporation. Difficult to effect any changes on existing classes.
EJB Command • Developing with a session façade and business delegates can result in long change-deploy-test roundtrips, which can become a bottleneck in a large project. • The crux of the problem is that the business logic is being placed in a layer of session EJB’s, which can be pretty heavy weight to develop with.
The Command Pattern • Wrap business logic in lightweight command objects • Decouple the client from EJB • Execute in one network call • Act as a façade to the EJB layer • plain java class with gets, sets and an execute method
How? • Clients interact with the command object locally • Execute within a remote EJB server, transparently to the client. • Encapsulate individual units of work in an application. • A use case’s business logic encapsulated in a command.
Command client view
TransferFunds w ithdraw AccountID depositAccountID transferAmount w ithdraw AccountBalance depositAccountBalance setWithdraw AccountID(int) setDepositAccountID(int) setTransferAmountID(double) execute() getWithdraw AccountBalance() getDepositAccountBalance()
Client interaction with a command • • • •
Client creates a Command Client sets attributes onto the command Client calls the command’s execute method Client calls gets on the command until it has retrieved all the data resulting from the execution of the command/use case.
Working • The command is actually transferred to a remote EJB server and executed within the EJB servers JVM. • When the command has completed executing, it is returned to the client, who can then call get methods to retrieve data.
Interaction • The client instantiates the command object • The client calls an executeCommand method on the routing logic/CommandExecutor • The CommandExecutor delegates the call to an EJBCommandTarget (part of routing logic) • The command target knows how to send the command to the command server • CommandServer is a stateless session bean. • CommandServer calls the execute method on the command, which then goes about its business logic.
Benefits • Rapid Application Development (RAD) • Separation of business logic from presentation logic. • Forces execution of use cases in single roundtrip. • Decouples client from EJB. • Commands can execute locally or produce dummy data. • Allows multiple return values.
Disadvantages • Very coarse-grained transaction control. Commands can only run under the transaction settings of the CommandServer that executes them. The workaround for this is to deploy multiple command server session beans with different jndi names and transaction settings (configured in the deployment descriptors). • Can’t use security: Since business logic is embedded in the command beans • Commands can become unmanageable on large projects.
Compare Session beans • Cheaper session beans. • They are more lightweight, • Quicker initial development process at the expense of possibly less maintainability over time.
Data Transfer Object or Value Object
Exchange of data • Read data from the server for display purposes • Change some data on the server by creating, updating or removing data.
Need • Transfer bulk data with the server. – Many parameters in a method call. – Client gets multiple attributes from a session or entity bean by executing multiple fine-grained calls to the server
The wrong way to get data from the server
Client
EJB Network getAttribute1() getAttribute2() getAttribute3() getAttribute4() getAttribute5()
Problem • Each call to the server is a network call • Blocking on the client while the EJB server intercepts the call to the server and performs transaction and security checks and retrieval • Each method call executes in its own separate transaction if the client is not using Java Transaction API client demarcated transactions.
To Achieve • Client exchange bulk data with the server without making multiple fine-grained network calls
Solution • Create plain java classes called Value Objects or DTOs, which contain and encapsulate bulk data in one network transportable bundle. • A value object is a plain serializable Java class that represents a snapshot of some server side data
import java.io.Serializable; public class SomeValueObject implements Serializable { private long attribute1; private String attribute2; private String attribute3; public long getAttribute1(); public String getAttribute2(); public String getAttribute3(); }
The right way to read data from the server Client
SomeValueObject
EJB
getSomeValueObject() getAttribute1() getAttribute2() getAttribute3() getAttribute4()
getAttribute5()
Network
How to design the DTO? • At the start value objects are copies of server side entity beans (or domain objects) called Domain Value Objects • As the needs of the clients are finalized, Domain Value Objects often become cumbersome as units of exchange • Custom Value Objects: value objects that wrap arbitrary sets of data, completely driven on the particular needs of the client.
DTO Factory
Need • When value objects change very often. • Value object creation and consumption logic should be implemented so as to minimize the impact of frequent changes in the value objects on the rest of the system.
Problem • Value Objects have a tendency to change often. • Domain Value Objects change whenever the domain objects change (adding a new attribute to an entity bean, etc). • Custom Value Objects are just use case specific data holders for transporting data across a network; they can change as frequently as your application’s presentation view. • Tens to hundreds of different Value Objects, each of which would require custom logic to create it. • How and where should this logic be implemented?
Solution 1 • getXXXValueObject / setXXXValueObject methods directly on entity beans. • Tightly couples the value object layer to the entity bean layer. • Every time a web page changed and a different view of the data model was required, you would have to add a new method to an entity bean, recompile your entity bean, and redistribute your remote interfaces to any client using them. • Entity beans are are no longer reusable.
Solution • Place the responsibility for creating and consuming Value Objects in a ValueObjectFactory or a DTO Factory.
Benefits • Separates the logic related to Value Objects (part of the application domain) from other components in your system such as entity beans (part of the business domain). • When new views or different subsets of server side data become necessary, new value object creation methods can be added to the ValueObjectFactory. • The entity beans themselves do not need to know about these different views of their data.
Benefits • Better maintainability. Entity beans no longer need to be changed and recompiled when the needs of the client change. • Enables entity bean reuse.
Business Interface
Need • The enterprise bean class MUST provide an implementation of all methods declared in the Remote or Local interface
Need • The EJB developer must manually maintain consistency between interface definition and bean implementation. • No automatic way to detect these problems at compile time. • server vendor’s proprietary post-compilation tool. • How can inconsistencies between remote/local interface methods and the enterprise bean implementation be discovered at compile-time?
Solution 1 • The enterprise bean directly implement the remote or local interface in the bean class. • This would enforce consistency between method definition and implementation, using any standard java compiler. • EJB specification advises against this practice • These interfaces define extra methods (isIdentical, getPrimaryKey, remove, etc), which are meant to be implemented by the EJBObject and EJBLocalObject stubs, not the enterprise bean class.
<> java.rmi.Remote
<> javax.ejb.EJBObject getEJBHome() getHandle() getPrimaryKey() isIdentical(obj) remove()
<> Remote businessMedthod1() businessMedthod2() ....
EJBObject and EJBLocalObject Interfaces
<> javax.ejb.EJBLocalObject getEJBLocalHome() getPrimaryKey() isIdentical(obj) remove()
<> Local businessMedthod1() businessMedthod2() ....
Cont… • Clutters your enterprise bean class by writing dummy implementations of these extra methods. • The bean could be directly cast to one of these interfaces, allowing a developer to pass an instance of this to a client. • Not allowed by the EJB specification. • To pass a reference to one-self, a bean needs should first get a reference to itself by calling getEJBObject or getEJBLocalObject off of the SessionContext or EntityContext interface.
Solution • Create a super interface called a Business Interface, which defines all business methods. • Both the remote/local interface and the enterprise bean class implement this interface, forcing compile-time consistency checks.
Business Interface for Remote and Local Beans <> java.rmi.Remote
<> javax.ejb.EJBObject getEJBHome() getHandle() getPrimaryKey() isIdentical(obj) remove()
<> Remote
<> BusinessRemote businessMedthod1() throws RemoteException() businessMedthod2() throws RemoteException ....
EnterpriseBean
<> javax.ejb.EJBLocalObject getEJBLocalHome() getPrimaryKey() isIdentical(obj) remove()
<> Local
<> BusinessLocal businessMedthod1() businessMedthod2() ....
EnterpriseBean
attribute1 attriute2 ...
attribute1 attriute2 ...
businessMedthod1() businessMedthod2() .... //EJB Methods ....
businessMedthod1() businessMedthod2() .... //EJB Methods ....
JDBC for Reading
JDBC for Reading • Present static server-side data to a client in tabular form. • Read-only
HTML Table of Employees
Employee
Department
Adam Berman Eileen Sauer Ed Roman Clay Roach
Development Training Management Architecture
Solution 1 • • • •
Employee and a Department entity bean. getEmployees() method on a Session Façade finder method on an EmployeeHome object find each employee’s related department entity bean • Create a Custom Data Transfer Object with the combined data from these two entity beans. • Session bean returns a collection of EmployeeDepartmentDTOs.
Problems • The n+1 entity bean database calls problem. • With BMP and certain implementations of CMP, retrieving data from N entity beans require N+1 database calls. – finder method (one database call). – ejbLoad() individually on each entity bean returned by the finder method, lock a db conn of the pool, n/w call,
• Employee and Departments example: 2N+1 database calls
Cont… • Remote Call overhead. If going through the entity bean remote interface (as opposed to the local interface), this method would also require 3N remote calls for N rows of employee and department data. The remote calls break down as follows: – N calls to getValueObject() for each Employee. – N calls to getDepartment() on each Employee. – N calls to getValueObject() on each Department.
• Require tens of lines of code • Significantly slow down a system due to – the database calls – remote calls – overhead incurred for traversing multiple entity bean relationships
Need • Client side mainly requires tabular data for read only, listing purposes • Using local interfaces will reduce the performance problems • Querying through the entity bean layer for simply listing of read only data causes unacceptable performance problems • In BMP, perform listing operations on relational databases using JDBC.
• Using JDBC to directly read the rows and columns required by the client can be far faster and more efficient then going through the entity bean layer. • Entire table of employees and departments could be bulk-read in just one JDBC call from the database • After reading in the ResultSet return using, – EmployeeDepartmentDTO – HashMaps – RowSets
Benefits • Perform queries in ONE BULK READ. • Takes advantage of DB built in caching. • The next time a query is run, the one bulk JDBC query will come directly from the database cache. • Retrieve the exact data your use case requires. Using JDBC, you can select the exact columns required across any number of tables.
Tradeoffs • Tight coupling between business and persistence logic. Data Access Object can be used to alleviate this problem. • Bug prone and less maintainable. • Changes to the database schema will require changes to multiple code fragments across the Session Façade.Data Access Object pattern can help here.
Data Transfer HashMap
Data Transfer HashMap • A client needs to exchange bulk data with the server in a generic fashion.
Problems with DTO • • • •
Minimizing on the number of network calls Data Transfer Objects help in this. new DTO for every new use case High cost to change: new DTOs and associated creation logic must be written.
Cont… • Data Transfer Objects create a new layer, which can explode to thousands of objects in a large application. • Changes in entity bean attributes will cause ripples that could require changes in multiple DTOs as well. • Client UI’s tightly coupled to the server. • Each client UI is tightly coupled to the DTO it uses
Solution • Use HashMaps to marshal arbitrary sets of data between client and EJB tier.
• Plain JDK HashMaps provide a generic, serializable container for arbitrary sets of data, that can replace an entire layer of Data Transfer Objects. • The only dependency been client and server side code is the naming conventions placed on the keys used to identify attributes, described later in this pattern. • Clients request HashMaps by going through the Session Façade.
Using a Data Transfer HashMap
Client
SessionFacade
AccountHashMap getAccountData() get("accountNumber") get("name") get("passw ord")
Netw ork
get("balance") put("balance", 123) setAccountData(aHashMap)
• A client is passed a HashMap that contains different sets of data, as needed by the particular use case. • Using a HashMap instead of a data transfer object comes at the cost of additional implementation complexity, since the client now needs to explicitly know the strings used as keys to query the HashMap for the attributes of interest. • The session façade and the client agree on the strings to be used by to populate and read from a HashMap.
Benefits • Excellent maintainability - eliminates the Data Transfer Object layer.
• One data object (Map) across all clients. A Map of attributes is reusable from the Session Façade down to the JSPs. In particular, using a Map as a data container significantly reduces the complexity of the JSP code, as pages don’t need to be written with use case specific Value Objects that are tightly coupled to the entity bean layer. • Low cost of maintenance over time. New views of server side data can be created that does not require any server side programming. Clients can dynamically decide which attributes to display.
Tradeoffs • Need to maintain a contract for attribute keys. Extra dependency between client and server. • Loss of strong typing/compile time checking.
Data Transfer Rowset
Data Transfer RowSet • When using JDBC for Reading, relational data needs to be transferred across the network tier from the Session Façade to the client. • How can relational data be transferred to the client in a generic, tabular format?
public class EmployeeDepartmentViewObject { public String employeeName; public String employeeTitle; ... public String departmentName; public String departmentLocation; ... }
• Session bean performs a JDBC call to get a ResultSet that contains information about an employee and their department. • Session bean manually extracts fields from the ResultSet and calls the necessary setters to populate the DTO. • Each row in the ResultSet will be transferred into a DTO which will be added to a collection. • This collection of DTO’s now forms a network transportable bundle, transferable to the client for consumption.
Problem • Tabular to OO and back to tabular is redundant. • Preserve the tabular nature of the data being transferred in a generic fashion, allowing for simpler clients and simpler parsing into the client UI.
Solution • Use RowSets for marshalling raw relational data directly from a ResultSet in the EJB tier to the client tier.
RowSet • An interface, a subclass of java.sql.ResultSet. • CachedRowSet implementation allows you to wrap ResultSet data and marshal it off to the client tier. • Client can operate directly on the rows and fields. • CachedRowSet is disconnected from the database. • Once the CachedRowSet has been initialized with data, database connections can be closed – the CachedRowSet now maintains a copy of the results of the SQL query.
Value Objects vs. RowSets
{
Client side Table UI
Department
Adam Berman Eileen Sauer Ed Roman Clay Roach
Development Training Management Architecture
Adam Berman Eileen Sauer Ed Roman Clay Roach
Adam Berman | Development
Eileen Sauer | Training
OR
{
Collection of Employee Department Custom Data Transfer Objects
Employee
Ed Roman | Management
Clay Roach | Architecture
Development Training Management Architecture
}
Single RowSet Object
Advantages • Provides a common interface for all query operations. • All the clients can use the same interface for all data querying needs. • No matter what the use case is or what data is being returned, the interface a client operates on stays the same. • Eliminates the redundant data translation.
Tradeoffs • Clients need to know the name of database table columns. Maintaining a ‘contract’ of attribute names between client and server, as described in the Generic Attribute Access pattern. • Not object oriented. • No compile-time checking of query results. Rather than calling getXXX() on a value object, a client must now call getString(“XXX”) on the RowSet, possibility of mistyping the attribute name.
Data Access Object
Problem • Access to data varies depending on the source of the data. Access to persistent storage, such as to a database, varies greatly depending on the type of storage (relational databases, object-oriented databases, flat files, and so forth) and the vendor implementation. • Code that depends on specific features of data resources ties together business logic with data access logic. This makes it difficult to replace or modify an application's data resources.
Participants • BusinessObject : requires access to the data source to obtain and store data. a session bean, entity bean, Java object, a servlet or helper bean. • DataAccessObject : abstracts the underlying data access implementation. Enables transparent access to the data source. • DataSource : a database such as an RDBMS, OODBMS, XML repository, flat file system, another system (legacy/mainframe), service (B2B service or credit card bureau), or some kind of repository (LDAP). • TransferObject : This represents a Transfer Object used as a data carrier. To return/receive the data to/from the client.
Benefits • Separates a data resource's client interface from its data access mechanisms • Adapts a specific data resource's access API to a generic client interface • Allows data access mechanisms to change independently of the code that uses the data.
References •
•
EJB Design Patterns by Floyd Marinescu - Wiley. (available online at www.theserverside.com and \\Kalpa) J2EE Design Patterns Catalog http://java.sun.com/blueprints/patterns/cata log.html
•
Core J2EE Patterns (online book) http://java.sun.com/blueprints/corej2eepatte rns/Patterns/
•
Sun Java Center J2EE Patterns http://developer.java.sun.com/developer/rest ricted/patterns/J2EEPatternsAtAGlance.html