001: /*
002: * JBoss, Home of Professional Open Source.
003: * Copyright 2006, Red Hat Middleware LLC, and individual contributors
004: * as indicated by the @author tags. See the copyright.txt file in the
005: * distribution for a full listing of individual contributors.
006: *
007: * This is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as
009: * published by the Free Software Foundation; either version 2.1 of
010: * the License, or (at your option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this software; if not, write to the Free
019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021: */
022: package org.jboss.aspects.dbc;
023:
024: import java.lang.reflect.Constructor;
025: import java.lang.reflect.Method;
026: import java.lang.reflect.Modifier;
027:
028: import org.jboss.aop.joinpoint.ConstructorCalledByConstructorInvocation;
029: import org.jboss.aop.joinpoint.ConstructorCalledByMethodInvocation;
030: import org.jboss.aop.joinpoint.ConstructorInvocation;
031: import org.jboss.aop.joinpoint.Invocation;
032: import org.jboss.aop.joinpoint.MethodCalledByConstructorInvocation;
033: import org.jboss.aop.joinpoint.MethodCalledByMethodInvocation;
034: import org.jboss.aop.joinpoint.MethodInvocation;
035: import org.jboss.aspects.dbc.condition.ConstructorConditionManager;
036: import org.jboss.aspects.dbc.condition.ExecutableCondition;
037: import org.jboss.aspects.dbc.condition.InvariantCondition;
038: import org.jboss.aspects.dbc.condition.MethodConditionManager;
039:
040: /**
041: * TODO:
042: * -Once version of beanshell in cvs allows importObject() (2.0, currently in beta),
043: * make invariants use that, so don't have to use $tgt for class invariants
044: * -Add $old funtionality
045: *
046: * @author <a href="mailto:kabir.khan@jboss.org">Kabir Khan</a>
047: * @version $Revision: 57186 $
048: */
049: public class DesignByContractAspect {
050: public static boolean verbose;
051:
052: ExecutableCondition[] preconditions;
053: ExecutableCondition[] postconditions;
054: InvariantCondition[] invariants;
055:
056: Method method;
057: Constructor constructor;
058: boolean isPublic;
059: boolean isStatic;
060: boolean isSynchronized;
061:
062: boolean initialised;
063:
064: //Keep track of if this checks have already been made for this joinpoint
065: //as the result of previous checks on the stack
066: ThreadLocal done = new ThreadLocal();
067:
068: public DesignByContractAspect() {
069: done.set(Boolean.FALSE);
070: }
071:
072: public void setVerbose(boolean vbs) {
073: verbose = vbs;
074: }
075:
076: public boolean getVerbose() {
077: return verbose;
078: }
079:
080: public Object invoke(MethodInvocation invocation) throws Throwable {
081: if (!initialised) {
082: initialise(invocation.getMethod());
083: }
084: Object[] args = invocation.getArguments();
085: return invoke(invocation, args);
086: }
087:
088: public Object invoke(MethodCalledByMethodInvocation invocation)
089: throws Throwable {
090: if (!initialised) {
091: initialise(invocation.getCalledMethod());
092: }
093: Object[] args = invocation.getArguments();
094: return invoke(invocation, args);
095: }
096:
097: public Object invoke(MethodCalledByConstructorInvocation invocation)
098: throws Throwable {
099: if (!initialised) {
100: initialise(invocation.getCalledMethod());
101: }
102: Object[] args = invocation.getArguments();
103: return invoke(invocation, args);
104: }
105:
106: public Object invoke(ConstructorInvocation invocation)
107: throws Throwable {
108: if (!initialised) {
109: initialise(invocation.getConstructor());
110: }
111: Object[] args = invocation.getArguments();
112: return invoke(invocation, args);
113: }
114:
115: public Object invoke(ConstructorCalledByMethodInvocation invocation)
116: throws Throwable {
117: if (!initialised) {
118: initialise(invocation.getCalledConstructor());
119: }
120: Object[] args = invocation.getArguments();
121: return invoke(invocation, args);
122: }
123:
124: public Object invoke(
125: ConstructorCalledByConstructorInvocation invocation)
126: throws Throwable {
127: if (!initialised) {
128: initialise(invocation.getCalledConstructor());
129: }
130: Object[] args = invocation.getArguments();
131: return invoke(invocation, args);
132: }
133:
134: private Object invoke(Invocation invocation, Object[] args)
135: throws Throwable {
136: if (isSynchronized) {
137: if (isStatic) {
138: synchronized (method.getDeclaringClass()) {
139: return doInvoke(invocation, args);
140: }
141: } else {
142: synchronized (invocation.getTargetObject()) {
143: return doInvoke(invocation, args);
144: }
145: }
146: }
147: return doInvoke(invocation, args);
148: }
149:
150: private Object doInvoke(Invocation invocation, Object[] args)
151: throws Throwable {
152: logStart();
153: Object ret = null;
154: boolean wasDone = ((Boolean) done.get()).booleanValue();
155:
156: try {
157: done.set(Boolean.TRUE);
158: if (!wasDone && isPublic && (constructor == null)) {
159: checkInvariants(invocation, null);
160: }
161: if (!wasDone) {
162: checkPreConditions(invocation, args);
163: }
164:
165: ret = invocation.invokeNext();
166:
167: if (!wasDone && isPublic) {
168: checkInvariants(invocation, ret);
169: checkPostConditions(invocation, args, ret);
170: }
171: } finally {
172: if (!wasDone) {
173: done.set(Boolean.FALSE);
174: }
175: }
176:
177: logEnd();
178: return ret;
179: }
180:
181: private void logStart() {
182: if (verbose) {
183: if (method != null) {
184: System.out.println("[dbc] ======= Invoking method: "
185: + method);
186: } else {
187: System.out
188: .println("[dbc] ======= Invoking constructor: "
189: + constructor);
190: }
191: }
192: }
193:
194: private void logEnd() {
195: if (verbose) {
196: if (method != null) {
197: System.out.println("[dbc] ======= Invoked method: "
198: + method);
199: } else {
200: System.out
201: .println("[dbc] ======= Invoked constructor: "
202: + constructor);
203: }
204: }
205: }
206:
207: private void initialise(Method m) {
208: method = m;
209: int modifiers = m.getModifiers();
210: initialise(modifiers);
211:
212: preconditions = MethodConditionManager.getPreConditions(m);
213: postconditions = MethodConditionManager.getPostConditions(m);
214:
215: if (isPublic) {
216: invariants = MethodConditionManager.getInvariants(m);
217: }
218: }
219:
220: private void initialise(Constructor c) {
221: constructor = c;
222: int modifiers = c.getModifiers();
223: initialise(modifiers);
224:
225: preconditions = ConstructorConditionManager.getPreConditions(c);
226: postconditions = ConstructorConditionManager
227: .getPostConditions(c);
228:
229: if (isPublic) {
230: invariants = ConstructorConditionManager.getInvariants(c);
231: }
232: }
233:
234: private void initialise(int modifiers) {
235: isSynchronized = Modifier.isSynchronized(modifiers);
236: isStatic = Modifier.isStatic(modifiers);
237: isPublic = Modifier.isPublic(modifiers);
238:
239: initialised = true;
240: }
241:
242: private void checkPreConditions(Invocation invocation, Object[] args) {
243: if (verbose)
244: System.out.println("[dbc] === checkPreconditions() for "
245: + ((method != null) ? method.toString()
246: : constructor.toString()));
247: for (int i = 0; i < preconditions.length; i++) {
248: preconditions[i].evaluateCondition(this , invocation, args,
249: null);
250: }
251: }
252:
253: private void checkPostConditions(Invocation invocation,
254: Object[] args, Object ret) {
255: if (verbose)
256: System.out.println("[dbc] === checkPostconditions() for "
257: + ((method != null) ? method.toString()
258: : constructor.toString()));
259: for (int i = 0; i < postconditions.length; i++) {
260: postconditions[i].evaluateCondition(this , invocation, args,
261: ret);
262: }
263: }
264:
265: private void checkInvariants(Invocation invocation, Object ret) {
266: if (verbose)
267: System.out.println("[dbc] === checkInvariants() for "
268: + ((method != null) ? method.toString()
269: : constructor.toString()));
270: boolean isConstructor = (constructor != null);
271: for (int i = 0; i < invariants.length; i++) {
272: invariants[i].evaluateCondition(invocation, isStatic,
273: isConstructor, ret);
274: }
275: }
276: }
|