BUY THIS BOOK
This print book is out of stock, with no immediate plans to reprint.

Safari Books Online

What is this?


Looking to Reprint this content?


Java Enterprise Best Practices
Java Enterprise Best Practices By The O'Reilly Java Authors
Edited by  Robert Eckstein
December 2002
Pages: 288

Cover | Table of Contents | Colophon


Table of Contents

Chapter 1: Introduction to Java Enterprise Best Practices
Robert Eckstein
Ever since Java programmers have downloaded their first virtual machine, their ears have been glued to the ground, constantly on the lookout for tips and tricks for using the latest Java APIs. After all, there's nothing quite as satisfying as grasping a new technique for solving a common programming problem. Remember the first time you learned the power of Model-View-Controller (MVC), or developed your first singleton class? It was clear that someone out there had thought through the same problems you were having and, best of all, developed a solution that worked.
However, as any Java programmer can tell you now, learning tips and tricks for the Java APIs isn't as easy anymore. Java has grown in the past seven years to include a ghastly number of APIs, classes, and methods. In fact, Java is so big that it is now separated into three distinct areas: the Java 2 Standard Edition (J2SE), the Java 2 Enterprise Edition (J2EE), and the Java 2 Micro Edition (J2ME). And each area now has an enormous range of classes and methods available from which to choose. Quite frankly, it's nearly impossible to become an expert in all areas of 21st-century Java.
That being said, programmers discover a number of lessons after using the Java APIs for a while. At O'Reilly, we like to call these lessons "best practices." Best practices come in many flavors. Some recommend that you always use a specific design, while others advise you to avoid a particular class or method. Still others illustrate that design and implementation choices are often not black and white, but instead shades of gray. Best practices help you decide which strategies and approaches are right for you by illustrating the pros and cons of each side.
This book focuses on the J2EE APIs. The J2EE APIs include such alphabet-soup acronyms as EJB, JDBC, RMI, XML, and JMX. Because the J2EE is the most popular area of Java right now, it seems logical that we put together a volume of experience that programmers like you can learn from. However, we have not limited this book exclusively to J2EE. This book is a companion to
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
How Does a Best Practice Come About?
Slowly, and with experience. But let's take a step back first and look at how anyone becomes an expert in a specific environment. A programmer goes through four steps when learning to program with any modern language, including Java:
  1. You learn the syntax of the language, usually through a tutorial of some sort. In the case of Java, you quickly learned, for example, that, unlike with C++, there was no "delete" keyword for memory deallocation. The garbage collector took care of that automatically. You also learned that the Java language designers included a "synchronized" keyword to help you avoid common threading issues.
  2. You learn the environment that you're programming toward. Is it on a 2 GHz PC, or an embedded controller with limited memory on a cell phone? Are you targeting a PDA with access to a business network? Are you compiling toward a supercomputer Internet server that must handle millions of connections per day? Perhaps it's only one of the above. Perhaps all.
  3. You learn how to use one or more specialized libraries and APIs with the language. Often, this involves a more direct tutorial or reference book. For example, a good many of you learned how to use the servlet API by reading one of our books, Java Servlet Programming. Or perhaps you learned from some other book, or even from an article on the Internet.
  4. You slowly begin to gain experience, gleaning tips and tricks for using both the language and the APIs in the defined environment. More precisely, you learn—from your own or others' mistakes—that there are things you should always do, things you should consider doing only under specific circumstances, and things you should never do, even if the documentation says it's OK.
