Java J2EE Portal
Enterprise Java Station
J2EE curve
Java News / Articles
Java News / Articles
Building Advanced Components For Tapestry Web Applications
Groovy and Grails - A Getting Started Guide
EJBToJDO
Migrating a J2EE application from EJB to JDO
Processing...
Buy Java, Deals On Software Technology Store
Click here for great deals on computers, laptops, software and books
8 Simple Rules: Java Generics PDF Print
Written by Chakra Yadavalli   
Feb 23, 2005 at 09:15 AM
No. This article is not about John Ritter's "8 Simple Rules for Dating My Teenage Daughter." Rather this is about 8 concrete classes that implement an interface called Rule. These classes use JDK 5 Generics and couple of GOF patterns to provide a simple but flexible means to build applications using functors. Some developers admire the notion of functors but some think they are pure evil (may be because of over engineered implementations such as JGA library that uses 10 patterns in 40 lines of code).

** Winner of the Best Java Blogger Contest (Feb - Mar 2005) **

Even though there are very similar APIs out there, I have chosen to re-implement these Rules because I needed to regain my "Generic Programming" aptitude and also to show how a simple design would influence the way you deal with XML, Collections or even Business Rule validations. Why talk about it when we can get to the code?

The Rule Interface

Rule is a parameterized (generic) interface. It defines an evaluate method that takes an argument argInput of type T. The method evaluates the rule and returns a boolean value indicating the result - true if the rule is satisfied and false otherwise. This is a simplistic view of any rule: A rule is either satisfied or not satisfied by someone or something! At this level, we don't really care to whom this rule applies and for what purpose it exists. That is expressed by the generic type parameter T in the following interface definition:

package com.cyslab.functors;
public interface Rule<T> {
 public boolean evaluate(T argInput);
}

The 8 Simple Rules

Now, lets take a look at the 8 concrete implementations of Rule interface that address the common evaluation needs such as comparision, look ups, regular expression matching and a combination of two or more of those. These classes are defined in the com.cyslab.simplerules package.

  1. InRule implements the Rule interface's evaluate method to check if the given object is present in the predefined collection of objects. The implementation of this method is as simple as looking up an element of a collection using java.util.Collection.contains(E argElement) method.

  2. ComparableRule's evaluate method compares the given object with a predefined java.lang.Comparable instance. This supports the common comparison operation such as <, <=, >, >= and = defined by the ComparisonOperator enum. This also provides between comparison operation to check if the given object in in the specified range.

  3. ComparatorRule is similar to the ComparableRule but aims at providing the common comparison operations on objects that do not have a java.lang.Comparable implementation. This concrete implementation compares the given object with the predefined object using the predefined java.util.Comparator instance. This also supports the between convenience comparison operation.

  4. NotRule is the first of four logical operations that simply negates the result of another predefined rule.

  5. AndRule is the composite rule that logically ANDs the result of one or more predefined rules. Meaning, the evaluate method returns true if and only if the given object satisfies all the rules.

  6. OrRule is another composite rule that logically ORs the result of one or more predefined rules. The evaluate method returns true if the given object satisfies any of the given rule.

  7. XorRule implements the logical XOR operation on the predefined rules. XOR is not common in business applications but could come in handy to express some complex business rules such as select all employees that are either married and have kids or that are not married and do not have kids. Logical XOR operation returns true if and only if all the the rules are satisfied or if all of the rules are not satisfied.

  8. RegexRule utilizes the Java standard java.util.regex package (available in JDK 1.4 or later) to implement the Rule interface. Its evaluate method matches the given object's toString() representation with the predefined regular expression patterns specified via its constructor. The RegexRule constructors also accept a MatchPolicy enum to decide if NONE, ALL, or ANY of the specified regular expression patterns need to be matched while evaluating the rule.

The RuleBuilder Class

In addition to these 8 simple rules, a RuleBuilder class is provided to minimize the burden of using these Rules. The RuleBuilder is similar to the StringBuffer or more appropriately the StringBuilder (of JDK 5) in that each of its method returns a reference to self, thus enabling the "chaining" of rules. As you can see the implementation of RuleBuilder is nothing more than a bunch of methods that provide most common combinations of Logical, Comparison and list operations.

Putting the Rules to Work

Imagine that you are developing an application that spiders through the file system and archives some files. The files are selected based on certain criteria. In other words, we need to archive all the files that satisfy a Rule. In this case, let's assume the rule is the file:

  1. Cannot be /secret/Vault.java or /secret/Vault.xml

  2. Must have an extension .txt, .java, .html or .xml

  3. Must not be located under /proc, /usr/bin or /sbin folders of one of their subdirectories.

Assume that we have a FileArchiver class (see below) that uses a Rule<String> object to select files and archive them. The implementation details of FileArchiver are avoided for brevity.

