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 3

by Vikram Goyal
07/23/2003

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 first installment of this series divided these components into five categories and described the Web and Trivial categories. The second article covered the XML and Packages categories. This article describes the final category, Utilities. Note that these categorizations are purely for organizational reasons.

Utilities

The Utilities category contains the BeanUtils, Logging, DBCP, Pool, and Validator components.

BeanUtils

Summary: Provides utilities for working with dynamic JavaBeans.

Where: Main Page, Binaries, Source.

Source Code:

Download the source code for the example application. This .zip file contains:
AppLayer1Bean.java
AppLayer2Bean.java
BeanUtilsDemo.java
SubBean.java
DBCPDemo.java
commons-logging.properties
LoggingDemo.java
MyObjectFactory.java
PoolDemo.java
MyFormBean.java
MyValidator.java
validator.xml
ValidatorDemo.java

When: When your application requires dynamic access to JavaBeans without any knowledge of pre-compiled accessors and modifiers. The JavaBeans must conform to the naming design patterns in the JavaBeans specification.

Example Applications: BeanUtilsDemo.java, AppLayer1Bean.java, AppLayer2Bean.java, SubBean.java require commons-beanutils.jar, commons-logging.jar, and commons-collections.jar in the CLASSPATH.

Description:

In dynamic Java application development environments, it is not always possible to know ahead in time about the various getter and setter methods for your JavaBeans. Even when you might know the names of the methods, you may find it cumbersome to write a setXXX or getXXX method to set or get each and every property of a bean. Consider the case of almost identical beans being transferred from one application layer to another. Do you call bean1.setXXX(bean2.getXXX()) for each and every property? You could, but you don't have to. BeanUtils does it for you! BeanUtils helps the developer with dynamic JavaBean creation, modification, and copying.

BeanUtils can act on JavaBeans that satisfy the following conditions:

Let us start with a simple example.

To get and set simple properties, use the PropertyUtils.getSimpleProperty(Object bean, String name) and PropertyUtils.setSimpleProperty(Object bean, String name, Object value) methods, respectively, as shown below with the help of AppLayer1Bean.java and AppLayer2Bean.java as our test JavaBeans.

PropertyUtils.setSimpleProperty(app1Bean, "intProp1", 
    new Integer(10));
System.err.println("App1LayerBean, stringProp1: " +
    PropertyUtils.getSimpleProperty(app1Bean, "stringProp1")); 

Why would you use these methods, when you could just as simply get (and set) the values of these beans by calling the methods directly on the beans (app1Bean.getStringProp1() or app1Bean.setIntProp1(10))? You may not always know the names of these properties in advance in your code, and therefore may not know the right methods to call. These property names might come from variables set by another process or an external application. So, for example, if you accessed the name of the property of a bean and stored it in a variable, you could pass the variable name to PropertyUtils. This reduces a dependency on the developer to know the right method names in advance.

What happens when the properties are not simple data types? For example, your bean might have a collection or a map as a property. In these cases, use PropertyUtils.getIndexedProperty or PropertyUtils.getMappedProperty. Indexed properties require you to pass the index of the value within the collection that you want to get or set. Mapped properties require you to pass the key of the value you want to get or set. For example:

PropertyUtils.setIndexedProperty(
    app1Bean, "listProp1[1]", "New String value 1"); 
System.err.println("App1LayerBean, listProp1[1]: " +
    PropertyUtils.getIndexedProperty(app1Bean, "listProp1[1]"));

Notice how, for indexed properties, the value of the index is passed within square brackets. The example above sets the value at index 1 of the list in the bean app1Bean to New String value 1, while the line after that retrieves the same value at index 1. An alternate way of doing the same thing is to use the methods PropertyUtils.setIndexedProperty(Object bean, String name, int index, Object value) and PropertyUtils.getIndexedProperty(Object bean, String name, int index), where the index is passed as a method parameter. Similar methods exist for mapped properties where you pass the key, not the index, to get and set mapped values.

Finally, your bean might itself have other beans as properties. What happens when you want to get or set the property of the bean that is contained as a property within your primary bean? Use the PropertyUtils.getNestedProperty(Object bean, String name) and PropertyUtils.setNestedProperty(Object bean, String name, Object value) methods, as shown below.

// accessing and setting nested properties
PropertyUtils.setNestedProperty(
    app1Bean, "subBean.stringProp",
    "Hello from SubBean, set via Nested Property Access"); 

System.err.println(
    PropertyUtils.getNestedProperty(app1Bean, "subBean.stringProp"));

As you can see, the contained bean's property is accessed via a dot nomenclature.

