GRAILS-1019: Allowing expressions to be used with the 'disabled' attribute for g...
[grails.git] / src / commons / org / codehaus / groovy / grails / commons / metaclass / AbstractDynamicMethods.java
blob14b6ee1434ed792580eebd51f4df99f1c003fbd4
1 /*
2 * Copyright 2004-2005 the original author or authors.
3 *
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
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
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.
15 */
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;
25 import java.util.*;
29 /**
30 * This class provides the base implementation responsible for performing dynamic method invocation such as the dynamic
31 * finders in GORM
33 * @author Steven Devijver
34 * @author Graeme Rocher
36 * @since 0.1
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);
50 /**
51 * Creates and registers a DelegatingMetaClass instance in the registry that delegates to this class
53 * @param theClass
54 * @throws IntrospectionException
56 public AbstractDynamicMethods(Class theClass)
57 throws IntrospectionException {
58 this(theClass, true);
61 /**
62 * Creates and optionally registers a DelegatingMetaClass in the MetaClasRegistry that delegates to this class
63 * @param theClass
64 * @param inRegistry
65 * @throws IntrospectionException
67 public AbstractDynamicMethods(Class theClass, boolean inRegistry)
68 throws IntrospectionException {
69 super();
70 this.clazz = theClass;
71 this.dynamicMethodInvocations = new ArrayList();
72 this.staticMethodInvocations = new ArrayList();
73 this.dynamicProperties = new HashMap();
74 this.dynamicConstructors = new ArrayList();
77 /* (non-Javadoc)
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);
84 /**
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();
95 /* (non-Javadoc)
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);
102 /* (non-Javadoc)
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);
109 /* (non-Javadoc)
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);
116 /* (non-Javadoc)
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);
125 return null;
127 /* (non-Javadoc)
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);
137 /* (non-Javadoc)
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.");
152 try {
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();
159 return result;
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);
164 return null;
168 return null;
173 /* (non-Javadoc)
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);
191 return null;
194 /* (non-Javadoc)
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");
210 try {
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();
217 return result;
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);
222 return null;
226 return null;
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;
241 return null;