2 * Copyright 2004-2005 the original author or authors.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package org
.codehaus
.groovy
.grails
.commons
.metaclass
;
18 import org
.apache
.commons
.lang
.ArrayUtils
;
19 import org
.apache
.commons
.logging
.Log
;
20 import org
.apache
.commons
.logging
.LogFactory
;
22 import groovy
.lang
.MissingMethodException
;
24 import java
.beans
.IntrospectionException
;
30 * This class provides the base implementation responsible for performing dynamic method invocation such as the dynamic
33 * @author Steven Devijver
34 * @author Graeme Rocher
38 * Created: Aug 7, 2005
40 public abstract class AbstractDynamicMethods
implements DynamicMethods
{
42 protected Collection dynamicMethodInvocations
= null;
43 protected Collection staticMethodInvocations
= null;
44 protected Collection dynamicConstructors
= null;
45 protected Map dynamicProperties
= null;
46 protected Class clazz
= null;
48 private static final Log LOG
= LogFactory
.getLog(AbstractDynamicMethods
.class);
51 * Creates and registers a DelegatingMetaClass instance in the registry that delegates to this class
54 * @throws IntrospectionException
56 public AbstractDynamicMethods(Class theClass
)
57 throws IntrospectionException
{
62 * Creates and optionally registers a DelegatingMetaClass in the MetaClasRegistry that delegates to this class
65 * @throws IntrospectionException
67 public AbstractDynamicMethods(Class theClass
, boolean inRegistry
)
68 throws IntrospectionException
{
70 this.clazz
= theClass
;
71 this.dynamicMethodInvocations
= new ArrayList();
72 this.staticMethodInvocations
= new ArrayList();
73 this.dynamicProperties
= new HashMap();
74 this.dynamicConstructors
= new ArrayList();
78 * @see org.codehaus.groovy.grails.commons.metaclass.DynamicMethods#addDynamicConstructor(org.codehaus.groovy.grails.commons.metaclass.DynamicConstructor)
80 public void addDynamicConstructor(DynamicConstructor constructor
) {
81 this.dynamicConstructors
.add(constructor
);
85 * A non-registering constructor that simple creates an instance
88 public AbstractDynamicMethods() {
89 this.dynamicMethodInvocations
= new ArrayList();
90 this.staticMethodInvocations
= new ArrayList();
91 this.dynamicProperties
= new HashMap();
92 this.dynamicConstructors
= new ArrayList();
96 * @see org.codehaus.groovy.grails.metaclass.DynamicMethods#addDynamicMethodInvocation(org.codehaus.groovy.grails.metaclass.DynamicMethodInvocation)
98 public void addDynamicMethodInvocation(DynamicMethodInvocation methodInvocation
) {
99 this.dynamicMethodInvocations
.add(methodInvocation
);
103 * @see org.codehaus.groovy.grails.metaclass.DynamicMethods#addStaticMethodInvocation(org.codehaus.groovy.grails.metaclass.StaticMethodInvocation)
105 public void addStaticMethodInvocation(StaticMethodInvocation methodInvocation
) {
106 this.staticMethodInvocations
.add(methodInvocation
);
110 * @see org.codehaus.groovy.grails.metaclass.DynamicMethods#addDynamicProperty(org.codehaus.groovy.grails.metaclass.DynamicProperty)
112 public void addDynamicProperty(DynamicProperty property
) {
113 this.dynamicProperties
.put(property
.getPropertyName(), property
);
117 * @see org.codehaus.groovy.grails.metaclass.DynamicMethods#getProperty(java.lang.Object, java.lang.String, org.codehaus.groovy.grails.metaclass.InvocationCallback)
119 public Object
getProperty(Object object
, String propertyName
, InvocationCallback callback
) {
120 DynamicProperty getter
= (DynamicProperty
)this.dynamicProperties
.get(propertyName
);
121 if (getter
!= null && getter
.isPropertyMatch(propertyName
)) {
122 callback
.markInvoked();
123 return getter
.get(object
);
128 * @see org.codehaus.groovy.grails.metaclass.DynamicMethods#setProperty(java.lang.Object, java.lang.String, java.lang.Object, org.codehaus.groovy.grails.metaclass.InvocationCallback)
130 public void setProperty(Object object
, String propertyName
,Object newValue
, InvocationCallback callback
) {
131 DynamicProperty setter
= (DynamicProperty
)this.dynamicProperties
.get(propertyName
);
132 if (setter
!= null && setter
.isPropertyMatch(propertyName
)) {
133 callback
.markInvoked();
134 setter
.set(object
,newValue
);
138 * @see org.codehaus.groovy.grails.metaclass.DynamicMethods#invokeMethod(java.lang.Object, java.lang.String, java.lang.Object[], org.codehaus.groovy.grails.metaclass.InvocationCallback)
140 public Object
invokeMethod(Object object
, String methodName
,
141 Object
[] arguments
, InvocationCallback callback
) {
142 if(LOG
.isTraceEnabled()) {
143 LOG
.debug("[DynamicMethods] Attempting invocation of dynamic method ["+methodName
+"] on target ["+object
+"] with arguments ["+ArrayUtils
.toString( arguments
)+"]");
145 for (Iterator iter
= this.dynamicMethodInvocations
.iterator(); iter
.hasNext();) {
146 DynamicMethodInvocation methodInvocation
= (DynamicMethodInvocation
)iter
.next();
147 if (methodInvocation
.isMethodMatch(methodName
)) {
148 if(LOG
.isDebugEnabled()) {
149 LOG
.debug("[DynamicMethods] Dynamic method ["+methodName
+"] matched, attempting to invoke.");
153 Object result
= methodInvocation
.invoke(object
, methodName
,arguments
);
154 if(LOG
.isDebugEnabled()) {
155 LOG
.debug("[DynamicMethods] Instance method ["+methodName
+"] invoked successfully with result ["+result
+"]. Marking as invoked");
157 callback
.setInvoker(methodInvocation
);
158 callback
.markInvoked();
160 } catch (MissingMethodException e
) {
161 if(LOG
.isDebugEnabled()) {
162 LOG
.debug("[DynamicMethods] Instance method ["+methodName
+"] threw MissingMethodException. Returning null and falling back to standard MetaClass",e
);
174 * @see org.codehaus.groovy.grails.commons.metaclass.DynamicMethods#invokeConstructor(java.lang.Object[], org.codehaus.groovy.grails.commons.metaclass.InvocationCallback)
176 public Object
invokeConstructor(Object
[] arguments
, InvocationCallback callBack
) {
177 if(LOG
.isDebugEnabled()) {
178 LOG
.debug("[DynamicMethods] Attempting invocation of dynamic constructor with arguments ["+ArrayUtils
.toString( arguments
)+"]");
181 for (Iterator i
= this.dynamicConstructors
.iterator(); i
.hasNext();) {
182 DynamicConstructor constructor
= (DynamicConstructor
) i
.next();
183 if(constructor
.isArgumentsMatch(arguments
)) {
184 if(LOG
.isDebugEnabled()) {
185 LOG
.debug("[DynamicMethods] Dynamic constructor found, marked and invoking...");
187 callBack
.markInvoked();
188 return constructor
.invoke(this.clazz
,arguments
);
195 * @see org.codehaus.groovy.grails.metaclass.DynamicMethods#invokeStaticMethod(java.lang.Object, java.lang.String, java.lang.Object[], org.codehaus.groovy.grails.metaclass.InvocationCallback)
197 public Object
invokeStaticMethod(Object object
, String methodName
,
198 Object
[] arguments
, InvocationCallback callBack
) {
199 if(LOG
.isDebugEnabled()) {
200 LOG
.debug("[DynamicMethods] Attempting invocation of dynamic static method ["+methodName
+"] on target ["+object
+"] with arguments ["+ArrayUtils
.toString( arguments
)+"]");
201 //LOG.debug("[DynamicMethods] Registered dynamic static methods: ["+this.staticMethodInvocations+"]");
203 for (Iterator iter
= this.staticMethodInvocations
.iterator(); iter
.hasNext();) {
204 StaticMethodInvocation methodInvocation
= (StaticMethodInvocation
)iter
.next();
205 if (methodInvocation
.isMethodMatch(methodName
)) {
206 if(LOG
.isDebugEnabled()) {
207 LOG
.debug("[DynamicMethods] Static method matched, attempting to invoke");
211 Object result
= methodInvocation
.invoke(this.clazz
, methodName
, arguments
);
213 if(LOG
.isDebugEnabled()) {
214 LOG
.debug("[DynamicMethods] Static method ["+methodName
+"] invoked successfully with result ["+result
+"]. Marking as invoked");
216 callBack
.markInvoked();
218 } catch (MissingMethodException e
) {
219 if(LOG
.isDebugEnabled()) {
220 LOG
.debug("[DynamicMethods] Static method ["+methodName
+"] threw MissingMethodException. Returning null and falling back to standard MetaClass",e
);
229 public DynamicProperty
getDynamicProperty(String propertyName
) {
230 return (DynamicProperty
)this.dynamicProperties
.get(propertyName
);
233 public DynamicMethodInvocation
getDynamicMethod(String method_signature
) {
234 for (Iterator iter
= this.dynamicMethodInvocations
.iterator(); iter
.hasNext();) {
235 DynamicMethodInvocation methodInvocation
= (DynamicMethodInvocation
)iter
.next();
236 if (methodInvocation
.isMethodMatch(method_signature
)) {
238 return methodInvocation
;