public class FileArchiver {
 // Creates a file archiver that spiders the file system
 // and archives the files that satisfy the specified Rule.
 public FileArchiver(Rule<String> argFileSelectionRule){}
 // Archives the qualified files and returns the File object 
 // that represents the archive.
 public File archive() throws IOException{}    
}

All we got to do now is to create a Rule that translates our file selection rules into the concrete Rule interface implemenations. The code fragment below is self explanatory and does the needful.

// Rule 1: Uses InRule 
InRule<String> inRule = new InRule<String>("/secret/Vault.java""/secret/Vault.xml");
NotRule<String> notInRule = new NotRule<String>(inRule);
// Rule 2: Uses RegexRule to match ANY of the specified patterns
RegexRule<String> extRule = RegexRule.<String>matchAny("*.txt""*.java""*.html""*.xml");
// Rule 3: Uses RegexRule to match NONE of the specified patterns
RegexRule<String> dirRule = RegexRule.<String>matchNone("/proc/*""/usr/bin/*""/sbin/*");
// A composite rule that logically ANDs all the three rules.
Rule<String> fileSelectionRule = new AndRule<String>(notInRule, extRule, dirRule);

Or, if you prefer a shorthand notation, use the RuleBuilder as shown below. The RuleBulder's default constructor behaves as if it contains a "NOOP" rule that does nothing.

Rule<String> fileSelectionRule = 
 new RuleBuilder<String>()
 .andNotIn("/secret/Vault.java""/secret/Vault.xml")
 .andMatchAny("*.txt""*.java""*.html""*.xml")
 .andMatchNone("/proc/*""/usr/bin/*""/sbin/*")
 .toRule();

Once you have the fileSelectionRule ready, it's a matter of couple of lines to spider the file system and archive the selected files using the FileArchiver.

FileArchiver archiver = new FileArchiver(fileSelectionRule);
File archivedFile = archiver.archive();

In the next installment of "8 Simple Rules" will look at more applications of Rules and Java Generics.


Side Bar: JDK 5 Generics Syntax Cheat Sheet

private final Collection<? extends T> values;

The ? is known as the wild card and ? extends T is known as a bounded wild card (with an upper bound) and it means - any class that implements T (if T were an interface) or extends T (if T were a class). Therefore, this collection can hold any object of type T or any subtype of T (either class or interface).

private final Comparable<? super T> value;.

This ? super T is known as a bounded wild card with lower bound. and it means that value could be any instance of T or any of its supertype.

private final Collection<? extends Rule<? super T>> rules;

This collection can hold any subtype of Rule that operates on any supertype of T or T itself.

public AndRule(Rule<? super T>... argRules) { }

In JDK 5, Varargs are denoted by ellipses, the three dots. JDK 5 presents the Varargs as one dimensional array of the specified type. In this case the AndRule constructor can accept any Rule implemenation that operates on the type T or any of its super type.

RegexRule.<String>matchAny("*.txt""*.java""*.html""*.xml");

The above line shows how a static parameterized (Generic/Template) method is invoked. Note the position of the period (.) and the <String>. The Java Generics notation at times is cryptic. It will take few days to get used to it.


User Comments

Comment by Noname on 2006-02-07 00:55:24
I would go for publishing a series of white papers. This tactic works wonderfully.-acyclovir 
acyclovir 

Comment by 'Guest' on 2006-04-12 02:08:06
What are the Copyrights for it. Can we use this code piece in out propreitary code.

Comment by GUEST on 2008-01-02 18:48:59
8 simple rules rox

Comment by GUEST on 2008-01-30 06:30:11
8 simple rules 404s

Comment by simongdkelly@gmail.com on 2008-07-14 03:29:56
all links to source files return 404 errors
Your Name / Email Address
Comment
Spam Protection - Please enter the code in the image -

Listen to code


Add This Feed Button

Enter your Email

IndicThreads.com Conference On Java Technology, Pune, India
Java Expert Interviews
Debu Panda - Oracle
Oracle Application Server is the fastest
Anil Saldhana JBoss
JBoss is light years ahead of other open source application servers
Ramesh Loganathan Pramati
Pramati 4.1 and beyond: An interview with Ramesh Loganathan
Processing...
Go to top of page  Home |
SiteMap

Copyright 2004 to 2008 Rightrix Solutions. All rights reserved. All product names are trademarks of their respective companies. Java and all Java-based marks are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries. Rightrix Solutions and IndicThreads.com are independent of Sun Microsystems, Inc.

Views expressed at IndicThreads.com reflect the views of the authors alone, and do not necessarily reflect those of IndicThreads.com. IndicThreads.com and it's authors are not responsible for reader comments and opinions.

Enterprise Java J2EE JEE Portal >> IndicThreads.com