RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX


Extend the JDK Classes with Jakarta Commons, Part I : Page 4

Explore the components in the Jakarta Commons set of reusable classes and you'll be convinced that most of them should be part of the JDK. Learn which ones you should use in your projects.



The Gang of Four's Chain of Responsibility (COR) behavioral design pattern is interesting and commonly used to model a set of operations. Each operation needs to be modeled as a command object and linked to others to form a chain. The command objects act upon some data and indicate whether the control should get passed to the next command in the chain. The benefit is that an operation can be added or removed easily without changing code. For successful execution, the arguments and the sub-commands passed from the command line while executing a command should be made available to the processing code.

The Commons Chain component provides the interfaces and implementations necessary for using this pattern in an application. The API is neat and easy to understand. I've apply it to a real-world problem to explain its usage. Many developers have developed or at least used a CLI (Command Line Interface) application. The Commons Chain example is a CLI application for using the basic network protocols HTTP, FTP, and PING. (Find the source files in the package in.co.narayanan.commons.chain.) The following listing is a sampling of some of its commands:

java CommandProcessor -user admin -password manager -ping {host}
java CommandProcessor -user admin -password manager -ftp {host} -get {path_to_file}
java CommandProcessor -user admin -password manager -http -get {path_to_file}

The application uses the –user and –password arguments to validate a user against a local database and not for the network commands. The argument –get is a subcommand to fetch a file for the given URL for both –ftp and –http master commands. To focus on demonstrating Commons Chain, the implementation contains only the skeleton code. Therefore, on executing the –ping command, you print log messages to the console and don't actually connect to the target. I leave it to you to complete this application. I recommend using the Commons Net API for this purpose.

Using the COR pattern for this problem greatly simplified and improved the modularity of the design.

CLI Context
When a CLI command executes, the arguments and the subcommands need to be available for the processing code to successfully complete the operation. The CommandlineContext and CLICommand classes are the domain objects, which represent the commands, subcommands, and arguments.

The CLICommand has a reference to itself. This is a Composite design pattern implementation to represent the subcommands, which enables nesting any number of commands. An instance of the CLICommand, along with user and password, will be contained in the CommandlineContext, thereby representing all the information of the executed CLI operation. The context will be passed to the commands in the chain during execution. It is up to each command in the chain to make use of the context information or pass the control to the next command.

This example represents the CLI arguments as private variables and accesses them using getter methods in the context class. The alternative is to use the ContextBase implementation. It uses Java Bean introspection to fetch the attribute value and presents a Map view. Hence, dedicated getter methods like getUser and getPassword can be replaced with get("user") and get("password").

Commands in the Chain
After representing the context information necessary for a command, the next step is to model the commands, chains, and subchains. (Later, you will see how the Commons Chain API executes the commands and chains.) The class Ping is the command that gets executed for –ping. This class uses the context passed in the execute method to check whether the command type is –ping. If the command type is something else, the method returns false to notify the Chain framework that the control needs to be passed to the next command in the chain.

The classes Ftp represents the master command –ftp. Hence, it is modeled as a subclass of ChainBase in order to process the ftp subcommands –get and –ls. The execute method check the command type, if it is –ftp, then the base class execute method is called for executing commands FtpGet and FtpLs in this chain. In this application, if a command contains a subcommand, such as –http –get, then it is modeled as a Chain to delegate the control further down to respective commands.

The Chain
The chains and commands identified for this application are visually presented here:

Main Chain
Authenticator (Verifies user and password) --> Ping (Command) --> 
Ftp (Sub-chain A) --> Default (Prints invalid command message) Sub-chain A FtpGet (Command) --> FtpLs (Command)

The chain can be programmatically built at runtime using the ChainBase or CatalogBase class. The alternative is to specify the commands and chains in a XML file and use ConfigParser to build the chain. The catalog.xml file used for this application is presented here:

<?xml version="1.0" ?>
    <chain name="CommandProcessor">
        <command name="authenticate" className="in.co.narayanan.commons.chain.Authenticator"/>
        <command name="ping" className="in.co.narayanan.commons.chain.Ping"/>
        <chain name="ftp" className="in.co.narayanan.commons.chain.Ftp">
            <command name="get" className="in.co.narayanan.commons.chain.FtpGet"/>
            <command name="ls" className="in.co.narayanan.commons.chain.FtpLs"/>
        <command name="default" className="in.co.narayanan.commons.chain.DefaultCLICommand"/>

Putting It All Together
The following listing is the code to set up and run the Commons Chain framework:

        ConfigParser parser = new ConfigParser();

        Catalog catalog = CatalogFactoryBase.getInstance().getCatalog();

        Command command = catalog.getCommand("CommandProcessor");

The catalog.xml file is parsed and the resultant Catalog reference is fetched from the CatalogFactoryBase. You have mocked the call to each of the CLI commands. You'll find the complete code in the test case class TestChain. Ideally, a separate class will parse the command-line input to create context objects and pass them to the chain. You can use Commons CLI for this purpose.

Close Icon
Thanks for your registration, follow us on our social networks to keep up-to-date