package er.extensions.foundation; import java.util.Enumeration; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.webobjects.foundation.NSArray; import com.webobjects.foundation.NSMutableDictionary; /** * Provides flexible and powerful assertion. Is modeled a bit like log4j in that you can have multiple asserters that can have * different behavior. In particular, each can be disabled, set to logging mode or set to raise an exception. Also you can set * your own failure handler. * * In WebObjects.properties, you can have: * * <blockquote><pre> * ERXAssert.instances=RAISE * ERXAssert.instances.com.somepackage=LOG * ERXAssert.instances.com.somepackage.someclass=RAISE * </pre></blockquote> * * In your code's static initialization, you can write: * * <blockquote><pre> * private static ERXAssert Assert = ERXAssert.getAssert(Foo.class); * private static ERXAssert Pre = ERXAssert.PRE; * private static ERXAssert Post = ERXAssert.POST; * </pre></blockquote> * * And finally, in your methods, you call it via: * * <blockquote><pre> * Pre.notNull(someObject); * Assert.notNull("someObject" ,someObject); * Post.notNull(someObject); * </pre></blockquote> * * or you can use the supplied assertors directly * * <blockquote><pre> * ERXAssert.DURING.notNull("someObject", someObject); * </pre></blockquote> * * Most of this code is derived from Jonathan "Wolf" Rentzsch's JAssert, which can be found here: * <a href="http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/redshed/JAssert/">http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/redshed/JAssert/</a>. **/ public class ERXAssert { private static final NSMutableDictionary _instances = new NSMutableDictionary(); private static final NSMutableDictionary _handlersForKey = new NSMutableDictionary(); private static final Logger log = LoggerFactory.getLogger(ERXAssert.class); public static final ERXAssert DURING; public static final ERXAssert PRE; public static final ERXAssert POST; //------------------------------------------- // Public assertion failure handler interface public interface FailureHandler { public void handleFailure(ERXAssert instance, String message); } protected static class EmptyHandler implements FailureHandler { public void handleFailure(ERXAssert instance, String message) { } } protected static class LoggingHandler implements FailureHandler { public void handleFailure(ERXAssert instance, String message) { String output = "Assertion failed (" + instance.name() + "): "; if(message != null) output += message; log.error(output, new Throwable()); } } protected static class ThrowingHandler implements FailureHandler { protected void raise(String message) { throw new RuntimeException(message); } public void handleFailure(ERXAssert instance, String message) { String output = "Assertion failed (" + instance.name() + "): "; if(message != null) output += message; raise(output); } } protected static class IllegalArgumentHandler extends ThrowingHandler { @Override protected void raise(String message) { throw new IllegalArgumentException(message); } } protected static class IllegalStateHandler extends ThrowingHandler { @Override protected void raise(String message) { throw new IllegalStateException(message); } } static { _handlersForKey.setObjectForKey(new EmptyHandler(), "NONE"); _handlersForKey.setObjectForKey(new LoggingHandler(), "LOG"); _handlersForKey.setObjectForKey(new ThrowingHandler(), "RAISE"); PRE = getAssert("PRE"); POST = getAssert("POST"); DURING = getAssert("DURING"); PRE.setFailureHandler(new IllegalArgumentHandler()); POST.setFailureHandler(new IllegalStateHandler()); DURING.setFailureHandler(new IllegalStateHandler()); } public static ERXAssert getAssert(String name) { synchronized(_instances) { ERXAssert value = (ERXAssert)_instances.objectForKey(name); if(value == null) { value = new ERXAssert(name); _instances.setObjectForKey(value, name); } setLevel(value); return value; } } protected static String getLevel(ERXAssert value) { NSArray arr = NSArray.componentsSeparatedByString(value.name(), "."); String prefix = "ERXAssert.instances"; String level = System.getProperty(prefix); if(level == null) level = "LOG"; for(Enumeration e = arr.objectEnumerator(); e.hasMoreElements(); ) { String s = (String)e.nextElement(); String possibleLevel = System.getProperty(prefix + "." + s); if(possibleLevel != null) { level = possibleLevel; } prefix = prefix + "." + s; } return level; } public static void setHandlerForLevel(FailureHandler object, String level) { _handlersForKey.setObjectForKey(object, level); } protected static void setLevel(ERXAssert value) { String level = getLevel(value); FailureHandler handler = (FailureHandler)_handlersForKey.objectForKey(level); if(handler == null) { throw new IllegalStateException("Can't find handler for level \"" + level + "\" for assert: " + value.name()); } value.setFailureHandler(handler); } public static ERXAssert getAssert(Class c) { return getAssert(c.getName()); } public static ERXAssert getAssert(String prefix, Class c) { return getAssert(prefix + "." + c.getName()); } protected String _name; private ERXAssert(String value) { _name = value; } //---------------------------------- // Public client assertion interface public void isTrue(boolean value) { if(value == false) fail("expected true"); } public void isTrue(String message, boolean value) { if(value == false) fail(message, "expected true"); } public void isFalse(boolean value) { if(value) fail("expected false"); } public void isFalse(String message, boolean value) { if(value) fail(message, "expected false"); } public void isNull(Object value) { if(value != null) fail("expected null object, got " + value); } public void isNull(String message, Object value) { if(value != null) fail(message, "expected null, got " + value); } public void notNull(Object value) { if(value == null) fail("expected non-null object"); } public void notNull(String message, Object value) { if(value == null) fail(message, "expected non-null object"); } public void isEmpty(String value) { if(value != null && !value.equals("")) fail("expected empty String, got " + value); } public void notEmpty(String value) { if(value == null) fail("expected non-empty String, got null"); else if(value.equals("")) fail("expected non-empty String, got empty string"); } public void isZero(int value) { if(value != 0) fail("expected zero int, got " + value); } public void isZero(long value) { if(value != 0L) fail("expected zero long, got " + value); } public void isZero(double value) { if(value != 0.0) fail("expected zero double, got " + value); } public void notZero(int value) { if(value == 0) fail("expected non-zero int, got " + value); } public void notZero(long value) { if(value == 0L) fail("expected non-zero long, got " + value); } public void notZero(double value) { if(value == 0.0) fail("expected non-zero double, got " + value); } public void isNegative(int value) { if(value >= 0) fail("expected negative int, got " + value); } public void isNegative(long value) { if(value >= 0L) fail("expected negative long, got " + value); } public void isNegative(double value) { if(value >= 0.0) fail("expected negative double, got " + value); } public void notNegative(int value) { if(value < 0) fail("expected non-negative int, got " + value); } public void notNegative(long value) { if(value < 0L) fail("expected non-negative long, got " + value); } public void notNegative(double value) { if(value < 0.0) fail("expected non-negative double, got " + value); } public void isPositive(int value) { if(value < 0) fail("expected positive int, got " + value); } public void isPositive(long value) { if(value < 0L) fail("expected positive long, got " + value); } public void isPositive(double value) { if(value < 0.0) fail("expected positive double, got " + value); } public void notPositive(int value) { if(value >= 0) fail("expected non-positive int, got " + value); } public void notPositive(long value) { if(value >= 0L) fail("expected non-positive long, got " + value); } public void notPositive(double value) { if(value >= 0.0) fail("expected non-positive double, got " + value); } public void isEqual(int value1, int value2) { if(value1 != value2) fail("expected equal integers, got " + value1 + " & " + value2); } public void isEqual(String message, int value1, int value2) { if(value1 != value2) fail(message, "expected equal integers, got " + value1 + " & " + value2); } public void isEqual(long value1, long value2) { if(value1 != value2) fail("expected equal longs, got " + value1 + " & " + value2); } public void isEqual(double value1, double value2) { if(value1 != value2) fail("expected equal doubles, got " + value1 + " & " + value2); } public void isEqual(Object value1, Object value2) { if((value1 != null && !value1.equals(value2)) || value2 == null ) fail("expected equal objects, got " + value1 + " & " + value2); } public void isEqual(String message, Object value1, Object value2) { if((value1 != null && !value1.equals(value2)) || value2 == null ) fail(message, "expected equal objects, got " + value1 + " & " + value2); } public void notEqual(int value1, int value2) { if(value1 == value2) fail("expected unequal integers, got " + value1 + " & " + value2); } public void notEqual(long value1, long value2) { if(value1 == value2) fail("expected unequal longs, got " + value1 + " & " + value2); } public void notEqual(double value1, double value2) { if(value1 == value2) fail("expected unequal doubles, got " + value1 + " & " + value2); } public void notEqual(Object value1, Object value2) { if((value1 != null && value1.equals(value2)) || value2 == null ) fail("expected unequal objects, got " + value1 + " & " + value2); } public void lessThan(int value1, int value2) { if(value1 >= value2) fail("expected " + value1 + " to be less than " + value2); } public void lessThan(long value1, long value2) { if(value1 >= value2) fail("expected " + value1 + " to be less than " + value2); } public void lessThan(double value1, double value2) { if(value1 >= value2) fail("expected " + value1 + " to be less than " + value2); } public void lessThanOrEqual(int value1, int value2) { if(value1 > value2) fail("expected " + value1 + " to be less than or equal to " + value2); } public void lessThanOrEqual(long value1, long value2) { if(value1 > value2) fail("expected " + value1 + " to be less than or equal to " + value2); } public void lessThanOrEqual(double value1, double value2) { if(value1 > value2) fail("expected " + value1 + " to be less than or equal to " + value2); } public void greaterThan(int value1, int value2) { if(value1 <= value2) fail("expected " + value1 + " to be greater than " + value2); } public void greaterThan(long value1, long value2) { if(value1 <= value2) fail("expected " + value1 + " to be greater than " + value2); } public void greaterThan(double value1, double value2) { if(value1 <= value2) fail("expected " + value1 + " to be greater than " + value2); } public void greaterThanOrEqual(int value1, int value2) { if(value1 < value2) fail("expected " + value1 + " to be greater than or equal to " + value2); } public void greaterThanOrEqual(long value1, long value2) { if(value1 < value2) fail("expected " + value1 + " to be greater than or equal to " + value2); } public void greaterThanOrEqual(double value1, double value2) { if(value1 < value2) fail("expected " + value1 + " to be greater than or equal to " + value2); } public void unknownSwitchCase(int value) { fail("unknown switch case: " + value); } public String name() { return _name; } public FailureHandler failureHandler() { return _failureHandler; } public void setFailureHandler(FailureHandler handler) { _failureHandler = handler; } protected FailureHandler _failureHandler; public void fail(String message) { _failureHandler.handleFailure(this, message); } public void fail(String message, String supplement) { _failureHandler.handleFailure(this, message + ": " + supplement); } }