As we hinted earlier, the exclusive province of this book is the fourth area, and it pinpoints the J2EE APIs. This book compresses advice from nearly all of O'Reilly's Java Enterprise authors, each of whom has gained a wealth of experience, not only while writing his book, but also while interacting with programmers like you since their publication. Some of these tips will surprise you; some you might have already learned yourself. But we think you'll agree that
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Can Best Practices Be Arguable?
Absolutely. As I've frequently scribbled on early drafts of these chapters, the term "best practice" implies that there is a "not-so-best practice" that should be avoided. However, you might disagree. It could be that you've found something that works well for you that was in fact discouraged by one of our authors. Or maybe you have something to add. Perhaps you've even found a better solution and you'd like to share it.
With that in mind, we certainly don't want this compendium of advice to degenerate into a stale set of obsolete guidelines. We actively seek and encourage your comments! Hence, we've set up a discussion forum for these books on the O'Reilly Network web site, which is located at:
http://www.oreillynet.com
Here, you can discuss with others (and occasionally with me and even the authors) what works best or worst for you and in which environments.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
What's in This Book?
We've tried to cover as many useful J2EE APIs as possible. That being said, we haven't included all of them, sometimes because we felt that the API isn't in widespread use, and sometimes because there just wasn't much to say about it. However, the majority of the central J2EE APIs are represented in this book.
This book consists of 10 additional chapters:
EJB Best Practices by Sasha Nikolic, EJB author
Chapter 2 contains important information on how to effectively develop and deploy Enterprise JavaBeans (EJBs).
Servlet Best Practices by Jason Hunter, author of Java Servlet Programming
Chapter 3 has tips and tricks from one of O'Reilly's bestselling authors on how to efficiently work with servlets and frameworks.
JDBC Best Practices by George Reese, author of Database Programming with JDBC
Chapter 4 includes wisdom on configuring, storing, and retrieving information from various databases using the latest version of JDBC.
XML Best Practices by Brett McLaughlin, author of Java and XML and O'Reilly editor
Chapter 5 contains practical advice on structuring XML, as well as using both the SAX and DOM APIs. Brett also covers using the new JAXP APIs in some detail.
RMI Best Practices by William Grosso, author of Java RMI
Chapter 6 includes a plethora of tips for making sure you don't pull your hair out working with Java's Remote Method Invocation (RMI).
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
About the Practices Themselves
Once you start reading the chapters, you'll find that almost all the best practices start with a header that briefly summarizes the author's advice. For example, in Chapter 4, one of the headers is:
Do Not Rely on Built-in Key Generation
Following this summary in Chapter 4 is an introduction to the type of problem the author encountered that prompted this dilemma in the first place, and after that the author explains why he came to that conclusion. But more importantly, you'll find that each best practice documented in this book does more than state problems and solutions. They tend to shift your mode of thinking on using the APIs from the start. For instance, with the previous example, you might be tempted to use built-in key generation with your databases initially, then switch to a manual system later on. However, as this text demonstrates, this is often more trouble than it's worth and should be avoided at all costs. Of course, each practice originated with the author's personal experience, or experience learned from others since publication. In some cases, a recommendation might be obvious (e.g., "Always Close Your Database Connections"), but we've chosen to include it because it's so commonly executed incorrectly that it bears repeating.
Many of the best practices include examples that illustrate either correct or incorrect usage of the API. In these cases, we have occasionally omitted package names at the beginning of the code listing, as well as other elements that are not required to demonstrate the point of the best practice. We assume that you are already familiar with the APIs to the point at which this is not an issue. If, however, you want to download the complete examples, you can do so at the web site for this book (http://www.oreilly.com/catalog/javaebp).
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Enterprise Java Programming Resources Online
As I mentioned earlier, this book is not a tutorial for the individual J2EE APIs. However, you can find several excellent choices online if you need a place to start. In addition to the books listed earlier, many free sources of information about Java and J2EE programming are available.
Sun's official Java web site is http://java.sun.com, which can also be reached by the now deprecated http://www.javasoft.com. Another web site specifically for Java and J2EE developers is the Java Developer Connection: http://developer.java.sun.com. Most of the technical articles and beta software on this developer site is password-protected, and access to it requires registration. However, registration is free, and you can allow the site to automatically log in through the use of cookies.
Don't forget O'Reilly's Java web sites: http://java.oreilly.com and http://www.onjava.com. These sites contain links to our catalog of latest books, as well as insightful tips and tricks for every level of Java programmer. Some other useful sites that you can access are those for Javaworld magazine, at http://www.javaworld.com; JavaPro magazine, at http://www.javapro.com; and IBM developerWorks, at http://www.ibm.com/developerworks.
Finally, if you've just started with the J2EE and want to come up to speed quickly, you should probably be aware that several of the Enterprise APIs covered in this book are now part of the core Java 2 platform. Hence, if you have downloaded the Java Development Kit (JDK), you already have the classes for APIs such as JDBC, RMI, and parts of XML. Other APIs are standard extensions, however, so if you want to use, say, JSP or servlets, you have to download the classes separately. The best way to get the latest API information is to start on Sun's Products and APIs page at http://java.sun.com/products and find the appropriate API.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 2: EJB Best Practices
Sasha Nikolic
The Enterprise JavaBean (EJB) component model provides a very powerful platform for distributed enterprise computing. In fact, it is one of the most widely used enterprise platforms around. Because of this, an enormous amount of developer experience and practical knowledge has accumulated with EJBs. In this chapter, I'll present best practices for a range of EJB topics. Most of these topics cannot be covered completely in one chapter, so I'll focus on conventions and techniques that will enable you to write solid Java 2 Enterprise Edition (J2EE) applications.
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.
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.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Design
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.
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.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Implementation
Now, let's discuss some implementation best practices.
As I said before, letting clients access entity beans directly is a bad idea, and this is why session façades should be used as the intermediate layer between entity beans and the client. Because all (or most) of your entity beans will be called by session beans, it makes perfect sense to make these calls use local interfaces. So, if you made your entity beans expose local interfaces, you would eliminate all network calls occurring between business logic and persistence layers. On the other hand, the session beans making up the façade would still have remote interfaces, and clients would access them remotely, which is what you want.
Because the bean implementation class does not inherit from the bean interface, it's a fairly common error to get a mismatch in business method signatures between the implementation and the interface. Typically, you would have to package and deploy the EJBs to see the error. Needless to say, this can be very frustrating at times, especially 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 inherit from 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 beans. Namely, because remote bean interfaces must throw RemoteException, you are also forced to do this in your business interface. Also, a minor inconvenience is that all method parameters must be Serializable .
Example 2-2 shows the key interfaces for a remote bean.
Example 2-2. The order interfaces and implementation
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Deployment and Packaging
Finally, let's briefly look at some best practices for deployment and packaging of EJBs.
Having a build environment for your application is very important. Even if you use a sophisticated integrated development environment (IDE) for your development that can create EJB JARs and WAR files, a proper build environment will pay off in the long run.
The biggest benefit is that you will have total control over the structure of the produced files. It will also be very easy to produce WAR files, or a separate component, without having to run the IDE every time a change in the code is made. The most obvious benefit is that you won't have to depend on a particular IDE and its features for your builds.
A commonly used open source tool for making build environments is Ant. It's written in Java and is easily customizable for any task. Ant can effortlessly compile and package Java code, and make different J2EE archives. Writing Ant build files, which are XML files, if fairly simple, even for J2EE applications.
I won't go into the details of writing Ant build files because that is a very large topic, but you can find a lot of information about this process on the official Ant site at http://jakarta.apache.org/ant/index.html.
J2EE programmers usually tend to write one big application, with one JAR file containing all EJBs, because it is easy to develop this way. This is bad when it comes to maintenance of a deployed application because a bug fix in one EJB would mean a redeployment of the whole application.
It's not hard to see the benefits of packaging EJBs into related groups. Aside from easing redeployment, this also facilities maintenance of the source code and deployment descriptors. Reusing different parts of the system is also easier if you can split up and package the application into separate components.
Frequently, classes and interfaces are shared among components and layers of the system—usually domain objects, utility classes, and various service interfaces. These can easily be packaged into shared libraries and used by other components. We use a shared library by putting it into the main EAR file, and then referencing the library in the manifest file of each JAR file that needs to use it. Here is an example:
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 3: Servlet Best Practices
Jason Hunter
Since their introduction in 1996, servlets have dominated the server-side Java landscape and have become the standard way to interface Java to the Web. They are the foundation technology on which Java developers build web applications and, increasingly, web services. This chapter discusses best practices for servlet-based development and deployment.
We start with a look at servlet frameworks. Frameworks (e.g., Apache Struts) are becoming increasingly popular because they increase programmer efficiency by providing a skeleton on which applications can be built. In the first section, we examine what servlet frameworks offer, and I give a quick overview of the most popular frameworks. After that, we jump from the high level to the low level with a discussion on how using pre-encoded characters can optimize your servlet's performance. Next, we tackle the thorny issue of loading configuration files and provide some code to make the task easier, and after that I give some tips on when you should (or should not) use the HttpSession and SingleThreadModel features. As we near the end of the chapter, I explain how to reliably control caching to improve the user's experience. Then I address the frequently asked question: "How do I download a file to the client so that the client sees a `Save As' pop up?" As you'll see, the answer lies in setting the right HTTP headers.
When writing web applications, it's good to remember that servlets are an enabling technology. This is easy to forget because in the early days, the Servlet API was all we had for server-side Java web programming. If the Servlet API didn't include something, we had to build it ourselves. It was a little like the Old West, where times were tough and real programmers wrote servlets by hand. Specs weren't written yet. Heck, we felt lucky just to have out.println( ).
These days, times have changed. The crowds have come, and with them we see a multitude of servlet-based technologies designed to make web application development easier and more effective. The first area of innovation has been happening at the presentation layer. Technologies such as JavaServer Pages (JSP), WebMacro, and Velocity give us more productive alternatives to the vast fields of
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Working Effectively with Servlets
We start with a look at servlet frameworks. Frameworks (e.g., Apache Struts) are becoming increasingly popular because they increase programmer efficiency by providing a skeleton on which applications can be built. In the first section, we examine what servlet frameworks offer, and I give a quick overview of the most popular frameworks. After that, we jump from the high level to the low level with a discussion on how using pre-encoded characters can optimize your servlet's performance. Next, we tackle the thorny issue of loading configuration files and provide some code to make the task easier, and after that I give some tips on when you should (or should not) use the HttpSession and SingleThreadModel features. As we near the end of the chapter, I explain how to reliably control caching to improve the user's experience. Then I address the frequently asked question: "How do I download a file to the client so that the client sees a `Save As' pop up?" As you'll see, the answer lies in setting the right HTTP headers.
When writing web applications, it's good to remember that servlets are an enabling technology. This is easy to forget because in the early days, the Servlet API was all we had for server-side Java web programming. If the Servlet API didn't include something, we had to build it ourselves. It was a little like the Old West, where times were tough and real programmers wrote servlets by hand. Specs weren't written yet. Heck, we felt lucky just to have out.println( ).
These days, times have changed. The crowds have come, and with them we see a multitude of servlet-based technologies designed to make web application development easier and more effective. The first area of innovation has been happening at the presentation layer. Technologies such as JavaServer Pages (JSP), WebMacro, and Velocity give us more productive alternatives to the vast fields of out.println( ) that came before. These technologies make it easier than ever before to quickly develop, deploy, and maintain dynamic web content. You can find a full discussion of these and other templating technologies in my book
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Caching with Servlets
Here are some tips to consider that will help things move quickly with your servlets.
Pregeneration and caching of content can be key to providing your site visitors with a quality experience. With the right pregeneration and caching, web pages pop up rather than drag, and loads are reduced—sometimes dramatically—on the client, server, and network. In this section I'll provide advice for how best to pregenerate content and cache at the client, at the proxy, and at the server. By the end of this section you'll feel compelled to generate new content during request handling only in worst-case scenarios.
There's no need to dynamically regenerate content that doesn't change between requests. Yet such regeneration happens all the time because servlets and JSPs provide an easy way to template a site by pulling in headers, footers, and other content at runtime. Now this might sound like strange guidance in a chapter on servlets, but in many of these situations servlets aren't the best choice. It's better to "build" the content offline and serve it as static content. When the content changes, you can build the content again. Pull the content together once it is offline rather than during every request.
Take, for example, an online magazine, newspaper, or weblog ('blog). How do the pros handle templatization without burdening the server? By pregenerating the content. Articles added to a site are written and submitted in a standard format (often XML-based) which, when run through a build process, produces a comprehensive update to the web site. The build reformats the article into HTML, creates links to the article from other pages, adds the content into the search engine (before the HTML reformatting), and ultimately prepares the site to handle heavy loads without extreme resources. You can see this in action with 'blog tools such as MovableType. It's a Perl application, but it generates content statically, so Perl doesn't even need to run on the production server.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Other Servlet Tips
Here are some other things to keep in mind when working with servlets.
While we're on the subject of magic header incantations, servlet developers often struggle with finding the right header combination to send a browser a file that's intended for saving rather than viewing and thus triggers a "Save As" dialog. For the solution to this problem, I have some good news and some bad news.
The bad news is that although the HTTP specification provides a mechanism for file downloads (see HTTP/1.1, Section 19.5.1), many browsers second-guess the server's directives and do what they think is best rather than what they're told. These browsers—including Microsoft Internet Explorer and Opera—look at the file extension and "sniff" the incoming content. If they see HTML or image content, they inline-display the file contents instead of offering a Save As dialog. Turns out there's no 100% reliable way to download a file across all browsers. Perhaps, with this effort, programmers are more like alchemists than magicians, trying in vain to turn lead into gold.
The good news is that the right combination of headers will download files well enough to be practical. With these special headers set, a compliant browser will open a Save As dialog, while a noncompliant browser will open the dialog for all content except HTML or image files. For these types it will display the content inline, where a user can use the menu to save the content. Example 3-9 shows the best technique for sending files.
Example 3-9. Sending a file for download
// Set the headers.
res.setContentType("application/x-download");
res.setHeader("Content-Disposition", "attachment; filename=" + filename);
   
// Send the file.
OutputStream out = res.getOutputStream(  );
returnFile(filename, out);  // Shown earlier in the chapter
First, set the Content-Type header to a nonstandard value such as application/x-download. It's very important that this header is something unrecognized by browsers because browsers often try to do something special when they recognize the content type. Then set the
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 4: JDBC Best Practices
George Reese
The JDBC API is the ideal interface for database access, independent of the constraints of any particular database engine. In theory, you can take your JDBC application and deploy it on any operating system within any application server talking to any relational database. In reality, however, it's easy for a programmer to write seemingly database-independent JDBC code that results in wildly different behavior on different database engines. In this chapter, I have compiled a list of best practices that can help ensure both database independence and optimal performance of your JDBC code.
JDBC configuration has very little to do with programming, per se. Instead, JDBC configuration assists you in configuring your applications in their runtime environments. Through proper JDBC configuration, you can take advantage of many of the performance features of your database of choice without burdening your applications with proprietary code. Proper configuration provides your database engine of choice with all the information it needs to tailor itself to your application's needs.
Sun classifies JDBC drivers into four categories, as shown in Table 4-1.
Table 4-1: JDBC drivers
Driver
Description
Type 1
A bridge between JDBC and another database-independent API, such as ODBC. The JDBC-ODBC driver that comes with the Java SDK is the primary example of a Type 1 driver.
Type 2
Translates JDBC calls into native API calls provided by the database vendor.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Configuration
JDBC configuration has very little to do with programming, per se. Instead, JDBC configuration assists you in configuring your applications in their runtime environments. Through proper JDBC configuration, you can take advantage of many of the performance features of your database of choice without burdening your applications with proprietary code. Proper configuration provides your database engine of choice with all the information it needs to tailor itself to your application's needs.
Sun classifies JDBC drivers into four categories, as shown in Table 4-1.
Table 4-1: JDBC drivers
Driver
Description
Type 1
A bridge between JDBC and another database-independent API, such as ODBC. The JDBC-ODBC driver that comes with the Java SDK is the primary example of a Type 1 driver.
Type 2
Translates JDBC calls into native API calls provided by the database vendor.
Type 3
Network bridges that enable an application to take advantage of the WORA (write once, run anywhere) capabilities of Type 4 drivers, even when your database of choice supports only Type 2 drivers.
Type 4
Talks directly to a database using a network protocol. Because it makes no native calls, it can run on any Java Virtual Machine (JVM).
Most programmers learn JDBC using the JDBC-ODBC Bridge, which is a Type 1 JDBC driver. Nevertheless, the JDBC-ODBC Bridge is a
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Design
Design best practices tend to favor the creation of manageable database applications and rarely enhance performance. In fact, you might find that some of these best practices come with performance costs. Design, however, is never the place to second-guess performance issues. In any kind of programming, you should always put forth the best design first and optimize later.
The single most critical best practice in design is the proper separation of application and database logic through a generic persistence interface. Figure 4-1 shows an example of this separation.
Figure 4-1: The division of labor in database programming
Note that in this approach, database logic is never mixed with application logic. (Here, the person bean object is separate from the person data access object.) This division not only makes code easier to read and manage, but it makes it possible for your data model and application logic to vary without impacting one another.
The ideal approach involves encapsulating application logic in components often referred to as business objects and developing a pattern through which these components persist, without knowing anything about the underlying persistence mechanism. Figure 4-2 is a class diagram showing how this approach works for bean-managed Enterprise JavaBean (EJB) entity beans.
Figure 4-2: Entity bean persistence
The PersonBean entity bean contains no JDBC code or other database logic. Instead, it delegates all persistence operations to a generic persistence API. Underneath the covers, an implementation of that API performs the actual mapping of bean values to the database through the data access object. In fact, the implementation could persist to any entirely different data storage technology, such as an object database or directory service, without the entity bean being any wiser.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Code
In the previous section, I mentioned the principle of "design first and optimize later." Code is where optimization is realized. Most of the following coding best practices are aimed at improving database performance or getting around deficiencies in different JDBC drivers or database engines.
JDBC provides three kinds of statement classes: Statement, PreparedStatement, and CallableStatement. All too often, however, discussions of which kind of statement to use focus purely on performance. That's not to say that the choice of statement class doesn't impact performance. As a general rule, CallableStatement instances based on database-stored procedures provide the best performance, with PreparedStatement instances close behind. Finally, Statement instances generally perform significantly worse than the other kinds of statements. Focusing purely on performance, however, disguises two important facts:
  • The difference between CallableStatement and PreparedStatement is generally negligible.
  • There are nontrivial situations in which a Statement gives you optimal performance.
The primary difference in performance among the different statement types concerns how the SQL parsing occurs. With Statement-based calls, the driver sends the SQL to the database, which parses it every time you execute the statement. Calls through a PreparedStatement (as the name implies) are "prepared" before they are executed. In other words, the driver sends the SQL to the database for parsing when the statement is created but before it is executed. By the time you call execute( ), the statement has been preparsed by the database. And if you're truly lucky, the same SQL has already been executed, and no parsing even needs to occur. Finally, a
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
General Database
You can do only so much in Java and JDBC. In the end, your application is at the mercy of the database supporting it. Many best practices are limited to specific database engines. A solid best practice as a database architect is to become intimately familiar with the strengths and quirks of your database of choice. With that in mind, however, I will close this chapter by providing some general best practices for approaching any database engine.
The natural tendency in JDBC programming is to tweak your Java code. The truth is you will get the most bang for your buck in SQL optimizations. Small things such as indexing the columns in your WHERE clauses will do more for your application performance than anything you can do in Java. A good way to find out what is happening with your SQL code is to use your database engine's command-line utility and run the SQL through the EXPLAIN SELECT command.
The information the EXPLAIN SELECT command provides is database-dependent. Whatever your database, it should tell you some basic things about how it is trying to execute your query. Is the query utilizing indexes fully, or is it doing multiple table scans for what should be a simple query?
Databases are horrible places for binary data. The database engine ends up being a nasty middleman for pulling large chunks of data. Furthermore, it is not particularly optimized for the unique needs of binary data. Unfortunately, moving the data to the filesystem and maintaining pointers to the filesystem in the database puts data integrity at risk. What if someone deletes the file, but the record pointing to the file remains in the database?
For most applications, the data integrity issue is not a huge problem. Digital asset collections, however, can become unmanageable when you store the binary data on the filesystem. These specialized applications should instead use a digital asset management system to manage the binary data.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 5: XML Best Practices
Brett McLaughlin
It's almost impossible for programmers not to use XML in modern enterprise applications. In fact, programmers are finding it increasingly common to read and write XML, either from other components within the same application or from external sources such as a web service.
In this chapter we'll discuss several types of XML-based best practices. First, we'll discuss several ways you can better structure your XML, regardless of the API you choose to use. From there, we'll look at tips for using three significantly different XML APIs included with a Java 2 Enterprise Edition (J2EE) distribution. We'll also discuss how, in addition to good document authoring, it is important that your XML manipulation code be efficient and well-designed. This chapter examines several best practices that will get you on the right track to effective Java and XML programming, and keep you sleeping at night.
Today's Java programmers frequently see a wealth of tips and tricks on the Internet to improve their use of APIs such as SAX, DOM, and JAXP. While I'll address each of these in turn in the second part of this chapter, all the good coding in the world won't make up for poor document authoring. In this section I'll present a few ideas that can make your documents cleaner and less error-prone.
An entity reference (also called an entity declaration in some circles) is one of those topics in XML that seems a little obscure. However, just think of an entity reference as a variable in XML. That variable has a declared value, and every time the variable occurs, the parser substitutes that value in the XML output. In that regard, an entity reference is like a static final variable in Java in that it cannot alter its value from an initial value defined in a Document Type Definition (DTD).
An entity reference often refers to an online resource (you'll see examples of this later in the Section 5.2), but it can also have a value defined in a DTD, such as the following:
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
XML Authoring
Today's Java programmers frequently see a wealth of tips and tricks on the Internet to improve their use of APIs such as SAX, DOM, and JAXP. While I'll address each of these in turn in the second part of this chapter, all the good coding in the world won't make up for poor document authoring. In this section I'll present a few ideas that can make your documents cleaner and less error-prone.
An entity reference (also called an entity declaration in some circles) is one of those topics in XML that seems a little obscure. However, just think of an entity reference as a variable in XML. That variable has a declared value, and every time the variable occurs, the parser substitutes that value in the XML output. In that regard, an entity reference is like a static final variable in Java in that it cannot alter its value from an initial value defined in a Document Type Definition (DTD).
An entity reference often refers to an online resource (you'll see examples of this later in the Section 5.2), but it can also have a value defined in a DTD, such as the following:
<!ENTITY phoneNumber "800-775-7731">
Instead of typing the phone number for O'Reilly several times in your XML document, and possibly introducing typographical errors, you can just refer to the value through its reference:
<content>O'Reilly's phone number is &phoneNumber;.</content>
Of course, this seems pretty trivial, so let's look at a more realistic example. Example 5-1 shows a simple XML document fragment intended for display on a web page.
Example 5-1. Sample document without entity references
<page>
  <title>O'Reilly Java Enterprise Best Practices</title>
  <content type="html">
    <center><h1>O'Reilly Java Enterprise Best Practices</h1></center>
    <p>
      Welcome to the website for <i>O'Reilly Java Enterprise Best
      Practices</i>. This book was written by O'Reilly's Java
      authors for Java Enterprise professionals. And so on and
      so on, ad infinitum.
    </p>
  </content>
</page>
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
SAX
At the base of nearly all Java and XML APIs is SAX, the Simple API for XML. The first part of making good decisions with SAX is deciding whether to use SAX. Generally, alpha-geek types want to use SAX and nothing else, while everyone else avoids it like the plague. The mystique of using SAX and the complexity that makes it daunting are both poor reasons to decide for or against using SAX. Better criteria are presented in the following questions:
  • Am I only reading and not writing or outputting XML?
  • Is speed my primary concern (over usability, for example)?
  • Do I need to work with only portions of the input XML?
  • Are elements and attributes in the input XML independent (no one part of the document depends on or references another part of the document)?
If you can answer "yes" to all these questions, SAX is well-suited for your application. If you cannot, you might want to think about using DOM, as detailed later in this chapter.
When using the SAX API, all input begins with the org.xml.sax.InputSource class. This is a class that allows the specification of an input (e.g., a file or I/O stream), as well as a public and system ID. SAX then extracts this information from the InputSource at parse time and is able to resolve external entities and other document source-specific resources.
In fact, SAX uses the InputSource class even when you do not. Consider the code fragment in Example 5-6, which uses JAXP to initiate a SAX parse.
Example 5-6. Using JAXP to initiate a SAX parse
import java.io.*;
import java.xml.parsers.*;
   
File myFile = ...
DefaultHandler myHandler = ...
   
SAXParserFactory spf = SAXParserFactory.newInstance(  );
SAXParser parser = spf.newSAXParser(  );
   
parser.parse(myFile, myHandler);
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
DOM
DOM, the Document Object Model, is a far better understood API than SAX. This is largely because it operates using more familiar Java principles: the XML input document is represented as a set of Java objects, output is performed via DOM serializers, and the ability to make significant programming errors is greatly lessened compared to SAX. However, DOM still presents more than its fair share of pitfalls to the unprepared developer.
When deciding to use DOM, you should always begin by first determining if you can use SAX. While SAX programming is generally more complex than DOM programming, it is almost always faster. However, if you were unable to answer "yes" to all the questions in the Section 5.2 , DOM might be a better solution for you.
In particular, there are two things that DOM excels at:
  • Providing an object model of an XML document
  • Providing access to all parts of an XML document at one time
These two aspects of DOM are interesting in that they both are significantly appealing to Java developers. On the whole, today's developers prefer using an object-oriented programming model and having an entire business unit (whether it be an XML document or some other construct) available for random access at all times. SAX forces a more procedural and generally unfamiliar programming model, while DOM's model seems more natural.
Of course, you pay performance and memory penalties for these features—keeping an entire document in memory and representing that document as objects expends both time and resources. That being said, DOM can be very powerful once you learn to account for its shortcomings. The following tips can help you use DOM as effectively as possible, decreasing performance penalties when possible.
One of the most misunderstood and abused aspects of using DOM is getting an initial DOM implementation for programming. This is typically referred to as
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
JAXP
The next API on the list is one which readers should realize is not a parser, or even an API for parsing XML. JAXP is the Java API for XML Processing and is simply an abstraction layer, a thin shim that sits on top of the SAX and DOM APIs. JAXP performs no XML parsing itself, but instead defers this task to the underlying SAX and DOM APIs. The same thing is true for JAXP's XML transformation processing capabilities.
You should always attempt to use JAXP in a J2EE application. With the release of JAXP 1.1 and support for SAX 2.0 and DOM Level 2, JAXP provides the baseline tool support required for solid Java and XML programming. You'll be able to migrate applications more easily and change parser and processor vendors at will—with minimal impact on your applications. JAXP also has shown no adverse performance effects, so there is no reason to avoid using JAXP.
At times, you will decide you need to use vendor-specific extensions to a parser or processor. In these cases, JAXP will obviously not suffice. However, I still recommend using JAXP, except in the specific portions of your code that reference these vendor-specific features.
Here, we will discuss a core feature of JAXP that is underused: conversion from one API format (SAX, a stream, or DOM) to another. While this has always been one of the basic features of JAXP, it is rarely used, probably due to a lack of understanding of JAXP's Transformation API for XML, or TRaX.
An example is the best way to illustrate this sort of format transformation. Example 5-17 shows a helper class that will perform these conversions for you, so you don't have to constantly deal with new Transformer instances and the JAXP TransformerFactory .
Example 5-17. Format conversion helper class
package com.oreilly.xml;
   
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.sax.SAXSource;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
   
public class FormatConverter {
   
    private static boolean initialized = false;
   
    private static Transformer transformer;
   
    private static void initialize(  ) throws TransformerException {
        TransformerFactory factory = TransformerFactory.newInstance(  );
        transformer = factory.newTransformer(  );
        initialized = true;
    }
   
    public static void convert(StreamSource source, SAXResult result) 
        throws TransformerException {
   
        transformer.transform(source, result);
    }
   
    public static void convert(StreamSource source, DOMResult result) 
        throws TransformerException {
   
        transformer.transform(source, result);
    }
   
    public static void convert(SAXSource source, DOMResult result) 
        throws TransformerException {
   
        transformer.transform(source, result);
    }
   
    public static void convert(SAXSource source, StreamResult result) 
        throws TransformerException {
   
        transformer.transform(source, result);
    }
   
    public static void convert(DOMSource source, StreamResult result) 
        throws TransformerException {
   
        transformer.transform(source, result);
    }
   
    public static void convert(DOMSource source, SAXResult result) 
        throws TransformerException {
   
        transformer.transform(source, result);
    }
    static {initialize();}
}
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 6: RMI Best Practices
William Grosso
Java's Remote Method Invocation (RMI) framework is a powerful, easy-to-use, and robust framework for building distributed applications. It's ideal for a wide variety of mid-range applications that don't fit into the Enterprise JavaBean (EJB) model, don't require the cross-language capabilities of either CORBA or web services, and don't use a web browser for a client.
RMI's ease of use is legendary. But ease of use gets you only so far. In this chapter, I will outline a number of best practices that will enable you to take an ordinary RMI application and turn it into one that performs well, is easy to maintain, and will be useful for years to come.
Because of space considerations, I've chosen to focus on three basic areas: marshalling and unmarshalling objects, making applications more robust, and improving application performance.
Marshalling is a generic term for gathering data from one process and converting it into a format that can be used either for storage or for transmission to another process (correspondingly, unmarshalling involves taking the converted data and recreating the objects). In RMI, marshalling is done either via serialization or externalization. Marshalling and unmarshalling occupy a strange role in designing a distributed application. On the one hand, the means by which you perform marshalling and unmarshalling is a technical detail: once you've decided to send information to another process, how you do so shouldn't be a primary design consideration. On the other hand, it's a very important technical detail, and the way you do it can often make or break an application.
Value objects are objects that contain data and very little behavior, aside from a few constructors that are convenient. They are encapsulations of information intended solely for communication between processes (they are more like structs in C or C++ than full-fledged objects). The idea behind using value objects is that by specifying remote interfaces, and then using data objects that play no further computational role, you separate the protocol definition (e.g., how the processes communicate) from the computational class structures (e.g., the objects and classes that the client or server needs to use to function effectively).
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Marshalling and Unmarshalling Objects
Marshalling is a generic term for gathering data from one process and converting it into a format that can be used either for storage or for transmission to another process (correspondingly, unmarshalling involves taking the converted data and recreating the objects). In RMI, marshalling is done either via serialization or externalization. Marshalling and unmarshalling occupy a strange role in designing a distributed application. On the one hand, the means by which you perform marshalling and unmarshalling is a technical detail: once you've decided to send information to another process, how you do so shouldn't be a primary design consideration. On the other hand, it's a very important technical detail, and the way you do it can often make or break an application.
Value objects are objects that contain data and very little behavior, aside from a few constructors that are convenient. They are encapsulations of information intended solely for communication between processes (they are more like structs in C or C++ than full-fledged objects). The idea behind using value objects is that by specifying remote interfaces, and then using data objects that play no further computational role, you separate the protocol definition (e.g., how the processes communicate) from the computational class structures (e.g., the objects and classes that the client or server needs to use to function effectively).
Building separate objects for data transmission might seem oppositional to standard object-oriented practices. And, to some extent, it is. But it's not as contrary as you might think. Consider writing a stock-trading application. Your stock-trading application probably has an idea for a purchase order. But it's not a single class—each part of the application deals with different aspects of the purchase order:
  • The client wants to help the customer enter data and verify the purchase order.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Making Applications More Robust
The first set of practices in this chapter dealt with how to encode objects that will be sent to another process. This section is very different; it contains practices for making an application more robust. The practices in this section aren't really about "design" in the classic sense. Nothing in these practices will help you determine the object composition for your business logic or write a better remote interface. Instead, they mostly deal with two related topics: connection maintenance and failure handling.
Connection maintenance refers to practices that make sure the programs in a distributed application can connect with each other and send method calls. Failure handling refers to practices that enable an application to recover as gracefully as possible from a connection failure; you might think there's not a lot you can do when an application crashes (or starts performing badly), but there are a few simple practices that will help you diagnose problems and provide end users with a better experience.
Everyone knows that networks fail. Failures can range from small-scale and transient to massive and persistent. Obviously, in the case of massive and persistent network failures, a distributed application will not work. But your application can be built to survive small-scale and transient network failures.
One of the best things you can do to make your application more robust is implement a retry strategy. That is, whenever you make a remote call, wrap it in a loop based on catching RemoteException , as in the following code snippet:
public vo