KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > tirsen > nanning > contract > ContractInterceptor


1 package com.tirsen.nanning.contract;
2
3 import java.text.MessageFormat JavaDoc;
4 import java.util.ArrayList JavaDoc;
5 import java.util.List JavaDoc;
6 import java.util.ListIterator JavaDoc;
7 import java.util.Map JavaDoc;
8 import java.util.regex.Matcher JavaDoc;
9 import java.util.regex.Pattern JavaDoc;
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 /**
20  * TODO document ContractInterceptor.
21  * Tip: use <code>Class.desiredAssertionStatus()</code> to check wheather to addLink this interceptor or not, that way
22  * you can enable and disable contract-checking in the same way you enable and disable assertions (java -ea and so on).
23  *
24  * @author <a HREF="mailto:jon_tirsen@yahoo.com">Jon Tirsén</a>
25  * @version $Revision: 1.9 $
26  */

27 public class ContractInterceptor implements MethodInterceptor {
28     private static final Log logger = LogFactory.getLog(ContractInterceptor.class);
29     private static final Pattern JavaDoc oldPattern =
30             Pattern.compile("(.*)\\{old (.*?)}(.*)");
31
32     /**
33      * If this is non-null don't execute contracts, used when executing the expressions.
34      */

35     private ThreadLocal JavaDoc checkContracts = new ThreadLocal JavaDoc();
36
37     public Object JavaDoc invoke(Invocation invocation) throws Throwable JavaDoc {
38         String JavaDoc ensures = Attributes.getAttribute(invocation.getMethod(), "ensures");
39         String JavaDoc requires = Attributes.getAttribute(invocation.getMethod(), "requires");
40         String JavaDoc invariant = Attributes.getAttribute(invocation.getMethod().getDeclaringClass(), "invariant");
41
42         StringBuffer JavaDoc parsedEnsure = null;
43         List JavaDoc oldValues = null;
44
45         if (checkContracts.get() == null) {
46             assertExpressionTrue(invocation, requires,
47                                  "precondition violated: {0}");
48
49             // execute and remove the old-references
50
if (ensures != null) {
51                 oldValues = new ArrayList JavaDoc();
52                 parsedEnsure = new StringBuffer JavaDoc();
53                 Matcher JavaDoc matcher = oldPattern.matcher(ensures);
54                 while (matcher.matches()) {
55                     String JavaDoc head = matcher.group(1);
56                     String JavaDoc old = matcher.group(2);
57                     String JavaDoc tail = matcher.group(3);
58                     oldValues.add(executeExpression(invocation, old));
59                     String JavaDoc oldRef = "#" + getOldReference(oldValues.size() - 1);
60                     parsedEnsure.append(head + oldRef + tail);
61                     matcher = oldPattern.matcher(tail);
62                 }
63                 // if there wasn't any old-references just addLink all of the expression
64
if (oldValues.size() == 0) {
65                     parsedEnsure.append(ensures);
66                 }
67             }
68         }
69
70         Object JavaDoc result = invocation.invokeNext();
71
72         if (checkContracts.get() == null) {
73
74             // check ensures with old-references
75
if (parsedEnsure != null) {
76                 Map JavaDoc context = createContext(invocation);
77                 for (ListIterator JavaDoc iterator = oldValues.listIterator(); iterator.hasNext();) {
78                     Object JavaDoc 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 JavaDoc getOldReference(int i) {
93         return "old" + i;
94     }
95
96     private Object JavaDoc executeExpression(Invocation invocation, String JavaDoc expression) {
97         Map JavaDoc context = createContext(invocation);
98         try {
99             return executeExpression(expression, invocation.getProxy(), context);
100         } catch (Exception JavaDoc e) {
101             throw new RuntimeException JavaDoc("Could not execute: " + expression, e);
102         }
103     }
104
105     private void assertExpressionTrue(Invocation invocation, String JavaDoc expression, String JavaDoc message) {
106         if (expression != null) {
107             Map JavaDoc context = createContext(invocation);
108             assertExpressionTrue(expression, invocation.getProxy(), context, MessageFormat.format(message, new Object JavaDoc[]{expression}));
109         }
110     }
111
112     private static Map JavaDoc createContext(Invocation invocation) {
113         Map JavaDoc variables = Ognl.createDefaultContext(invocation.getProxy());
114         variables.put("this", invocation.getProxy());
115         Object JavaDoc[] args = invocation.getArgs();
116         if (args != null) {
117             for (int i = 0; i < args.length; i++) {
118                 Object JavaDoc arg = args[i];
119                 variables.put("arg" + i, arg);
120             }
121         }
122         return variables;
123     }
124
125     private void assertExpressionTrue(String JavaDoc expression, Object JavaDoc root, Map JavaDoc context, String JavaDoc message) {
126         // disable execution of contracts when contracts are executed (to avoid looping)
127
if (checkContracts.get() == null) {
128             checkContracts.set(checkContracts);
129             try {
130                 boolean result;
131                 Boolean JavaDoc aBoolean = (Boolean JavaDoc) executeExpression(expression, root, context);
132                 result = aBoolean.booleanValue();
133                 if (!result) {
134                     throw new AssertionError JavaDoc(message);
135                 }
136             } catch (MethodFailedException e) {
137                 if (e.getReason() instanceof Error JavaDoc) {
138                     throw (Error JavaDoc) e.getReason();
139                 } else {
140                     logger.error("Could not execute expression: " + expression);
141                     throw new AssertionError JavaDoc("Could not execute expression: " + expression);
142                 }
143             } catch (Exception JavaDoc e) {
144                 logger.error("Could not execute expression: " + expression);
145                 throw new AssertionError JavaDoc("Could not execute expression: " + expression);
146             } finally {
147                 checkContracts.set(null);
148             }
149         }
150     }
151
152     private static Object JavaDoc executeExpression(String JavaDoc expression, Object JavaDoc root, Map JavaDoc context) throws Exception JavaDoc {
153         return Ognl.getValue(Ognl.parseExpression(expression), context, root);
154     }
155 }
156
Popular Tags