1 package com.tirsen.nanning.contract; 2 3 import java.text.MessageFormat ; 4 import java.util.ArrayList ; 5 import java.util.List ; 6 import java.util.ListIterator ; 7 import java.util.Map ; 8 import java.util.regex.Matcher ; 9 import java.util.regex.Pattern ; 10 11 import com.tirsen.nanning.Invocation; 12 import com.tirsen.nanning.MethodInterceptor; 13 import com.tirsen.nanning.attribute.Attributes; 14 import ognl.MethodFailedException; 15 import ognl.Ognl; 16 import org.apache.commons.logging.Log; 17 import org.apache.commons.logging.LogFactory; 18 19 27 public class ContractInterceptor implements MethodInterceptor { 28 private static final Log logger = LogFactory.getLog(ContractInterceptor.class); 29 private static final Pattern oldPattern = 30 Pattern.compile("(.*)\\{old (.*?)}(.*)"); 31 32 35 private ThreadLocal checkContracts = new ThreadLocal (); 36 37 public Object invoke(Invocation invocation) throws Throwable { 38 String ensures = Attributes.getAttribute(invocation.getMethod(), "ensures"); 39 String requires = Attributes.getAttribute(invocation.getMethod(), "requires"); 40 String invariant = Attributes.getAttribute(invocation.getMethod().getDeclaringClass(), "invariant"); 41 42 StringBuffer parsedEnsure = null; 43 List oldValues = null; 44 45 if (checkContracts.get() == null) { 46 assertExpressionTrue(invocation, requires, 47 "precondition violated: {0}"); 48 49 if (ensures != null) { 51 oldValues = new ArrayList (); 52 parsedEnsure = new StringBuffer (); 53 Matcher matcher = oldPattern.matcher(ensures); 54 while (matcher.matches()) { 55 String head = matcher.group(1); 56 String old = matcher.group(2); 57 String tail = matcher.group(3); 58 oldValues.add(executeExpression(invocation, old)); 59 String oldRef = "#" + getOldReference(oldValues.size() - 1); 60 parsedEnsure.append(head + oldRef + tail); 61 matcher = oldPattern.matcher(tail); 62 } 63 if (oldValues.size() == 0) { 65 parsedEnsure.append(ensures); 66 } 67 } 68 } 69 70 Object result = invocation.invokeNext(); 71 72 if (checkContracts.get() == null) { 73 74 if (parsedEnsure != null) { 76 Map context = createContext(invocation); 77 for (ListIterator iterator = oldValues.listIterator(); iterator.hasNext();) { 78 Object oldValue = iterator.next(); 79 context.put(getOldReference(iterator.previousIndex()), oldValue); 80 } 81 82 assertExpressionTrue(parsedEnsure.toString(), 83 invocation.getProxy(), context, "postcondition violated: " + ensures); 84 } 85 86 assertExpressionTrue(invocation, invariant, "invariant violated: {0}"); 87 } 88 89 return result; 90 } 91 92 private static String getOldReference(int i) { 93 return "old" + i; 94 } 95 96 private Object executeExpression(Invocation invocation, String expression) { 97 Map context = createContext(invocation); 98 try { 99 return executeExpression(expression, invocation.getProxy(), context); 100 } catch (Exception e) { 101 throw new RuntimeException ("Could not execute: " + expression, e); 102 } 103 } 104 105 private void assertExpressionTrue(Invocation invocation, String expression, String message) { 106 if (expression != null) { 107 Map context = createContext(invocation); 108 assertExpressionTrue(expression, invocation.getProxy(), context, MessageFormat.format(message, new Object []{expression})); 109 } 110 } 111 112 private static Map createContext(Invocation invocation) { 113 Map variables = Ognl.createDefaultContext(invocation.getProxy()); 114 variables.put("this", invocation.getProxy()); 115 Object [] args = invocation.getArgs(); 116 if (args != null) { 117 for (int i = 0; i < args.length; i++) { 118 Object arg = args[i]; 119 variables.put("arg" + i, arg); 120 } 121 } 122 return variables; 123 } 124 125 private void assertExpressionTrue(String expression, Object root, Map context, String message) { 126 if (checkContracts.get() == null) { 128 checkContracts.set(checkContracts); 129 try { 130 boolean result; 131 Boolean aBoolean = (Boolean ) executeExpression(expression, root, context); 132 result = aBoolean.booleanValue(); 133 if (!result) { 134 throw new AssertionError (message); 135 } 136 } catch (MethodFailedException e) { 137 if (e.getReason() instanceof Error ) { 138 throw (Error ) e.getReason(); 139 } else { 140 logger.error("Could not execute expression: " + expression); 141 throw new AssertionError ("Could not execute expression: " + expression); 142 } 143 } catch (Exception e) { 144 logger.error("Could not execute expression: " + expression); 145 throw new AssertionError ("Could not execute expression: " + expression); 146 } finally { 147 checkContracts.set(null); 148 } 149 } 150 } 151 152 private static Object executeExpression(String expression, Object root, Map context) throws Exception { 153 return Ognl.getValue(Ognl.parseExpression(expression), context, root); 154 } 155 } 156
| Popular Tags
|