ONJava.com    
 Published on ONJava.com (http://www.onjava.com/)
 See this if you're having trouble printing code examples


Using the Jakarta Commons, Part 1

by Vikram Goyal
06/25/2003

The Jakarta Commons is a Jakarta subproject that creates and maintains independent packages unrelated to any other framework or product. The packages are a collection of components that serve small, useful purposes in their own right, and are usually server-centric.

The Commons project is divided into two parts: the Sandbox and the Commons repository. The Sandbox is a test bed for trying out ideas by the Jakarta committers. This article explains the components that make up the repository. It will show you when to use a component in each repository, where to get it, and how to use it with a basic example.

Introduction

Reusability is the name of the game for the Jakarta Commons project. Packages that form part of this project are conceived with the aim of making them reusable. Some of them, like the commons logging package, were developed for other projects, such as Jakarta Struts. When the committers saw how useful this package could be to other projects and realized that other packages could cut across project lines, they decided to form a "common" place for all such packages. This is the Jakarta Commons project.

Related Reading

Java Enterprise Best Practices
By The O'Reilly Java Authors

To be really reusable, each package needs to be independent of any other bigger framework or project. Thus, each package in the Commons project is largely independent, not only from other projects, but mostly of other packages as well. Deviations exist, but mostly to the extent of using well-set APIs. For example, the Betwixt package depends on the use of XML APIs. The primary aim though, is for these packages to work straight out of the box using a set of well-defined interfaces.

The brevity of most packages, however, has led to a brevity of documentation, poor maintenance, and lack of support. Some suffer from incorrect links and very sparse documentation. With most packages, you are left to figure out for yourself how to use them or, in some cases, why to use them. Hopefully this article will answer some of those questions.

Note: Jakarta Commons is different from Apache Commons. The latter is a top-level project of the Apache Software Foundation. The former is a subproject of the top-level Jakarta Project, and the subject of this article. Furthermore, Jakarta Commons is solely based on the Java language. In this article, whenever I say Commons, I am referring to Jakarta Commons.

Components

For organizational reasons, I have divided the 18 production-ready (I have excluded EL, Latka, and Jexl, for now) components of the Commons project into five categories. The table below lists these.

Component CategoryComponents
Web-related FileUpload, HTTPClient, and Net
XML-related Betwixt, Digester, Jelly, and JXPath
Utilities BeanUtils, Logging, DBCP, Pool, and Validator
Packages Codec and Modeler
Trivial CLI, Discovery, Lang, and Collections

Note that this organization is only for the purpose of this article. No such organization actually exists within the Commons project. The boundaries of these categories overlap to a certain degree. In this article, I will cover the Web-related and the Trivial categories; my next article will cover the XML-related and Packages categories. The final article will describe the components in the Utilities category.

Trivial

Source Code

Download commons1src.zip for the example applications.

The reason the CLI, Discovery, Lang, and Collections packages are categorized as Trivial is because they each serve a very small, yet very useful purpose.

1. CLI

Summary: CLI (Command Line Interface) provides a consistent interface for accessing and parsing the command-line parameters from within your Java program.

Where: Main Page, Binaries, Source.

When: When you want to use a consistent way of accessing and specifying command-line parameters.

Example Application: CLIDemo.java; needs commons-cli-1.0.jar in the CLASSPATH.

Description:

How many times have you written a Java application and had had to rewrite a new way of specifying the input parameters to your application? Wouldn't it be nice if there were one single interface to the way you define the input parameters (mandatory vs. numbers vs. Boolean, etc.), parse these parameters (according to a set of rules), interrogate, and decide the path that your application will take? CLI is the answer.

In CLI, each parameter that you want to specify on the command line is an Option. Create an Options object, add individual Option objects to it, then use the CLI-supplied methods to parse the user's input parameters. An Option might require the user to input a value as well; for example, if the name of a file is required. In such a case, the Option must be created where this is explicitly specified.

These are the steps towards using CLI:

  1. Create your Options:

    Options options = new Options();
    options.addOption("t", false, "current time");
  2. Create a Parser, and parse your input:

    CommandLineParser parser = new BasicParser();
    CommandLine cmd;
    try {
    	cmd = parser.parse(options, args); 
    } catch (ParseException pe) {
    	usage(options);
    	return;
    }
  3. Based on what the user has entered, take the relevant actions in your code:

    if (cmd.hasOption("n")) {
    	System.err.println("Nice to meet you: " + cmd.getOptionValue('n'));
    }

That is almost all there is to using CLI. Of course, there are other advanced options that give you control over various formats and parsers, but the basic idea remains the same. Look at the demo application for a complete example.

2. Discovery

Summary: An implementation of the discovery pattern, where you can use a consistent way of locating and instantiating your classes and other resources.

Where: Main Page, Binaries, Source. All code is in pre-release mode.

When: When you want to use best-practice algorithms for locating implementations of Java interfaces in your code.

Example Applications: DiscoveryDemo.java, MyInterface.java, MyImpl1.java, MyImpl2.java, MyInterface. Requires commons-discovery.jar and commons-logging.jar in the CLASSPATH.

Description:

Discovery is an attempt to locate all known implementations of an interface using best-practice algorithms. As a user of services, this is particularly useful in cases where you want to locate all known service providers for the service that you are trying to access.

Consider the case where you write an interface for a certain difficult task. All implementations of this interface would have code written in a unique way to achieve this difficult task. This would give the actual end user a variety of choices for actually doing this task. How would he know what implementations of your interface are available on his system?

The scenario that I have painted is the Service and Service Provider architecture. The Service is promised by your interface. The Service Providers provide the implementations of your service. The end user now needs to discover which Service Providers are actually installed. The Discovery component helps in doing this by a variety of means. Note that Discovery is not just used for discovering implementing classes, but also for locating resources, such as images and other files. In this it follows the rules set out in the Service Provider Architecture specified by Sun.

As such, it is really simple to use Discovery. See the example application, the associated MyInterface, and the Implementing classes MyImpl1 and MyImpl2 for details. You will also need the MyInterface file, which should be in the META-INF/services directory. Note that the name of this file corresponds to the fully qualified name of your interface. If your interface is in a package structure, the name of this file should change accordingly.

  1. Use the supplied ClassLoaders:

    ClassLoaders loaders =
    	ClassLoaders.getAppLoaders(MyInterface.class, getClass(), false);
  2. DiscoverClass is used to find our implementing classes:

    DiscoverClass discover = new DiscoverClass(loaders);
  3. Find the implementing class:

    Class implClass = discover.find(MyInterface.class);
    System.err.println("Implementing Provider: " + implClass.getName());

When you run the above code (DiscoveryDemo.java), you will get the class that you have registered in the MyInterface file, as shown below. Again, note that if your implementation is in a package structure, the name here should reflect that. If you don't have this file in the specified place, or if the name of your implementing class cannot be instantiated or located, you will get a DiscoverException stating that no implementation can be found for MyInterface.

MyImpl2 # Implementation 2

Of course, this is not the only way that you can register your implementing classes, otherwise there would be no use for Discovery! In fact, this way is the last way in which classes are discovered by Discovery's internal class-finding mechanism. Other preferred ways include passing the implementing class names in either the system properties or user-defined properties. For example, get rid of the file in META-INF/services and type the following to run this demo. You will get the same results as before. The system property in this case is the name of our interface, and the value is the provider for this interface.

$ java -DMyInterface=MyImpl1 DiscoveryDemo

Discovery can also be used to create (singleton) instances of your service providers and invoke methods on them. To do so, use the following syntax:

((MyInterface)discover.newInstance(MyInterface.class)).myMethod();

Note that we do not know at this stage which service provider is actually going to implement myMethod, nor do we care. Based on how you run this code and who you have registered as the service provider, you will get different implementations of the above method.

3. Lang

Summary: An extension of the java.lang package with many useful additions for String manipulations. Provides C-like enumerations as well.

Where: Main Page, Binaries, Source.

When: When you are unhappy with the default methods provided in the java.lang package and want to take more control over String manipulation, numeric methods, and System properties. Also, when you want to use C-like enumerations.

Example Applications: LangDemo.java, Mortgage.java, OnTV.java. Requires commons-lang.jar in the CLASSPATH.

Description:

A number of utility methods in this package are provided that make the life of the Java programmer easier. These methods, mostly static, reduce the coding required for everyday functions. This is most visible in the StringUtils class, which allows you to manipulate strings over and above the methods provided by the standard java.lang.String package. Using them is as simple as calling a static method with the right parameters. For example, to capitalize a string, you would simply use:

StringUtils.capitalise("name");

The output of this method, as expected, would be Name. Browse the rest of the StringUtils API for the rest of the static methods, and you will probably see something that you could use in your code. The example application exercises some of the methods.

Another interesting class is the RandomStringUtils class. This class provides methods to create random Strings, which can be really useful in creating random passwords.

The NumberUtils class provides methods for number manipulations. Interesting methods exist in this class, such as finding the maximum or minimum, and converting Strings to numbers. The NumberRange and CharRange classes provide a way of creating and manipulating ranges of numbers and characters, respectively.

The classes in the Builder package provide methods to build toString, hashCode, compareTo, and equals methods for classes. The idea is to build quality toString, equals, compareTo, and hashcode methods for your classes where you don't need to specify these methods yourself. You can simply use the methods in the Builder packages to build these methods. For example, using the ToStringBuilder method, you can create a toString representation for your class as follows:

public class Mortgage {
	private float rate;
	private int years;
  		
	....

	public String toString() {
		return new ToStringBuilder(this) .
			append("rate",  this.rate)   . 
			append("years", this.years)  .
			toString();
	}
}

Why would you use a method like this? It allows for a consistent way of handling all data types, returns null properly, and enables you to control the level of detail for objects and collections. This is applicable for all of the builder methods, and the syntax is similar to the one shown above.

For developers who miss C-style enums in Java, this package fills the void by providing a type-safe Enum data type. The Enum class is abstract, so to create your own enumerations, you need to extend this class. This is best illustrated with an example:

  1. Define, and extend your enumeration class:

    import org.apache.commons.lang.enum.Enum;
    import java.util.Map;
    import java.util.List;
    import java.util.Iterator;
        
    public final class OnTV extends Enum {
                
    	public static final OnTV IDOL     = new OnTV("Idol");
    	public static final OnTV SURVIVOR = new OnTV("Survivor");
    	public static final OnTV SEINFELD = new OnTV("Seinfeld");
                
    	private OnTV(String show) {
    		super(show);
    	}
                
    	public static OnTV getEnum(String show){
    		return (OnTV) getEnum(OnTV.class, show);
    	}
                
    	public static Map getEnumMap() {
    		return getEnumMap(OnTV.class);
    	}
                
    	public static List getEnumList() {
    		return getEnumList(OnTV.class);
    	}
                
    	public static Iterator iterator() {
    		return iterator(OnTV.class);
    	}
                
    }
  2. Now simply use this in your own methods as you would use an enumeration:

    OnTV.getEnum("Idol");

This returns the Idol item from the enumeration data type that we have created. The Enum class provides other useful methods for fully using this class.

4. Collections

Summary: An extension of the Java Collection Framework with great new data structures, iterators, and comparators.

Where: Main Page, Binaries, Source.

When: I recommend the use of the Collections API in almost all serious Java development projects where you need to work with data structures. The value that this API brings in over the regular Java implementations is tremendous.

Example Application: CollectionsDemo.java. Requires commons-collections.jar in the CLASSPATH.

Description:

There are too many classes in the Collections API to do justice to them in a single section. However, I will cover the most important ones here and hope that I have piqued your interest enough to take a serious look at the remaining ones. The API documentation itself provides a lot of information on how to use each of the classes.

The Bag interface extends the regular Java Collection by allowing a count to be kept of all elements in the Bag. A Bag is useful in situations where you want to track the number of elements going into or out of your collection of elements. Since Bag itself is an interface, you must use any of the implementing classes, such as HashBag or TreeBag. As the names suggest, HashBag implements a HashMap based Bag, while a TreeBag implements a TreeMap based Bag. Two important methods on the Bag interface are getCount(Object o), which returns the count of a particular element in the Bag, and uniqueSet(), which returns the unique elements in the Bag.

The Buffer interface allows you to remove objects from your collection based on a predefined order. This order can be LIFO (Last In First Out), FIFO (First In First Out), or you can define your own ordering. Let us see how we would implement a Buffer where the removal of elements is based on the natural sort order.

  1. The BinaryHeap class that implements the Buffer interface provides for removing elements based on the natural sort order. To reverse this sort order, pass a value of false, which indicates to the Heap that you want a reverse of the natural sorting.

    BinaryHeap heap = new BinaryHeap();
  2. Add your elements to this heap:

     heap.add(new Integer(-1));
    heap.add(new Integer(-10));
    heap.add(new Integer(0));
    heap.add(new Integer(-3));
    heap.add(new Integer(5));
  3. Call remove on this heap. Based on the natural sort order, -10 will be removed from this collection of elements. If we had requested reverse sort order, 5 would have been removed.

     heap.remove();

The FastArrayList, FastHashMap, and FastTreeMap classes operate in two modes over the corresponding regular Collection classes. The first mode is the "slow" mode, and is ideal for when these classes are being constructed and initialized. During "slow" mode, changes in the structure (addition or deletion of elements) of these classes is synchronized. In the "fast" mode, the access to these classes is thought to be read-only, and therefore is faster, as no synchronization takes place. Structural changes, if required during the fast mode, are accomplished by cloning the existing class, making modifications on the cloned class, and finally, replacing the existing class with the cloned one. These classes are useful in multithreaded environments where most access, after initialization, is read-only.

The iterator package provides iterators for various collections and objects that are not present in the regular Java Collections package. The example application exercises the ArrayIterator, which iterates over the contents of an Array. Using these iterators is the same as using the normal Java iterators.

Finally, some useful comparators are provided in the comparator package. A comparator is a class that allows you to define a way of comparing and deciding the sort order of two objects of the same class. For example, in the Buffer class that we talked about earlier, we could have defined our own comparator, and used it to impose a sorting order instead of going with the natural sorting of elements. Let us see how we would actually do this:

  1. Create a new BinaryHeap class, but this time, use a NullComparator. A NullComparator compares nulls against other objects to decide whether or not a null is higher than other objects based on the value of the flag nullsAreHigh. If this value is set to false, nulls are deemed to be lower than other objects.

    BinaryHeap heap2 = new BinaryHeap(new NullComparator(false));
  2. Add objects to this heap along with some nulls.

    heap2.add(null);
    heap2.add(new Integer("6"));
    heap2.add(new Integer("-6"));
    heap2.add(null);
  3. Finally, remove an element. The resulting Bag contains one fewer null, as nulls are lower than all other objects.

    heap2.remove();

This concludes our discussion of the Trivial category. For further details, read the API documentation, or better still, look at the source code of these packages.

Web Category

The components of the web category are related in one way or other to supplementing the web-related tasks for the Java programmer.

1. FileUpload

Summary: Ready-to-use file upload component.

Where: Main Page. Since this component has not been officially released and the beta that was released in February of this year is full of bugs, I advise you to download the latest code from the nightly builds.

When: When you want an easy-to-use, high-performance file upload component in your Java server environment.

Example Applications: fileuploaddemo.jsp, fileuploaddemo.htm, msg.jsp. Requires commons-fileupload-1.0-dev.jar in the WEB-INF/lib directory of your application on the server.

Description:

FileUpload solves the common problem of handling file uploads from the server point of view. It provides an easy-to-use interface to handle files uploaded to the server and can be used in JSP pages and servlets. It follows the RFC1867 standard, parses input requests, and hands over to your application a list of individual items uploaded to the server. Uploaded files are either kept in memory or in a temporary location (configurable with a size parameter; if the uploaded file size crosses the limit specified by the parameter, the files are written to a temporary location). You can also set other parameters, such as the maximum acceptable file sizes and the location of temporary files.

These are the steps needed to use FileUpload in your application. I will illustrate this with the help of an example where two different files on a single page need to be uploaded to the server.

  1. Create the HTML page. Note that for forms that allow for file uploads, the enctype must be specified and it must be equal to multipart/form-data, and the request method must be POST. Also note that our page not only contains provisions for two files to be uploaded, but also a normal text field.

    <form name="myform" action="fileuploaddemo.jsp"
     method="post" enctype="multipart/form-data">
        Specify your name:<br />
          <input type="text" name="name" size="15"/><br />
      Specify your Image:<br />
          <input type="file" name="myimage"><br/>
        Specify your File:<br />
          <input type="file" name="myfile"><br /><br />
        <input type="submit" name="Submit" value="Submit your files"/>
  2. Create your JSP.

    a. Check if the input request has been sent as multipart form data.

    // first check if the upload request coming in is a multipart request
    boolean isMultipart = FileUpload.isMultipartContent(request);

    b. Create a handler for this request, and use it to parse the request. Upon parsing, all of the form items are available in a list.

    DiskFileUpload upload = new DiskFileUpload();
        
    // parse this request by the handler
    // this gives us a list of items from the request
    List items = upload.parseRequest(request);

    c. Iterate over this list to access individual file items. To distinguish between items that are actual uploaded files versus regular form fields, use the isFormField() method. Based on the required processing scenarios, we could save the uploaded files, access them byte by byte, or open an input stream on them.

    Iterator itr = items.iterator();
    
    while(itr.hasNext()) {
    	FileItem item = (FileItem) itr.next();
            
    	// check if the current item is a form field or an uploaded file
    	if(item.isFormField()) {
                
    	// get the name of the field
    	String fieldName = item.getFieldName();
    	
    	// if it is name, we can set it in request to thank the user
    	if(fieldName.equals("name"))
    		request.setAttribute("msg", "Thank You: " + item.getString());
    		
    	} else {
    
    		// the item must be an uploaded file save it to disk. Note that there
    		// seems to be a bug in item.getName() as it returns the full path on
    		// the client's machine for the uploaded file name, instead of the file
    		// name only. To overcome that, I have used a workaround using
    		// fullFile.getName().
    		File fullFile  = new File(item.getName());  
    		File savedFile = new File(getServletContext().getRealPath("/"),
    		fullFile.getName());
    		item.write(savedFile);
    	}
    }

We could have restricted the size of uploaded files by using upload.setSizeMax on the upload handler. This would cause an exception to be thrown whenever a file is uploaded that is greater in size than the one specified. In the example above, I have set this size to -1, which allows all file sizes to be uploaded.

There are other, smaller variations to this scenario. As specified earlier, you can open an input stream on the uploaded files, let them remain in memory until a size threshold is reached, enquire about their content type, get their contents as a String or a Byte array, and delete them. All of this can be done by using simple methods on the FileItem class (DefaultFileItem is an implementation of this class).

2. HttpClient

Summary: An API to extend the java.net package. Provides functionality to mimic the usage of a browser.

Where: Main Page, Binaries, Source. The source code and the binaries are available for the beta 1 version.

When: When you are building web browser functionality; when your application requires an efficient way of handling HTTP/HTTPS connections.

Example Application: HttpClientDemo.java. Requires commons-httpclient.jar, common-logging.jar in the CLASSPATH, and JDK version 1.4 and above.

Description:

HttpClient is an extensive library that extends and enhances the basic java.net package. It is an extremely rich library that can help you build various kinds of distributed applications that use the HTTP protocol or embed it into your applications to leverage access over this protocol. The library is perhaps much better documented than the other packages in the Commons stable, and comes with several examples. I will delve into how you can develop a simple application that can retrieve a web page. A similar example exists in the tutorial section of the documentation; I will extend this example to support SSL. Note that JDK 1.4 and above is required for this example application because the example application requires the Java Secure Socket Connection library, which is part of the JDK from the 1.4 version.

  1. Identify a page that you can download via HTTPS. I used https://www.paypal.com/. Then make sure that the file %JAVA_HOME%/jre/lib/security/java.security contains a line similar to:

    security.provider.2=com.sun.net.ssl.internal.ssl.Provider

    After this, there is no difference in the way HTTPS connections are handled, at least in terms of your application. If however, the root certificate used on the remote site is not trusted by your Java implementation, you will need to import it before you can continue.

  2. Create an instance of HttpClient. Think of the HttpClient class as the main application driver that is required for all functions that you may want to perform. This class requires a Connection Manager that manages the actual connections. The HttpConnectionManager interface allows you to create your own managers, or you can use the built-in SimpleHttpConnectionManager or MultiThreadedHttpConnectionManager class. If you create a blank instance of HttpClient, it defaults its connection manager to the SimpleHttpConnectionManager.

     // create an instance of HttpClient.
    HttpClient client = new HttpClient();
  3. Create a method instance. This defines which HTTP method you want to use for transfer of information from the remote site. The possible values are GET, POST, PUT, DELETE, HEAD, OPTIONS, and TRACE. These methods are implemented as individual classes that implement the HttpMethod interface. For our example, we will use GetMethod, creating it by passing the URL that we want to GET.

    // create a method instance.
    HttpMethod method = new GetMethod(url);
  4. Execute this method instance for this particular URL. This is where an attempt is actually made to connect to the URL with the method that is specified. Upon execution, the status code returned by the server is returned by this method. Note that the executeMethod is on the client, and not the method.

     // execute the method.
    statusCode = client.executeMethod(method);
  5. Read the response from the server. If the previous attempt to connect had been unsuccessful, the method would have thrown HttpException or IOException. An IOException would indicate that there is something wrong with the network and that retrying is unlikely to be unsuccessful. The response can be read in as a byte array, as an input stream or as a String. You can now process this input as you wish.

    byte[] responseBody = method.getResponseBody();
  6. Finally, release the connection so that it can be reused, if need be.

     method.releaseConnection();

This has been a very simple discussion of the HttpClient library. There is much more that can be done with it; it is robust and efficient and is likely be officially released very soon.

3. Net

Summary: A low-level API for basic Internet protocols.

Where: Main Page, Binaries, Source.

When: When you want low-level access to various Internet protocols (Finger, Whois, TFTP, Telnet, POP3, FTP, NNTP, and SMTP) through your Java applications.

Example Application: NetDemo.java. Requires commons-net-1.0.0.jar in the CLASSPATH.

Description:

The Net package is an extremely robust and professional suite of classes. The classes in this library were initially part of a commercial product called NetComponents.

The Net classes offer both low-level access to most of the protocols and a high-level abstraction if you so desire. In most cases, the abstraction is enough, as it does not involve you in parsing the low-level socket-level commands for various protocols. Using the high-level abstraction does not take away any of the functionality, though, and the API does a good job of providing enough functionality without compromising on the available feature set.

The base class for all protocols is the SocketClient class. It is an abstract class that groups the common functionality required for all protocols. Using each of the different protocols is quite similar. First you use the connect method to establish a connection to the remote server, do the service required for the protocol, and finally disconnect from the server. Let us create an example to illustrate this usage.

  1. Create a relevant client. We will use a NNTPClient to download the list of available newsgroups on a news server.

    client = new NNTPClient();
  2. Connect with this client to the news server. I have used a server with a relatively short list of newsgroups. Please be kind to them.

    client.connect("aurelia.deine.net");
  3. Retrieve the list of newsgroups. The following command returns an array of NewsGroupInfo objects. This array will be empty if there are no newsgroups on this server, and null if an error occurs. Note that this command will take a long time, as the whole list of newsgroups may be very big. Each NewsGroupInfo object contains more information about the newsgroup and has public commands that you can use to retrieve information such as article count, last article posted, or posting permissions.

    list = client.listNewsgroups();
  4. Finally, disconnect from the server.

     if (client.isConnected())
    	client.disconnect();

Similarly, you can use any of the rest of the clients, be it FingerClient, POP3Client, TelnetClient, or any other.

Conclusion

This concludes the discussion on the Web-related and Trivial categories. In the next installment of this article, I will cover the XML and Packages categories. The final installment will cover the Utilities package.

I hope you have fun trying the demos in this article and that I've given you more insight into the often-chaotic world of Jakarta Commons. At the least, I hope this article has piqued your interest in the Commons subproject and the various useful APIs and libraries that it provides.

Vikram Goyal is the author of Pro Java ME MMAPI.


Return to ONJava.com.

Copyright © 2009 O'Reilly Media, Inc.