2.1 Design

I l @ ve RuBoard

Application design is the first step in J2EE application development, as any text on the topic will attest. The reason for this is simple: changing the design is usually much more expensive than adding a new feature, or fixing a bug in the application. Design of the EJBs will also significantly impact the performance of a J2EE application.

2.1.1 Know When to Use EJBs

Even though EJBs are great, they are not always the right solution to the problem at hand. Developers often refer to this as "using a sledgehammer to crack a nut." Whenever you are considering how to implement your application, bear in mind the following basic guidelines:

Design

The EJB component model, and the J2EE architecture in general, are meant to solve a particular class of problems. If your application naturally separates into standard layers (persistence, domain objects, business logic, presentation), you should consider using EJBs.

Implementation

A proper J2EE application takes time to develop. A typical EJB consists of at least four files (home, remote, implementation, and deployment descriptor), so even a small application requires some work before it can run. If you are prototyping an application, consider using only JavaServer Pages (JSPs) and servlets, and then refactoring and expanding that code to include EJBs.

Performance

Application servers are meant to run applications that need scalability. The services that the server provides (i.e., transaction management and instance and connection pooling) are very useful for writing scalable applications, but they also take up a good number of computer resources. If your application does not use these services to its advantage, EJBs might actually slow down your application by, for instance, unnecessarily caching objects, or checking security descriptors.

In general, deciding whether EJBs are the right choice for your application comes from experience. Knowing exactly what you will gain and what you will lose by using EJBs will also help you make the right decision.

2.1.2 Use Standard Design Architecture

As I mentioned earlier, it is usually a good idea to design most of the application before implementing it. This is especially true of J2EE applications, which regularly contain many different components .

Even though every developer or system architect has a unique approach to application design, most people follow some general principles. The first of these principles is the layered structure of a J2EE application:

Presentation layer

This is the UI of the application. It usually contains servlets, JSP files, applets, and various presentation and display logic. This layer is considered to be a client of the business logic layer because it exclusively uses that layer to complete its operations.

Business logic layer

This is the most important layer of the application, at least from the perspective of an EJB programmer. This layer contains the business workflow and various services used by the client. It relies on the persistence layer for storing and retrieving data.

Persistence layer

This layer is obviously used to persist application data. Most of the code here will comprise entity beans, and possibly some other layers of persistence abstraction, such as data access objects (which abstract the source of the data).

These layers are by no means set in stone. You might encounter a situation in which adding an additional logical layer will make the application design cleaner and easier to implement. Or you might find that you don't need a presentation layer if your application is used by another application. In any case, the layout of an application is flexible, but there are some definite advantages to using this three-layer structure, given that the J2EE specification encourages it by classloader schemes and packaging rules. Also, different types of components that can be built in J2EE (servlets, entity beans, session beans, etc.) lend themselves to this type of structure.

The second principle of design has to do with the order in which the application layers are developed. Even though every programmer has his own philosophy and way of developing an application, you should follow these rules if you follow the layout described earlier:

  1. Define requirements and use cases. This will help you understand what the application has to do and how flexible it must be, and it might help you decide which technologies to use.

  2. Clearly define the domain object model (i.e., your data objects) and business interfaces that will be exposed to the clients .

  3. Possibly write stubs for various components so that development can start.

  4. Implement the persistence layer.

  5. Define and write services , which are independent components of the system that are used in the implementation.

  6. Implement the business logic layer.

  7. Implement the presentation layer.

Writing functional prototype applications is almost as involved as writing a full application. You have to define and partially implement most of the components if your strategy will extend the prototype into a proper application. For this reason, design patterns similar to business delegates are commonly used (see Section 2.2.9), and simple implementations of these can be used in place of EJB components and layers.

2.1.3 Use CMP Entity Beans

Whenever possible, try to use container-managed persistence (CMP) for entity beans. Most application servers have highly optimized handling mechanisms for CMP beans, and even though CMP beans might be a little harder to configure and deploy properly, they are well worth the effort. Some of the benefits of CMP are:

  • Better transaction management

  • Configurable database layout

  • No SQL or persistence logic in source code

  • Container-managed relationships between entity beans

2.1.4 Use Design Patterns

Learn and use as many EJB design patterns as possible. Most patterns will save you development time, improve the performance of your application, and make it more maintainable . It's fair to say that without patterns, writing solid J2EE applications would be very hard.

Because this is not a design patterns book, we will not examine in detail the multitude of EJB patterns that exist out there. Instead, we'll focus on several patterns that most EJB developers will find useful in their work.