You can use a combination of nested, mapped, and indexed properties to any depths you like. To use a combination of these different property-access methods, use PropertyUtils.getProperty(Object bean, String name) and PropertyUtils.setProperty(Object bean, String name, Object value). For example, this would allow you to make method calls such as:

PropertyUtils.setProperty(app1Bean, "subBean.listProp[0]", 
    "Some Value");

This combines nested and indexed property access into one call.

BeanUtils is often used when dynamically accessing the request parameters for a web-based system. In fact, BeanUtils arose out of a need to transfer the request parameters dynamically into system JavaBeans in the Struts project. A user-filled form is transferred into a Map in code, where the parameter names form the keys and the parameter values are the values from by the user, and a simple BeanUtils.populate transfers these values into a system bean.

Finally, BeanUtils provides a one-step method to copy values from one bean into another:

// let's copy app1Bean to app2Bean
BeanUtils.copyProperties(app2Bean, app1Bean);

In this package, there are several other useful methods that I have not covered here. BeanUtils is one of the better-documented components. I encourage you to have a look at the Javadocs for this package for descriptions of the rest of the methods.

Logging

Summary: Wrapper library around a set of popular logging implementations.

Where: Main Page, Binaries, Source.

When: When your application requires more than one logging implementation, or you anticipate such a need in the future.

Example Application: LoggingDemo.java, commons-logging.properties requires commons-logging.jar in the CLASSPATH. Requires log4j.jar, in certain cases.

Description:

Logging enables your applications to debug and trace their behaviors at any point in time. Logging is an integral part of any application, so there are many third-party logging implementations that eliminate the need for you to write your own logging API. In fact, even the JDK comes with a prebuilt logging API. With such a plethora of choices (log4j, JDK, Logkit, et cetera), the choice of a particular logging API to use within your own application comes down to selecting the one that best suits your requirements. However, a case can be made for instances where the choice of a logging API may not be compatible within applications, either because of company requirements or incompatibilities with existing architecture. The idea of the Logging component is to wrap the requirement of logging within a set of standard APIs where the underlying implementation can change or differ. The developer simply uses this API to make the log requests. The API decides, based on available logging architectures, to direct these logging calls to the appropriate handler. Thus, the Logging component, as far as the developer is concerned, is independent of any particular logging implementation.

If you are familiar with using log4j (also see this log4j article), using Commons-Logging should not be a problem. Even if you are not familiar with it, using Commons-Logging requires you to import two classes, create a static instance of a Log, and log away. The relevant code bits are shown below:

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class LoggingDemo {
    private static Log log = LogFactory.getLog(LoggingDemo.class);

    // ...
}

An interesting thing happens when you call LogFactory.getLog(). A process of discovery is started to find the required Logging implementation, according to the following scheme. Note that irrespective of how the desired implementation is found, it should be a class that implements the Log interface and is available in the CLASSPATH. Commons-Logging comes prebuilt with Jdk14Logger, Log4JLogger, LogKitLogger, NoOpLogger (which simply swallows all messages), and a SimpleLog.

  1. Commons-Logging looks for a configuration file called commons-logging.properties in the CLASSPATH. This file must define, at the minimum, the property org.apache.commons.logging.Log, and it should be equal to the fully qualified name of one of the implementations of the Log interface listed above.

  2. If a configuration file cannot be found with the right property above, Commons-Logging looks for a system property called org.apache.commons.logging.Log.

  3. If there is no system property with the above name, Commons-Logging looks for log4j classes in the CLASSPATH. By the simple act of finding these classes in the CLASSPATH, Commons-Logging assumes that you are using log4j. However, note that log4j still needs to be configured for its properties in its own log4j.properties file.

  4. If none of the above is found and if the application is running on JRE 1.4 and above, the application defaults to using the JRE1.4's logging mechanism.

  5. Finally, if none of the above is valid and the application is not running on JRE 1.4 and above, the application uses a built-in SimpleLog, which writes everything to System.err.

Once the desired logging implementation has been obtained, you can start logging within your environment, based on your rules and degree of severity of your log messages. Using a standard API abstracts from the underlying mechanism and the same call is translated into implementation-specific calls.

Jakarta Struts Pocket Reference

Related Reading

Jakarta Struts Pocket Reference
By Chuck Cavaness, Brian Keeton

The supplied demo file simply prints an information message and tells you which logging implementation was used to do so. Try running this file in different environments, for example, run the file on its own without specifying any properties, and you will default to Jdk14Logger. Run it by specifying the system property as -Dorg.apache.commons.logging.Log=org.apache.commons.logging.impl.SimpleLog, and you will see that SimpleLog is used to print the message. Finally, try putting Log4 classes in the CLASSPATH. If you have set the correct configuration for log4j in a log4j.properties file, you will get the message created with Log4JLogger.

