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 }
|