1 /* Copyright 2008 the original author or authors.
2  *
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *      http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 package grails.test;
16 
17 import groovy.lang.Closure;
18 
19 /**
20  * Skeleton implementation of a wrapper class for closures that allows
21  * you to intercept invocations of the closure. The wrapper can be used
22  * anywhere that the target closure can be used.
23  */
24 @SuppressWarnings("serial")
25 public abstract class AbstractClosureProxy extends Closure {
26 
27     private Closure target;
28 
29     /**
30      * Creates a new instance that wraps the target closure and sends
31      * profiling events to the given profiler log.
32      * @param closure The target closure to wrap.
33      */
AbstractClosureProxy(Closure closure)34     public AbstractClosureProxy(Closure closure) {
35         super(closure.getOwner(), closure.getThisObject());
36         target = closure;
37     }
38 
39     /**
40      * This method is called before the target closure is invoked.
41      * This is a passive interceptor, so you cannot prevent the
42      * call to the target closure. You can modify the arguments,
43      * though, but it's not recommended unless you really know
44      * what you're doing.
45      * @param args The arguments passed to the closure.
46      */
doBeforeCall(Object[] args)47     protected abstract void doBeforeCall(Object[] args);
48 
49     /**
50      * This method is called after the target closure is invoked.
51      * It will be triggered whether or not an exception is thrown
52      * by the target closure.
53      * @param args The arguments passed to the closure.
54      */
doAfterCall(Object[] args)55     protected abstract void doAfterCall(Object[] args);
56 
57     /**
58      * Called when a new instance of the proxy needs to be created for
59      * the given closure. Usually the implementation simply creates a
60      * new instance of the current class, copying over the existing
61      * proxy properties:
62      * <pre>
63      *    return new MyClosureProxy(c, this.field1, ...)
64      * </pre>
65      * @param c The closure to wrap/proxy.
66      */
createWrapper(Closure c)67     protected abstract Closure createWrapper(Closure c);
68 
69     /**
70      * This is the important one: logs entry and exit of the closure call.
71      */
72     @Override
call(Object[] objects)73     public Object call(Object[] objects) {
74         doBeforeCall(objects);
75 
76         try {
77             return target.call(objects);
78         }
79         finally {
80             doAfterCall(objects);
81         }
82     }
83 
84     /**
85      * Compares based on identities, but unlike the standard implementation
86      * this one will return <code>true</code> if the given object is the
87      * target closure for this wrapper as well.
88      */
89     @Override
equals(Object obj)90     public boolean equals(Object obj) {
91         return this == obj || target == obj;
92     }
93 
94     @Override
hashCode()95     public int hashCode() {
96         return target.hashCode();
97     }
98 
99     @Override
curry(Object[] objects)100     public Closure curry(Object[] objects) {
101         return createWrapper(target.curry(objects));
102     }
103 
104     @Override
isCase(Object o)105     public boolean isCase(Object o) {
106         return target.isCase(o);
107     }
108 
109     @Override
asWritable()110     public Closure asWritable() {
111         return target.asWritable();
112     }
113 
114     @Override
getProperty(String property)115     public Object getProperty(String property) {
116         return target.getProperty(property);
117     }
118 
119     @Override
setProperty(String s, Object o)120     public void setProperty(String s, Object o) {
121         target.setProperty(s, o);
122     }
123 
124     @Override
getMaximumNumberOfParameters()125     public int getMaximumNumberOfParameters() {
126         return target.getMaximumNumberOfParameters();
127     }
128 
129     @Override
getParameterTypes()130     public Class<?>[] getParameterTypes() {
131         return target.getParameterTypes();
132     }
133 
134     @Override
getDelegate()135     public Object getDelegate() {
136         return target.getDelegate();
137     }
138 
139     @Override
setDelegate(Object o)140     public void setDelegate(Object o) {
141         target.setDelegate(o);
142     }
143 
144     @Override
getDirective()145     public int getDirective() {
146         return target.getDirective();
147     }
148 
149     @Override
setDirective(int i)150     public void setDirective(int i) {
151         target.setDirective(i);
152     }
153 
154     @Override
getResolveStrategy()155     public int getResolveStrategy() {
156         return target.getResolveStrategy();
157     }
158 
159     @Override
setResolveStrategy(int i)160     public void setResolveStrategy(int i) {
161         target.setResolveStrategy(i);
162     }
163 }
164