2.1.4.1 Session fa §ade

A session fa §ade is the most frequently used EJB design pattern. It's a way to encapsulate business workflow logic to get better performance and to have more maintainable code. The basic idea is very simple: put all business workflow logic into stateless session beans, and have clients call those beans instead of calling the different components of the application. This concept is shown in Figure 2-1.

Figure 2-1. Session fa §ade pattern
figs/jebp_0201.gif

There are many advantages to this pattern. The most significant is that moving all business logic into its own layer makes the code a lot cleaner and more manageable. Because each workflow operation corresponds to one business method in the session bean, all implementation logic for that operation is executed under one transaction. This means you need to set the transaction attributes for the session bean methods to "Required" for this aspect of the fa §ade to work correctly.

Having session fa §ades will also enable you to use local interfaces in the persistence layer, and expose only the remote session bean interface to the client.

2.1.4.2 Value objects

Value objects , or data transfer objects, are a way to transfer "bulk" data between remote components, with minimal network traffic. For example, suppose you have a User entity bean. To get the user's first name, last name , address, and other data, you would usually have to call a get method for each piece of data that you need. If you have to do this through a remote interface, the network overhead will be very large. The natural solution to this problem is to create an object that can hold all the data you need, and use that object to transfer the data. This is exactly what a value object is. Figure 2-2 illustrates this pattern.

Figure 2-2. Value object pattern
figs/jebp_0202.gif

A common practice is to use the value object in the entity bean, instead of constructing it every time a client requests it. Another common practice is to expose several different value objects from a single entity bean so that clients can get only the data they are interested in. This is ordinarily used when the entity bean contains large amounts of data, and sending everything over the network becomes impractical .

When the number of value objects is very large and their management becomes tedious , it might be a good idea to implement a generic HashMap value object that can be used to transfer arbitrary data. Now, a generic value object would have only a couple of getField / setField methods, and it would be hard to implement some kind of validation code to ensure that the right value object fields are being set. In contrast, a simple value object has getXXX / setXXX methods for each field, which makes it impossible to make that mistake. A compromise is to implement all value objects as interfaces, and then use a DynamicProxy with a HashMap to store the value object fields. Example 2-1 shows a dynamic proxy implementation, and how it's used in an entity bean.

Example 2-1. Use of a dynamic proxy implementation in an entity bean
 public class ValueObjectProxy implements InvocationHandler, Serializable {    protected HashMap fieldMap;    protected Class valueObjectClass;        protected ValueObjectProxy (Class valueObjectClass) {           this.valueObjectClass = valueObjectClass;           fieldMap = new HashMap(  );    }        public static Object createValueObject (Class valueObjectClass) {           return Proxy.newProxyInstance (                  valueObjectClass.getClassLoader(  ),                  new Class[  ] {valueObjectClass},                  new ValueObjectProxy(valueObjectClass));    }        public Object invoke (Object proxy, Method method, Object[  ] args)    throws Exception {           String methodName = method.getName(  );               if (methodName.startsWith ("get")) {                  // Remove "get" to get the field name.                  String fieldName = methodName.substring(3);                      // It's a get, so return the value.                  if (!fieldMap.containsKey ("fieldName"))                         throw new ValueObjectException ("Field " + fieldName                                                         + " does not exist");                  return fieldMap.get(fieldName);               } else if (methodName.startsWith ("set")) {                  // Remove "set" to get the field name.                  String fieldName = methodName.substring(3);                      // Put it into the hashmap.                  // Assume we received one argument in the set method.                  fieldMap.put (fieldName, args[0]);               // It's neither a get nor a set.           } else {                  throw ValueObjectException ("Invalid method");           }    } }     public SomeBean implements EntityBean {    // Skipping irrelevant methods . . .         public SomeValueObject getValueObject(  )    {           // Create the value object.           SomeValueObject vo = (SomeValueObject)                  ValueObjectProxy.createValueObject (SomeValueObject.class);               // Set its values.           vo.setName ("John Smith");           vo.setAddress ("140 Maple Drive");               return vo;    } } 

Because local interfaces are implemented in EJB 2.0, there is really no need to expose entity beans with remote interfaces. However, you still need to handle domain objects, such as the User object in the example, whether the entity bean is directly available to the client or not. So, in this case, you still have to use value objects in to transfer this data between application layers.

I l @ ve RuBoard


The OReilly Java Authors - JavaT Enterprise Best Practices
The OReilly Java Authors - JavaT Enterprise Best Practices
ISBN: N/A
EAN: N/A
Year: 2002
Pages: 96

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net