Java Enterprise Best Practices
Trang 1Expert Tips & Tricks for Java Enterprise Programmers
Enterprise
Best Practices
TM
Trang 3Application design is the first step in J2EE application development,as any text onthe topic will attest The reason for this is simple: changing the design is usually muchmore 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
Know When to Use EJBs
Even though EJBs are great,they are not always the right solution to the problem athand 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 thefollowing basic guidelines:
Design
The EJB component model,and the J2EE architecture in general,are meant tosolve a particular class of problems If your application naturally separates intostandard layers (persistence,domain objects,business logic,presentation),youshould consider using EJBs
Implementation
A proper J2EE application takes time to develop A typical EJB consists of atleast four files (home,remote,implementation,and deployment descriptor),so
Trang 4even a small application requires some work before it can run If you are typing an application,consider using only JavaServer Pages (JSPs) and servlets,and then refactoring and expanding that code to include EJBs.
proto-Performance
Application servers are meant to run applications that need scalability The vices that the server provides (i.e.,transaction management and instance andconnection pooling) are very useful for writing scalable applications,but they alsotake up a good number of computer resources If your application does not usethese services to its advantage,EJBs might actually slow down your application
ser-by, for instance, unnecessarily caching objects, or checking security descriptors
In general,deciding whether EJBs are the right choice for your application comesfrom experience Knowing exactly what you will gain and what you will lose by usingEJBs will also help you make the right decision
Use Standard Design Architecture
As I mentioned earlier,it is usually a good idea to design most of the applicationbefore implementing it This is especially true of J2EE applications,which regularlycontain many different components
Even though every developer or system architect has a unique approach to tion design,most people follow some general principles The first of these principles
applica-is the layered structure of a J2EE application:
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 variousservices used by the client It relies on the persistence layer for storing andretrieving data
Persistence layer
This layer is obviously used to persist application data Most of the code herewill comprise entity beans,and possibly some other layers of persistence abstrac-tion, 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 whichadding 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 yourapplication is used by another application In any case,the layout of an application isflexible,but there are some definite advantages to using this three-layer structure,
Trang 5Design | 9
given that the J2EE specification encourages it by classloader schemes and ing 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
packag-The second principle of design has to do with the order in which the application ers are developed Even though every programmer has his own philosophy and way
lay-of developing an application,you should follow these rules if you follow the layoutdescribed earlier:
1 Define requirements and use cases This will help you understand what theapplication has to do and how flexible it must be,and it might help you decidewhich technologies to use
2 Clearly define the domain object model (i.e.,your data objects) and businessinterfaces 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
busi-ness delegates are commonly used (see “Use Busibusi-ness Delegates for
Clients”),and simple implementations of these can be used in place of
EJB components and layers.
Use CMP Entity Beans
Whenever possible,try to use container-managed persistence (CMP) for entitybeans Most application servers have highly optimized handling mechanisms forCMP beans,and even though CMP beans might be a little harder to configure anddeploy 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
Trang 6Use Design Patterns
Learn and use as many EJB design patterns as possible Most patterns will save youdevelopment time,improve the performance of your application,and make it moremaintainable It’s fair to say that without patterns,writing solid J2EE applicationswould be very hard
Because this is not a design patterns book,we will not examine in detail the tude of EJB patterns that exist out there Instead,we’ll focus on several patterns thatmost EJB developers will find useful in their work
multi-Session façade
A session façade is the most frequently used EJB design pattern It’s a way to
encap-sulate business workflow logic to get better performance and to have more able code The basic idea is very simple: put all business workflow logic into statelesssession beans,and have clients call those beans instead of calling the different com-ponents of the application This concept is shown in Figure 2-1
maintain-Figure 2-1 Session façade pattern
SessionFacade FirstHome FirstRemote SecondHome SecondRemote
findByPrimaryKey() create() method1() method2() method3()
Before:
Trang 7Design | 11
There are many advantages to this pattern The most significant is that moving allbusiness 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 sessionbean,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 persistencelayer, and expose only the remote session bean interface to the client
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
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 datayou 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
After:
Before:
Client BeanHome BeanRemote
findByPrimaryKey() getAddress() getZipCode() getCountry()
Client BeanHome BeanRemote
findByPrimaryKey() getValueObject()
Trang 8A common practice is to use the value object in the entity bean,instead of ing it every time a client requests it Another common practice is to expose severaldifferent value objects from a single entity bean so that clients can get only the datathey are interested in This is ordinarily used when the entity bean contains largeamounts of data, and sending everything over the network becomes impractical.When the number of value objects is very large and their management becomes
be used to transfer arbitrary data Now,a generic value object would have only a
of validation code to ensure that the right value object fields are being set In
impossible to make that mistake A compromise is to implement all value objects as
Example 2-1 shows a dynamic proxy implementation,and how it’s used in an entitybean
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) {
// 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")) {
Trang 9Implementation | 13
Because local interfaces are implemented in EJB 2.0,there is really no need to exposeentity beans with remote interfaces However,you still need to handle domain
available to the client or not So,in this case,you still have to use value objects in totransfer this data between application layers
Implementation
Now, let’s discuss some implementation best practices
Use Local Interfaces for Entity Beans
As I said before,letting clients access entity beans directly is a bad idea,and this iswhy session façades should be used as the intermediate layer between entity beansand the client Because all (or most) of your entity beans will be called by sessionbeans,it makes perfect sense to make these calls use local interfaces So,if you made
// 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.
// 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");
Trang 10your entity beans expose local interfaces,you would eliminate all network calls ring between business logic and persistence layers On the other hand,the sessionbeans making up the façade would still have remote interfaces,and clients wouldaccess them remotely, which is what you want.
occur-Use Business Interfaces
Because the bean implementation class does not inherit from the bean interface,it’s afairly common error to get a mismatch in business method signatures between theimplementation and the interface Typically,you would have to package and deploythe EJBs to see the error Needless to say,this can be very frustrating at times,espe-cially because most of these errors are simple typos or missed method parameters.One common practice is to use business interfaces to enforce compile-time checks
To do this,create a new interface that contains only business methods of your bean,and let both the remote/local bean interface and the implementation class inheritfrom it However,even though this method will work for all types of beans (CMP,BMP,local,or remote),there are some inconveniences when dealing with remote
also forced to do this in your business interface Also,a minor inconvenience is that
Example 2-2 shows the key interfaces for a remote bean
Example 2-2 The order interfaces and implementation
// Business interface
public interface Order
{
public int getQuantity( ) throws RemoteException;
public void setQuantity (int quantity) throws RemoteException;
public double getPricePerItem( ) throws RemoteException;
public void setPricePerItem (double price) throws RemoteException;
public double getTotalPrice( ) throws RemoteException;
Trang 11Implementation | 15
imple-mentation class This is not necessary because although you are allowed to overridemethods with definitions that have fewer exceptions,the opposite doesn’t work (i.e.,you can’t add new exceptions to a superclass method) Beans with local interfaceswould use a business interface in the same way,except that there are no
RemoteException andSerializable rules to follow
Now,you might be tempted to use a business interface instead of the real local/remoteinterface so that whenever you get an interface to a bean,you cast it to its businessinterface and use it as if it’s not an EJB but a standard Java class In general,this isusually a bad idea because an EJB exposes other methods and functionality to the cli-ent (create,remove,find,getHandle,getPrimaryKey,etc.) If you expose these meth-ods,there is no point in having a separate business interface because it would beidentical to the remote/local interface If you don’t expose these methods,you wouldstill have to perform a lot of extra EJB management (i.e.,handle remote exceptions,terminate sessions,etc.) If you need the client to work with simple Java classes,youcan write a separate class that internally handles all EJB details,and possibly exposesthe business interface to the client This is called a “business delegate,” and we’ll talkabout it later in the chapter So,to recap this discussion: it’s a bad idea to use busi-ness interfaces for anything other than compile-time syntax checking
private int quantity;
private double pricePerItem;
// Business interface implementation
public int getQuantity( ) {
Trang 12Handle Exceptions in EJB Code Correctly
Handling exceptions in a distributed J2EE environment can be confusing and verymessy at times Because most exceptions are never thrown in a properly debuggedapplication,you might tend to ignore them,or just print them out to see where theerror is Nevertheless,writing a robust application requires you to properly deal withall possible error conditions that might appear
To see how and where to handle various EJB exceptions,it’s useful to separate theminto three basic types:
RemoteException
This exception is declared in all remote interfaces exposed by an EJB It is meant
to be caught by the client of an EJB,and it usually indicates a network problem
A class implementing an EJB really cannot throw this type of exception If youneed to propagate a network problem (i.e.,call another remote object and
you’ll see next
EJBException and its subclasses
This exception is thrown by the developer in the EJB implementation class and
error,in which case the container will always do a rollback of the current
exception,and in most cases,it should never be caught by the developer To help
effectively wrapping another exception A common use of this is to rethrow an
SQLException by wrapping it into anEJBException
Application-level exceptions
Unlike the previous two types of exceptions,application-level exceptions areconsidered “normal,” as far as the container is concerned They are meant to beused in the spirit of standard Java exceptions to report various application errorssuch as: “user Bob is too old.” An EJB can declare and throw these exceptions,and the client will receive them just like it would any normal Java exception,butbecause these exceptions might potentially travel over the network (from the EJB
of application-level exceptions are the ones already predefined in the EJB
Know When to Use Compound Primary Keys
If you decide to write a compound primary key class for an entity bean,you must
Trang 13Implementation | 17
equals( )is important because the container uses these methods to compare primarykeys and to look up cached entity bean instances
bean lookups,especially if there are a lot of instantiated beans This happens because
perfor-mance of these structures relies on the fact thathashCode( )returns different values fordifferent objects
primary key contains However,there are a few generic algorithms that work well
method This algorithm simply adds all hashcodes of the primary key plying each intermediate result by 31 (so that it’s not a simple sum of hashcodes)
fields,multi-Example 2-3 Compound primary key
public class CompoundPK implements Serializable
{
private String str1;
private String str2;
private int int1;
private Date date1;
// Omitting irrelevant code here
public int hashCode( )
{
int hash = 0;
hash = hash * 31 + str1.hashCode( );
hash = hash * 31 + str2.hashCode( );
hash = hash * 31 + int1;
hash = hash * 31 + date1.hashCode( );
return hash;
}
public boolean equals (Object obj)
{
if (!(obj instanceof CompoundPK)) returns false;
CompoundPK other = (CompoundPK)obj;
return str1.equals (other.str1)
&& str2.equals (other.str2)
&& int1 = = other.int1
&& date1.equals (other.date1);
}
}