AbstractClosureProxy.java
001 /* 
002  * Copyright 2008-2012 the original author or authors.
003  *
004  * Licensed under the Apache License, Version 2.0 (the "License");
005  * you may not use this file except in compliance with the License.
006  * You may obtain a copy of the License at
007  *
008  *      http://www.apache.org/licenses/LICENSE-2.0
009  *
010  * Unless required by applicable law or agreed to in writing, software
011  * distributed under the License is distributed on an "AS IS" BASIS,
012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013  * See the License for the specific language governing permissions and
014  * limitations under the License.
015  */
016 package griffon.test;
017 
018 import groovy.lang.Closure;
019 
020 /**
021  * Skeleton implementation of a wrapper class for closures that allows
022  * you to intercept invocations of the closure. The wrapper can be used
023  * anywhere that the target closure can be used.
024  */
025 @SuppressWarnings("serial")
026 public abstract class AbstractClosureProxy extends Closure {
027     private Closure target;
028 
029     /**
030      * Creates a new instance that wraps the target closure and sends
031      * profiling events to the given profiler log.
032      @param closure The target closure to wrap.
033      */
034     public AbstractClosureProxy(Closure closure) {
035         super(closure.getOwner(), closure.getThisObject());
036         target = closure;
037     }
038 
039     /**
040      * This method is called before the target closure is invoked.
041      * This is a passive interceptor, so you cannot prevent the
042      * call to the target closure. You can modify the arguments,
043      * though, but it's not recommended unless you really know
044      * what you're doing.
045      @param args The arguments passed to the closure.
046      */
047     protected abstract void doBeforeCall(Object[] args);
048 
049     /**
050      * This method is called after the target closure is invoked.
051      * It will be triggered whether or not an exception is thrown
052      * by the target closure.
053      @param args The arguments passed to the closure.
054      */
055     protected abstract void doAfterCall(Object[] args);
056 
057     /**
058      * Called when a new instance of the proxy needs to be created for
059      * the given closure. Usually the implementation simply creates a
060      * new instance of the current class, copying over the existing
061      * proxy properties:
062      <pre>
063      *    return new MyClosureProxy(c, this.field1, ...)
064      </pre>
065      @param c The closure to wrap/proxy.
066      */
067     protected abstract Closure createWrapper(Closure c);
068 
069     /**
070      * This is the important one: logs entry and exit of the closure call.
071      */
072     @Override
073     public Object call(Object[] objects) {
074         doBeforeCall(objects);
075 
076         try {
077             return target.call(objects);
078         }
079         finally {
080             doAfterCall(objects);
081         }
082     }
083 
084     /**
085      * Compares based on identities, but unlike the standard implementation
086      * this one will return <code>true</code> if the given object is the
087      * target closure for this wrapper as well.
088      */
089     @Override
090     public boolean equals(Object obj) {
091         return this == obj || target == obj;
092     }
093 
094     @Override
095     public int hashCode() {
096         return target.hashCode();
097     }
098 
099     @Override
100     public Closure curry(Object[] objects) {
101         return createWrapper(target.curry(objects));
102     }
103 
104     @Override
105     public boolean isCase(Object o) {
106         return target.isCase(o);
107     }
108 
109     @Override
110     public Closure asWritable() {
111         return target.asWritable();
112     }
113 
114     @Override
115     public Object getProperty(String property) {
116         return target.getProperty(property);
117     }
118 
119     @Override
120     public void setProperty(String s, Object o) {
121         target.setProperty(s, o);
122     }
123 
124     @Override
125     public int getMaximumNumberOfParameters() {
126         return target.getMaximumNumberOfParameters();
127     }
128 
129     @Override
130     public Class<?>[] getParameterTypes() {
131         return target.getParameterTypes();
132     }
133 
134     @Override
135     public Object getDelegate() {
136         return target.getDelegate();
137     }
138 
139     @Override
140     public void setDelegate(Object o) {
141         target.setDelegate(o);
142     }
143 
144     @Override
145     public int getDirective() {
146         return target.getDirective();
147     }
148 
149     @Override
150     public void setDirective(int i) {
151         target.setDirective(i);
152     }
153 
154     @Override
155     public int getResolveStrategy() {
156         return target.getResolveStrategy();
157     }
158 
159     @Override
160     public void setResolveStrategy(int i) {
161         target.setResolveStrategy(i);
162     }
163 }