Pool

Summary: A library that allows you to maintain a pool of objects.

Where: Main Page, Binaries, Source.

When: Whenever you need to maintain a pool of object instances.

Example Applications: PoolDemo.java and MyObjectFactory.java require commons-pool.jar and commons-collections.jar in the CLASSPATH.

Description:

Pool serves the purpose of defining a set of interfaces for object-pooling mechanisms. It also provides some general-purpose pool implementations and some base classes that you could use to create your own pooling architecture.

Object pools may not be new to most developers. Many developers have, at some time or other, used a database pooling mechanism for access to databases. Object pools allow you to instantiate a set of objects within a pool as part of configuration and startup, allowing for shorter response times when these objects are actually needed within your application. These objects can be returned to the pool once they've been used, remaining available to any other calling application.

The Pool component allows you to create Object (Instance) pools without tying you to one particular implementation. Several implementations are provided with the component, and you can create your own, if so required.

Three types of base classes make up the Pool component: ObjectPool, an interface that defines and maintains a pool, ObjectPoolFactory, responsible for creating instances of ObjectPool, and PoolableObjectFactory, which defines a set of lifecycle methods for instances to be used in the ObjectPool. A variation on these classes is the KeyedXXX interface. This interface allows you to create several object pools for different types of objects, only differentiated with the help of a Key. In a way, the KeyedXXX interface is a Map implementation of the normal ObjectPool.

As stated before, there are several generic implementations prebuilt within the Pool component. One of these is the GenericObjectPool, and I will illustrate its usage with the help of an example.

  1. Create a PoolableObjectFactory. This factory defines how your objects are created, destroyed, and validated.

    import org.apache.commons.pool.PoolableObjectFactory;
    
    public class MyObjectFactory implements PoolableObjectFactory {
        private static int counter;
    
        // returns a new string
        public Object makeObject() {
        	return String.valueOf(counter++); 
        }
    
        public void destroyObject(Object obj) {}
        public boolean validateObject(Object obj) { return true; }
        public void activateObject(Object obj) {}
        public void passivateObject(Object obj) {}
    }

    Notice that we are creating a pool of String objects with an incrementing number, and that our validations always return true. You can implement the other methods, if required.

  2. Using this PoolableObjectFactory, create a GenericObjectPool, using default values for maxActive, maxIdle, and so on.

    // create a GenericObjectPool using MyObject factory and default
    // values for the maxActive, maxIdle etc.
    GenericObjectPool pool = new GenericObjectPool(new MyObjectFactory());
  3. Borrow an object from it.

    System.err.println("Borrowed: " + pool.borrowObject());
  4. Return it.

    pool.returnObject("0");

You can use various methods to find the state of the pool.

// so what's the number of active (borrowed objects) ?
System.err.println("Active objects: " + pool.getNumActive());

The example file PoolDemo.java contains the full source code.

DBCP

Summary: Database Connection Pooling, based on the Pool component.

Where: Main Page, Binaries, Source.

When: Whenever access is required to a relational database.

Example Application: DBCPDemo.java requires commons-dbcp.jar, commons-pool.jar, and commons-collections.jar in the CLASSPATH. You will also require access to a database and the JDBC drivers for accessing that database. The example application tests connection to a MySQL server using the MySQL JDBC driver. Note that you will require the nightly version of the binaries, as the official release does not contain some of the required classes. Finally, when this example is run, make sure that you set the system property for the JDBC driver you are using (-Djdbc.drivers=com.mysql.jdbc.Driver).

Description:

DBCP provides a database-connection pooling mechanism based on the Pool component. Its usage is slightly more involved than regular connection pooling mechanisms, as the idea was to provide a generic architecture available as a pseudo-JDBC driver. However, since we have already covered the basics of the Pool component, understanding the usage for DBCP should be easier.

  1. Create a GenericObjectPool class:

    GenericObjectPool pool = new GenericObjectPool(null);
  2. Recall from the discussion on the Pool component that the GenericObjectPool requires a PoolableObjectFactory to create the instances of our Objects that need to be pooled. This, in DBCP's case, is provided by the PoolableConnectionFactory as shown below:

    Create the PoolableConnectionFactory:

    DriverManagerConnectionFactory cf =
        new DriverManagerConnectionFactory(
        "jdbc:mysql://host/db", "username", "password"); 
    
    PoolableConnectionFactory pcf =
        new PoolableConnectionFactory(
        CF, pool, null, "SELECT * FROM mysql.db", false, true);
  3. Now, all we need to do is to create and register the PoolingDriver.

    new PoolingDriver().registerPool("myPool", pool);

