Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs
TEXTBOX:
TEXTBOX_HEAD: Using the if-then-else framework: Read the whole series!
:END_TEXTBOX
For convenience, Listing 1 below displays the implementation of the if-then-else framework for the example used in Parts 1
and 2. I suggest you review the use of Conditions, Actions, Rules, the Updateable interface, and the Invoker subclass before diving into the rest of the discussion. (You may also wish to compare my approach to coding branching logic
with the Hashed Adapter Objects design pattern, discussed in Mark Grand's book on design patterns -- see Resources for more information.)
Listing 1. The URLProcessor_good class with user-defined inner classes
class URLProcessor_good extends URLProcessor implements logic.Updateable {
static final String URL_STR = "urlString";
URLProcessor_good(){
super();
}
void decideUrl() {
try {
Invoker inv = new ConcreteInvoker((Updateable)this);
inv.execute();
}
catch(NestingTooDeepException ntde) {}
catch(IllegalExpressionException iee) {}
catch(RuleNotFoundException rnfe) {}
catch(DataNotFoundException dnfe) {}
}
/** Updateable interface implementation */
public void doUpdate(Hashtable ht) {
if(ht == null) return;
Object ob = ht.get(Action.MAIN_KEY);
if(ob != null && ob instanceof String) {
setUrl((String)ob);
}
}
static class OtherCondition extends Condition {
public static final String KEY = "key";
public OtherCondition(Hashtable ht) {
super(ht);
}
public Boolean evaluate() throws DataNotFoundException {
Object ob = null;
if(getData() == null || (ob = getData().get(KEY)) == null) {
throw new DataNotFoundException();
}
if(!(ob instanceof DataBank.Region)) {
return Boolean.FALSE;
}
DataBank.Region region = (DataBank.Region)ob;
boolean result = !region.equals(DataBank.WEST_REGION) &&
!region.equals(DataBank.EAST_REGION);
return new Boolean(result);
}
}
static class MemberCondition extends Condition {
public static final String KEY = "id";
public static final String TABLE = "table";
public MemberCondition(Hashtable ht) {
super(ht);
}
public Boolean evaluate() throws DataNotFoundException {
Object id = null, table = null;
if(getData() == null ||
((id = getData().get(KEY)) == null) ||
((table = getData().get(TABLE))==null) ||
!(table instanceof Hashtable)) {
throw new DataNotFoundException();
}
Hashtable members = (Hashtable)table;
return new Boolean(members.containsKey(id));
}
}
public class ConcreteInvoker extends Invoker {
public ConcreteInvoker(Updateable ud) throws NestingTooDeepException {
super(ud);
}
public void loadRules() throws NestingTooDeepException {
rules = new Rules();
try {
// Conditions: Actions:
// East|West|Other|Lim|Member
rules.addRule("TFFT*", new Action(ud,EAST_PRIVILEGED));
rules.addRule("TFFF*", new Action(ud,EAST_NOT_PRIVILEGED));
rules.addRule("FTFTT", new Action(ud,WEST_MEMBER_PRIVILEGED));
rules.addRule("FTFTF", new Action(ud,WEST_NONMEMBER_PRIVILEGED));
rules.addRule("FTFFT", new Action(ud,WEST_MEMBER_NOT_PRIVILEGED));
rules.addRule("FTFFF", new Action(ud,WEST_NONMEMBER_NOT_PRIVILEGED));
rules.addRule("FFT**", new Action(ud,OTHER_REGION));
}
catch(NestingTooDeepException e) {
throw e;
}
}
public void loadConditions() throws IllegalExpressionException {
try {
conditions = new Vector(5);
conditions.addElement(new Condition(db.getRegion(),DataBank.EAST_REGION));
conditions.addElement(new Condition(db.getRegion(),DataBank.WEST_REGION));
Hashtable other = new Hashtable();
other.put(OtherCondition.KEY,db.getRegion());
conditions.addElement(new OtherCondition(other));
conditions.addElement(new Condition(db.LIMIT_THRESHOLD, Condition.LESS,db.getLimit() ));
Hashtable mem = new Hashtable();
mem.put(MemberCondition.TABLE, db.getWestMembers());
mem.put(MemberCondition.KEY, db.getUserId());
conditions.addElement(new MemberCondition(mem));
}
catch(IllegalExpressionException e) {
throw e;
}
}
}
}
The following issues, which I outlined at the end of Part 2, will provide a structure for this discussion:
sampleCode2 and sampleProfile. The sampleCode2 package shows how to use sequencers in URLProcessor_good; the package name for this GUI code has changed to sampleCode2, and so the HTML file that runs the applet had to be changed to iteGUI2.html. The sampleProfile package contains the Profiler class and the Main class, with which you can test performance. The files were compiled with JDK 1.1.7, and the GUI was written in Swing. If
you attempt to recompile, be sure to include the swingall.jar file for Swing 1.0.3 in your classpath. Download the zip fileHashtables in Chapter 11Hashtable lookups. Some obvious differences between Grand's pattern and my framework are: