package org.oddjob.jobs; import java.io.Serializable; import org.apache.log4j.Logger; import org.oddjob.arooa.ArooaSession; import org.oddjob.arooa.ArooaValue; import org.oddjob.arooa.convert.ArooaConverter; import org.oddjob.arooa.convert.ConversionFailedException; import org.oddjob.arooa.convert.NoConversionAvailableException; import org.oddjob.arooa.deploy.annotations.ArooaAttribute; import org.oddjob.arooa.deploy.annotations.ArooaHidden; import org.oddjob.arooa.life.ArooaSessionAware; /** * @oddjob.description Checks a value for certain criteria. This * job is analogous to the Unix 'test' command. * <p> * This Job will COMPLETE if all checks pass. It will be INCOMPLETE * if any fail. * <p> * The conditional values are converted into the type of the * value before the checks are made. Thus in the example below * if the row count property is an integer, the 1000 is converted * into an integer for the comparison. * <p> * If the value property is not provided the job will be INCOMPLETE unless * the null property is set to true. * * @oddjob.example * * Example text comparisons. All these checks COMPLETE. * * {@oddjob.xml.resource org/oddjob/jobs/CheckTextExample.xml} * * Checks that are INCOMPLETE. * * {@oddjob.xml.resource org/oddjob/jobs/CheckTextIncompleteExample.xml} * * @oddjob.example * * Numeric checks. Note that the value must be the numeric value. The * operand attributes values are converted to the type of the value before * the comparison. If the value was "999" and the lt was "${sequence.current}" * this check would not be COMPLETE because the text "999" is greater than * "1000". * * {@oddjob.xml.resource org/oddjob/jobs/CheckNumberExample.xml} * * @oddjob.example * * Check a Property Exists. The second check will be INCOMPLETE because the * property doesn't exist. * * {@oddjob.xml.resource org/oddjob/jobs/CheckExistsExample.xml} * * @author rob * */ public class CheckJob implements Runnable, Serializable, ArooaSessionAware { private static final long serialVersionUID = 2009092700L; private static final Logger logger = Logger.getLogger(CheckJob.class); /** * @oddjob.property * @oddjob.description The result of the check. */ private int result; /** * @oddjob.property null * @oddjob.description Must the value be null for the check to pass. * True the value must be null. False it must not be null. If this * property is true other checks will cause an exception because they * require the value property has a value. * @oddjob.required No, if this does exist the check value null will fail. */ private transient boolean null_; /** * @oddjob.property * @oddjob.description The value to check. * @oddjob.required No, but the check value is not null will fail. */ private transient Object value; /** * @oddjob.property * @oddjob.description The value to check. * @oddjob.required No, but the check value is not null will fail. */ private transient Boolean z; /** * @oddjob.property * @oddjob.description The value must be equal to this. * @oddjob.required No. */ private transient ArooaValue eq; /** * @oddjob.property * @oddjob.description The value must be not equal to this. * @oddjob.required No. */ private transient ArooaValue ne; /** * @oddjob.property * @oddjob.description The value must be less than this. * @oddjob.required No. */ private transient ArooaValue lt; /** * @oddjob.property * @oddjob.description The value must be less than or equals to this. * @oddjob.required No. */ private transient ArooaValue le; /** * @oddjob.property * @oddjob.description The value must be greater than this. * @oddjob.required No. */ private transient ArooaValue gt; /** * @oddjob.property * @oddjob.description The value must be greater than or equal to this. * @oddjob.required No. */ private transient ArooaValue ge; private transient ArooaConverter converter; /** * @oddjob.property * @oddjob.description The name of this job. Can be any text. * @oddjob.required No. */ private transient String name; @SuppressWarnings("unchecked") public void run() { result = 0; Check[] checks = new Check[] { new Check() { @Override public boolean required() { return true; } @Override public boolean check() { return !(value == null ^ null_); } @Override public String toString() { return "value [" + value + "] should" + (null_ ? "" : " not" ) + " be null"; } }, new Check() { @Override public boolean required() { return z != null; } @Override public boolean check() { return value != null && (value.toString().length() == 0) == z.booleanValue(); } @Override public String toString() { return "[" + value + "] should be of " + (z.booleanValue() ? "" : "none") + " zero length"; } }, new Check() { @Override public boolean required() { return eq != null; } @Override public boolean check() { return value != null && value.equals(convert(eq)); } @Override public String toString() { return "[" + value + "] should equal [" + eq + "]"; } }, new Check() { @Override public boolean required() { return ne != null; } @Override public boolean check() { return value != null && !value.equals(convert(ne)); } @Override public String toString() { return "[" + value + "] should not equal [" + ne + "]"; } }, new Check() { @Override public boolean required() { return lt != null; } @SuppressWarnings("rawtypes") @Override public boolean check() { return value != null && ((Comparable) value).compareTo( convert(lt)) < 0; } @Override public String toString() { return "[" + value + "] should be less than [" + lt + "]"; } }, new Check() { @Override public boolean required() { return le != null; } @Override @SuppressWarnings("rawtypes") public boolean check() { return value != null && ((Comparable) value).compareTo( convert(le)) <= 0; } @Override public String toString() { return "[" + value + "] should be less or equal to [" + le + "]"; } }, new Check() { @Override public boolean required() { return gt != null; } @Override @SuppressWarnings("rawtypes") public boolean check() { return value != null && ((Comparable) value).compareTo( convert(gt)) > 0; } @Override public String toString() { return "[" + value + "] should be greater than [" + gt + "]"; } }, new Check() { @Override public boolean required() { return ge != null; } @Override @SuppressWarnings("rawtypes") public boolean check() { return value != null && ((Comparable) value).compareTo( convert(ge)) >= 0; } @Override public String toString() { return "[" + value + "] should be greater or equal to [" + ge + "]"; } } }; for (Check check : checks) { if (!check.required()) { continue; } if (check.check()) { logger.debug("Check " + check + " passed."); } else { logger.info("Check " + check + " FAILED!"); result = 1; return; } } logger.info("Check(s) passed."); } /** * Encapsulate the a check. */ interface Check { /** * Is a check required? * * @return true if it is, false if it isn't required. */ boolean required(); /** * Perform the check. * * @return true if it passed, false if it didn't. */ boolean check(); } /** * Convert the Right Hand Side of the expression to the type of the * value property. * * @param rhs * @return */ Object convert(ArooaValue rhs) { try { return converter.convert(rhs, value.getClass()); } catch (NoConversionAvailableException e) { throw new RuntimeException(e); } catch (ConversionFailedException e) { throw new RuntimeException(e); } } @ArooaHidden public void setArooaSession(ArooaSession session) { this.converter = session.getTools().getArooaConverter(); } public String getName() { return name; } public void setName(String name) { this.name = name; } public boolean getNull() { return null_; } @ArooaAttribute public void setNull(boolean value) { this.null_ = value; } public Boolean getZ() { return z; } public void setZ(Boolean z) { this.z = z; } public Object getValue() { return value; } @ArooaAttribute public void setValue(Object value) { this.value = value; } public ArooaValue getEq() { return eq; } @ArooaAttribute public void setEq(ArooaValue eq) { this.eq = eq; } public ArooaValue getNe() { return ne; } @ArooaAttribute public void setNe(ArooaValue ne) { this.ne = ne; } public ArooaValue getLt() { return lt; } @ArooaAttribute public void setLt(ArooaValue lt) { this.lt = lt; } public ArooaValue getGt() { return gt; } @ArooaAttribute public void setGt(ArooaValue gt) { this.gt = gt; } public ArooaValue getLe() { return le; } @ArooaAttribute public void setLe(ArooaValue le) { this.le = le; } public ArooaValue getGe() { return ge; } @ArooaAttribute public void setGe(ArooaValue ge) { this.ge = ge; } public int getResult() { return result; } @Override public String toString() { return name == null ? CheckJob.class.getSimpleName() : name; } }