We are now ready to get connections out of this Connection Pool. Note that it has been created with default values for maxActive, maxIdle, et cetera. You can set these properties to what you require while creating the GenericObjectPool class in step 1 above. DBCPDemo.java gives the complete example.

Validator

Summary: API that combines commonly used validations of user input.

Where: Main Page, Binaries, Source.

When: Whenever you need to validate JavaBeans on a regular basis.

Example Application: ValidatorDemo.java, MyValidator.java, MyFormBean.java, validation.xml require commons-validator.jar, commons-beanutils.jar, commons-collections.jar, commons-digester.jar, and commons-logging.jar in the CLASSPATH.

Description:

If you have developed a web application using Struts before, you've come across the Validator package. It makes the job of performing validations on user input quite easy, and provides a single interface for locale-specific error messages. However, Validator is not just of use in web applications — it can be quite easily used at other places where JavaBeans are used.

Validator allows you to define validations for your user input fields, provide internationalization support in form of locale-specific error messages, and create custom Validators. There are several prebuilt validators that you can use, and you can create your own if the custom validators do not serve your purpose.

Validation rules and validation methods are defined using XML files. (The definitions can be in one or many files. It is a good idea to separate them, though.) The validation methods file defines the validators to be used and names the class that actually implements the validator. This class does not need to implement any specific interfaces or extend another class. It should simply conform to the definition, as specified in the method file.

Let us construct a validator of our own that simply checks if a String property of a bean contains a specific character (*).

import org.apache.commons.validator.*;

public class MyValidator {
    public static boolean validateContainsChar(Object bean, Field field) {

    	// first get the value of this bean property as a string
    	String val = ValidatorUtil.getValueAsString(bean, field.getProperty());

    	// now return true or false based on the presence of the '*' sign
    	return ((val.indexOf('*') == -1) ? false : true);
    }
}

The ValidatorUtil class provides useful methods to get the values of bean properties as easily manipulable String values. This validator now needs to be defined in an XML file:

<!-- This defines the validator methods that we are implementing -->
<global>
    <validator name="containsStar"
    	classname="MyValidator"
    	method="validateContainsChar"
  		methodParams="java.lang.Object, org.apache.commons.validator.Field" />
</global>

Notice that we define the exact method structure, including the parameters that it expects. To use this validator in a method of your own, follow these steps:

  1. Add the validator rules that we want to implement in the XML file above:

    <!-- This defines the validator rules -->
    <formset>
        <!-- This checks if the form bean's name property implements 
        the containsPercent method -->
        <form name="myFormBean">
        	<field property="name" depends="containsStar">
        		<arg0 key="myFormBean.name" />
        	</field> 
        </form>
    </formset>

    As you can see, all validation rules are enclosed in the formset element, following which the form for which the validations are to be performed is listed with the individual validations. In our case, we want the name property of myFormBean to be validated so that it passes the containsStar validation (so that it contains the character *).

  2. Create a Validator and initialize it, based on the XML file:

    // load the validator xml files
    InputStream in = getClass().getResourceAsStream("validator.xml");
    
    // create a ValidatorResources
    ValidatorResources resources = new ValidatorResources();
    
    // and load resources in
    ValidatorResourcesInitializer.initialize(resources, in);
    
    // now create the Validator
    Validator validator = new Validator(resources, "myFormBean");
    validator.addResource(Validator.BEAN_KEY, bean);
  3. Validate the bean:

    // finally validate
    ValidatorResults results = validator.validate();

    The results of the validation are passed as an instance of ValidatorResults. It contains a hashmap of individual ValidationResult objects for each property for which validation was requested.

  4. Process the ValidationResults:

    // the result object may contain the results of validation on other form
    
    // properties as well. For each property we can get the result individually
    ValidatorResult result = results.getValidatorResult("name");
    
    // and for each property, we can check for individual validations
    // for example, did the name property pass the containsStar validation?
    
    System.err.println(
        "Contains Star validation passed for \'name\' property?" +
        result.isValid("containsStar"));

    On each ValidationResult instance, we can query whether it passed or failed a particular validation. For example, in the code above the result instance for the name property is queried for the containsStar validation by the code result.isValid('containsStart').

Validator is quite useful in web applications, as it reduces the repetitive task of validations to be performed on user input by providing a set of prebuilt Validators. These include, but are not limited to, range checking, limitations on types and sizes of input values, and email and locale testing. Further, you can extend and create your own Validators to add to this list.

Conclusion

This concludes the third and final installment of coverage of Jakarta Commons. Although these articles covered only the basics of each component, I hope that they have given enough information for you to start exploring them further. Good Luck!

Vikram Goyal is the author of Pro Java ME MMAPI.


Return to ONJava.com.

Copyright © 2009 O'Reilly Media, Inc.