Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 29 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
29
Dung lượng
154,19 KB
Nội dung
public Map getAllAttributes() { return(HashMap)attributes.clone(); } /** * Used by clients to specify the attributes they are interested in * @return java.util.Map * @param keysofAttributes the name of the attributes the client is * interested in */ public Map getAttributes(Collection keysofAttributes) { Iterator keys = keysofAttributes.iterator(); Object aKey = null; HashMap aMap = new HashMap(); while ( keys.hasNext() ) { aKey = keys.next(); aMap.put( aKey, this.attributes.get(aKey)); } //map now has all requested data return aMap; } /** * Used by clients to update particular attributes in the entity bean * @param keyValuePairs java.util.Map */ public void setAttributes(Map keyValuePairs) { Iterator entries = keyValuePairs.entrySet().iterator(); Map.Entry anEntry = null; while ( entries.hasNext() ) { anEntry = (Map.Entry)entries.next(); this.attributes.put(anEntry.getKey(), anEntry.getValue()); } } In Container-Managed Persistence (CMP), using an internal map of attrib- utes is not possible, since the implementation of an entity bean’s classes is abstracted behind container generated get and set methods. When using an internal map is not possible, the attribute access interface can be implemented generically using the Java Reflection API. That is, in setAttributes, reflection can EJB Layer Architectural Patterns 35 be performed on the key-value of the attribute a client wants to set. Specifi- cally, if the key-value is XXX the setAttribute implementation will attempt to call setXXX( ) on the entity bean. Similarly, in the getAttributes method, reflec- tion can be used to find all get methods on an entity bean, invoke them and populate a map for the client. If a developer would prefer not to use the Reflec- tion API, then implementing the Attribute Access method cannot be done generically for CMP. The developer will need to interlace his Attribute Access implementation with IF statements that call hard-coded get/set methods on the entity bean, depending on the key-value string. In order to make the Attribute Access implementation code reusable across all entity beans, a superclass can be used to implement the interface methods, which are completely generic, whether we use the reflection method or the internal map of attributes style of implementation. All entity beans wanting to make use of the Attribute Access services need only to subclass the superclass implementation, thus automatically exposing this unified interface to their attributes with no extra coding required. The final piece of the puzzle is how to name the keys, which identify the attributes of an entity bean. Not only do the attributes need to be identified by key, but both the logic that accesses an entity bean via the attribute access interface and the entity bean itself need to agree on the naming conventions. Some sort of “contract” is required between client and server. Several possibil- ities are discussed: ■■ Establish a consistent, well-documented naming convention. The client and the entity bean can agree upon a well-documented, consis- tent naming convention for attributes. For an Account entity bean, “com.bank.Account.accountName,” or simply “accountName” would be an example of a consistent convention. The drawback with this approach is that the contract exists in the minds of developers and on paper only. When developing, it is easy to misspell the attribute name, resulting in costly development errors that are hard to track down. ■■ Define static final member variables in the entity bean remote or local interface. An entity bean client can make calls to the entity bean using references to static final variables containing the correct key- string required to get an attribute. For example, in order to retrieve the attributes from an Employee entity bean; a session bean could use the following code: //Ask employee for personal attributes Collection aCollection = new ArrayList(); aCollection.add(Employee.NAME); aCollection.add(Employee.EMAIL); aCollection.add(Employee.SEX); 36 Chapter One aCollection.add(Employee.SSN); Map aMap = employee.getAttributes(aCollection); Where the entity beans local interface contains the following definitions: public interface Employee extends EJBLocalObject, AttributeAccess { //Since attributes are stored in a hashmap in the entity bean, //we need a central place to store the ‘keys’ used to reference //attributes, so that the clients and the entity bean won’t need //need to be hard-coded with knowledge of the attribute key strings public final static String ID = “EMPLOYEEID”; public final static String NAME = “NAME”; public final static String EMAIL = “EMAIL”; public final static String AGE = “AGE”; public final static String SSN = “SSN”; public final static String SEX = “SEX”; } This approach works great for the DTO factory approach, where a ses- sion bean is querying the entity bean directly for its attributes, with the intention of returning a hard-coded data transfer object to the client, instead of a HashMap. Here, only the session bean and the entity bean need to agree on the names of the attribute keys, making the local/ remote interface a good place to localize names of the attributes. This approach breaks down when using the Data Transfer Hashmap pattern, since the client also needs to know the names of the key-values, but the client does not have access to the entity bean’s remote/local interface. ■■ Shared class with static final member variables. Here we can create a class that is shared by both the client classes and the server classes, which is used to encapsulate the actual strings used to populate and read strings from a HashMap behind a hard-coded final static variable, accessible by both client and server. For example, a client would query a hashmap for an attribute as follows: accountMap.get(Names.ACCOUNTBALANCE) Where the shared class called Names would look like: public class Names { public final static String ACCOUNTBALANCE = “BALANCE”; } EJB Layer Architectural Patterns 37 One disadvantage to this method is that should the key mappings need to be updated or added to, the new class would need to be redistributed to the client and the server (and their JVM would thus need to be restarted). ■■ Place the Attribute contract in a JNDI tree. In this approach, a single- ton of sorts is maintained by placing a class containing the keys in a JNDI tree, accessible by client and server. Client and server code would not need to be recompiled or rebooted, when keys were changed/ updated, since a central object in a JNDI tree would always contain the freshest copy of keys. The trade-off with this solution is the overhead incurred in grabbing the contract from the JNDI tree whenever key- values are required. The Generic Attribute Access pattern has many advantages: ■■ One interface across all entity beans. Entity bean clients can manipulate entity beans consistently via the attribute access interface, simplifying client code. Entity beans are also simplified, because the attribute access can be encapsulated in a superclass. ■■ Scales well to large entity beans. Whether an entity bean has 20 or 2000 attributes, attribute access logic is simplified to just a few lines. ■■ Low cost of maintenance over time. New views of server-side data can be created that do not require any server-side programming. Clients can dynamically decide which attributes to display. ■■ Allows for dynamic addition of attributes at run time. When using BMP, this pattern can easily be extended to allow for the ability to add and remove attributes from an entity bean dynamically. This can be achieved by adding an addAttribute and removeAttribute method to the interface, which simply performs operations on the attribute HashMap. Like all patterns, using Generic Attribute Access has its trade-offs: ■■ Additional overhead per method call. For each attribute call, clients must use an attribute key to identify attributes. Finally, attributes need to be cast to their appropriate type after being extracted from the HashMap object. ■■ Need to maintain a contract for attribute keys. Since attributes are requested by string, clients need to remember the key-strings used to identify attributes. Defining a key-attribute contract (discussed earlier in this pattern), can alleviate these dependencies. ■■ Loss of strong typing/compile-time checking. When we use DTOs, values passed by gets or sets are always of the correct type; any errors would be passed at compile time. When we use Generic Attribute 38 Chapter One Access, attribute access must be managed by the client at run time by casting objects to their correct type and associating the correct attribute type with the correct key. Overall, the Generic Attribute Access pattern provides a generic method of managing the state of entity beans, eliminating the bulky repetitive code asso- ciated with domain-specific entity bean data access. Related Patterns Property Container (Carey, et al., 2000) Data Transfer HashMap EJB Layer Architectural Patterns 39 Business Interface The EJB specification mandates that the enterprise bean class provide an implementation of all methods declared in the remote or local interface, but the bean cannot directly implement these interfaces. How can inconsistencies between remote/local interface methods and the enterprise bean implementation be discovered at compile time? * * * One of the most common errors experienced during the EJB development process is the lack of consistency between the business method definitions in the remote or local interfaces and implementations in the enterprise bean class. The EJB specification requires that the enterprise bean properly implement all the business method signatures defined in the remote/local interface, but does not provide for an automatic way to detect problems with this at compile time. Many types of errors can arise from this decoupling of interface definition and implementation, including mistyping of method names, parameter types, exceptions, inconsistent parameters, and so on. As a result, these types of errors cannot be detected at compile time, the EJB developer must manually maintain consistency between interface definition and bean implementation. The errors can only be detected when using your EJB server vendor’s pro- prietary postcompilation tool. These tools are typically used to take compiled Java classes and test them for compliance to the EJB spec, before packaging and deploying them. These postcompilation tools are typically slow and ardu- ous to use, and are less viable for incremental compilation practices that devel- opers often use to catch errors early. The end result is that development errors are caught later on in the development process. One solution would be to have 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. Unfortunately, the EJB specification advises against this practice, and with good reason. The remote interface extends javax.ejb.EJBObject inter- face, and the local interface implements the javax.ejb.EJBLocalObject interface, as shown in Figure 1.15. These interfaces define extra methods (isIdentical, get- PrimaryKey, remove, etc), which are meant to be implemented by the EJBObject and EJBLocalObject stubs, not by the enterprise bean class. 40 Chapter One Figure 1.15 EJBObject and EJBLocalObject interfaces. In order to make your bean compile, you would have to clutter your enter- prise bean class by writing dummy implementations of these extra methods. Furthermore, if the enterprise bean class directly implemented the remote or local interface, the bean could be directly cast to one of these interfaces, allow- ing a developer to pass an instance of this to a client. This behavior is not allowed by the EJB specification. To pass a reference to oneself, a bean needs to first get a reference to itself by calling getEJBObject or getEJBLocalObject from the SessionContext or EntityContext interface. EJB developers should not implement the remote or local interfaces directly in their enterprise bean class, but developers need a mechanism that would allow compile-time confirmation of consistency between remote/local inter- face method definitions and implementations in the bean class. getEJBLocalHome() getPrimaryKey() isIdentical(obj) remove() <<interface>> javax.ejb.EJBLocalObject getEJBHome() getHandle() getPrimaryKey() isIdentical(obj) remove() <<interface>> javax.ejb.EJBObject <<interface>> java.rmi.Remote businessMethod1() businessMethod2() <<interface>> Remote <<interface>> Local businessMethod1() businessMethod2() EJB Layer Architectural Patterns 41 Therefore: Create a superinterface called a business interface, which defines all business methods. Let both the remote/local interface and the enterprise bean class implement this interface, forcing compile-time consistency checks. A business interface is a plain Java interface that defines the method signa- tures for all the business methods that an enterprise bean chooses to expose. The business interface is implemented by the remote or local interface, and the enterprise bean class, as shown in Figure 1.16. By creating this superinterface, errors in consistency between the method signature definitions in the remote/ local interface and the enterprise bean class can be caught at compile time. The business interface does not implement javax.ejb.EjbObject or javax.ejb. EJBLocalObject, so the bean class developer does not have to implement dummy methods. Furthermore, the developer cannot cast the bean class directly to its remote or local interfaces, keeping the bean developer from passing this to its clients. Figure 1.16 Business interface for remote and local beans. businessMethod1() throws RemoteException() businessMethod2() throws RemoteException <<interface>> BusinessRemote <<interface>> javax.ejb.EJBLocalObject getEJBHome() getHandle() getPrimaryKey() isIdentical(obj) remove() <<interface>> javax.ejb.EJBObject <<interface>> java.rmi.Remote <<interface>> Remote businessMethod1() businessMethod2() <<interface>> BusinessLocal getEJBHome() getPrimaryKey() isIdentical(obj) remove() <<interface>> Local EnterpriseBean attribute1 attribute2 businessMethod1() businessMethod2() //EJB Methods EnterpriseBean attribute1 attribute2 businessMethod1() businessMethod2() //EJB Methods 42 Chapter One The business interface pattern differs slightly, depending on whether the enterprise bean exposes its business methods on the local interface or the remote interface. If the entity bean exposes the remote interface, all method signatures on the business interface need to throw java.rmi.RemoteException (but do not need to extend java.rmi.Remote). Note that the method implemen- tations in the enterprise bean class should not throw RemoteException, this has been deprecated by the EJB specification. Instead, business methods can throw EJBException from within the body of a method, without declaring it in the throws clause, since EJBException is a subclass of RuntimeException. When using the business interface with a local interface, the business inter- face need not implement any other interface, and the business method signa- tures can be written without any special rules. There is one dangerous side effect of using the Business Interface pattern. For methods whose return values are the remote/local interface of the bean itself, implementing the business interface allows the bean developer to return this without any compile-time problems being detected. This is possible because both the bean class and the remote/local interface implement the business interface. Returning this is always caught at compile time when the Business Interface pattern is not used (since the bean class doesn’t implement the remote/local interface). Thus, special care must be taken by bean developers using a business interface pattern to not return this, or unpredictable errors can occur at run time. The Business Interface pattern is a common pattern in EJB development. It allows developers to catch common programming errors at compile time, ensur- ing consistency between business method definition and implementation. EJB Layer Architectural Patterns 43 [...]... have an Account DTO, as shown in Figure 2 .3 AccountBean AccountDTO accountNumber name password balance accountNumber name password balance / /ejb methods ejbLoad() ejbStore() getAccountNumber() getName() getPassword() getBalance() setAccountNumber() setName() setPassword() setBalance() Figure 2 .3 Account EJB and Account domain DTO Inter-Tier Data Transfer Patterns Using domain data transfer objects... this object to the session façade, which would use it in the ejbCreate method on AccountHome The less maintainable alternative would be to pass all the attributes of Account as method parameters to the session façade and then to ejbCreate() For example, which looks more maintainable: ejbCreate(attrib1, attrib2, attrib3, attrib4, attrib5, ), or ejbCreate(aDTO)? Much debate has arisen as to whether domain... Java application development world This chapter covers the following patterns: Data Transfer Object The essential design pattern Discusses why, how, and when to marshal data across the network in bulk bundles called data transfer objects (DTOs) The two follow-up patterns (Domain and Custom DTO) provide guidance about how DTOs should be designed Domain Data Transfer Object Interacting with the domain model... access needs of the client Once an EJB project has been launched, access to server-side programmers tends to be expensive, as is the EJB redeployment process I I Need to create a data transfer object layer Data transfer objects create a new layer, which can explode to thousands of objects in a large application Imagine a distributed system with 30 entity beans Each of those 30 entity beans would likely have... encapsulated in any domain data transfer objects At this point, developers can design custom data transfer objects, that is, data transfer objects that wrap arbitrary sets of data, completely driven on the particular needs of the client The differences between these two design paradigms can have significant impact on the design of the application as a whole Although they represent contradictory approaches,... is that as soon as the data reaches the client, it has the potential of being stale The Version Number pattern (see Chapter 3) can help protect against problems with staleness Related Patterns State Holder Value Object (Alur, et al., 2001) Details Object Inter-Tier Data Transfer Patterns Domain Data Transfer Object A client wants to access and manipulate data from the server-side domain object model... Network getAttribute1() getAttribute2() getAttribute3() getAttribute4() getAttribute5() Figure 2.1 An inefficient way to get data from the server EJB 47 48 Chapter Two The problem with this approach is that each call to the server is a network call, requiring the serialization and deserialization of return values, blocking on the client while the EJB server intercepts the call to the server and performs... object design at about the same time they need to decide upon what EJB interfaces to use Despite this need, designing data transfer objects at the beginning of a project can be difficult since developers often don’t completely understand exactly what units of data should be transferred between the client and server An easy way to start in designing data transfer objects is as copies of serverside entity... transfer objects be designed when domain data transfer objects don’t fit? *** The Data Transfer Object pattern introduced the notion of using a data transfer object to pass bulk data between the client and server The Data Transfer Object pattern described a common method of designing data transfer objects—by mapping directly to the object model used on the server side Although this method of designing data... model length width height year horsepower volume engine type engine model CarEngineDTO horsepower volume engine type engine model getHorsePower() getVolume() getEngineType() getEngineModel() / /ejb methods ejbLoad() ejbStore() Figure 2.4 A Custom data transfer object wrapping a subset of data 57 58 Chapter Two A typical J2EE application will have a proliferation of custom DTOs, so many so that often developers . have an Account DTO, as shown in Figure 2 .3. Figure 2 .3 Account EJB and Account domain DTO. accountNumber name password balance / /ejb methods ejbLoad() ejbStore() AccountBean accountNumber name password balance getAccountNumber() getName() getPassword() getBalance() setAccountNumber() setName() setPassword() setBalance() AccountDTO 52. the EJB specification advises against this practice, and with good reason. The remote interface extends javax .ejb. EJBObject inter- face, and the local interface implements the javax .ejb. EJBLocalObject. <<interface>> BusinessRemote <<interface>> javax .ejb. EJBLocalObject getEJBHome() getHandle() getPrimaryKey() isIdentical(obj) remove() <<interface>> javax .ejb. EJBObject <<interface>> java.rmi.Remote <<interface>> Remote businessMethod1() businessMethod2()