CI Tools and Best Practices in the Cloud

Continuous Integration

Subscribe to Continuous Integration: eMailAlertsEmail Alerts newslettersWeekly Newsletters
Get Continuous Integration: homepageHomepage mobileMobile rssRSS facebookFacebook twitterTwitter linkedinLinkedIn

Continuous Integration Authors: Jason Bloomberg, Yeshim Deniz, Elizabeth White, Pat Romanski, Liz McMillan

Related Topics: Java EE Journal, Java Developer Magazine, Continuous Integration

J2EE Journal: Article

Setting Up a Java Shop: How To Build Better Software Faster

Basic infrastructure: Utility Classes, Standards and Conventions, Build and Quality Control Tools

Three times in recent years I've joined an organization that was relatively new to Java development and missing some basic infrastructure elements that I'd relied on in previous development efforts. These elements include utility classes, standards and conventions, and build and quality control tools that help you produce a higher quality product with less risk. If you're involved in a development effort, whether it's new or ongoing, that's lacking any of these elements, you should consider incorporating them into your project infrastructure.

Nuts and Bolts
Some common utility software components should be incorporated into your development efforts as early as possible, because delaying their introduction may result in the proliferation of differing approaches that will need to be reworked later.

Configuration Settings
Access configuration settings via wrappers that hide the settings' underlying storage mechanism. There are numerous places where you can define configuration settings, including properties files, XML files, the database, and via the JDK's preferences package (which on Windows stores preferences to the registry, and to the file system on Unix). If your code uses direct calls to these mechanisms and future needs require that you either change which mechanisms are used or add functionality to those mechanisms, you'll need to make changes everywhere the mechanisms are referenced.

For example, suppose developers store configuration settings in properties files and load and access the settings via calls to the Properties class sprinkled throughout their code. If sometime later you find that changes made to the configuration settings need to be reflected in the application while the application is running, you'll need to change the code that loads those properties to support reloading them. If the settings that need to be reloaded aren't all loaded by the same code - for example, some are UI settings loaded by UI code and others are network settings loaded by network code - you'll need to make the same types of changes in multiple places.

You might also need to change the underlying storage mechanism. For example, a new customer might be database-centric and used to administering configuration settings in database tables and insist that your settings be administered the same way. If you're reusing a code base that has references to the Properties class throughout the code, you'll have to make a lot of changes to accommodate the new customer.

You can roll your own configuration settings classes or harvest them from the Internet. If you can incorporate open source into your product, take a look at the Jakarta Commons Configuration package. If you need or prefer to roll your own, you could start with a simple factory+interface approach as in:

public class ConfigFactory {
public static ConfigFactory getInstance() {...}
public Config getConfig( ) {...};

public interface Config {
public int getInt( String settingName );
public long getLong( String settingName );

You would then implement the Config interface once for each settings repository that you use, as in a ConfigProperties implementation, a ConfigXML implementation, etc.

If you don't have a logging package in place very early in your coding efforts, you can easily find yourself with a hodgepodge of logging approaches that make error investigation far more difficult than it should be. I've joined a number of large in-progress development efforts where almost every subsystem had its own custom logging package with numerous log files scattered in various directories, and log messages and message timestamps with varying formats. Consequently, one of the first hurdles in investigating a problem becomes determining, and locating, which log files may contain messages related to the problem. Then, if messages of interest are in multiple files, you may need to collate them into a chronological sequence, possibly reconciling different timestamp formats to do so.

Your choice for logging should be between using the JDK logging APIs and Log4j, unless you have specific logging needs that can't be addressed by either package. The March 2005 issue of JDJ contained an excellent article, "Log4j vs java.util.logging," by Joe McNamara that can help you in your decision.

If you're developing J2EE applications, an additional factor in your decision should be how easily your log messages can be directed to the application server's logging console and files. Many application server administration UIs have capabilities for displaying and filtering log messages, so if you can direct your messages to the application server's log message store, you can capitalize on those capabilities. In addition, having your log messages automatically collated with the application server's log messages may aid your problem investigation. For example, suppose your application fails because a resource pool in the application server was exhausted, but the error messages reported by your application contain insufficient detail to determine the cause. Having your messages in the application server log right after an application server message reports the exhaustion saves you considerable time in understanding the problem.

If you need to support more than one logging mechanism, consider using the Jakarta Commons logging package, which provides a common logging API under which you can plug in JDK logging, Log4j, or a custom logger. However, realize that if you use this common API, you will be unable to access some features of the underlying implementation, as is explained at by Ceki Gülcü, a key contributor to Log4j.

Exception Handling
Establish your exception handling approach early to ensure that you have mechanisms in place for the consistent and complete reporting and handling of errors. Decide on the project's philosophy regarding checked and unchecked exceptions - should checked exceptions be wrapped in unchecked exceptions? Your initial reaction might be "Why is this even an issue, since it defeats the point of having checked exceptions?" Well, a number of luminaries in the Java field, such as Bruce Eckel, advocate wrapping checked exceptions in unchecked exceptions (see One argument for doing so is that many developers don't really know what to do when a checked exception occurs. Because they're forced (by the compiler) to either catch it or declare it in their method's throws clause, they commit sins such as catching but not rethrowing it, which can make a problem investigation more difficult. (See Joshua Bloch's book Effective Java for a more extensive discussion on why consuming exceptions is bad practice.)

More Stories By Glen Cordrey

Glen Cordrey is an architect and developer of J2ME and J2EE applications. He works in the Washington, D.C. area and has been working with Java for six years.

Comments (1)

Share your thoughts on this story.

Add your comment
You must be signed in to add a comment. Sign-in | Register

In accordance with our Comment Policy, we encourage comments that are on topic, relevant and to-the-point. We will remove comments that include profanity, personal attacks, racial slurs, threats of violence, or other inappropriate material that violates our Terms and Conditions, and will block users who make repeated violations. We ask all readers to expect diversity of opinion and to treat one another with dignity and respect.