UberInterceptorMetaClass.groovy
001 /*
002  * Copyright 2007-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 org.codehaus.griffon.runtime.builder
017 
018 import griffon.util.MethodUtils
019 import java.lang.reflect.InvocationTargetException
020 import org.codehaus.groovy.runtime.InvokerHelper
021 import org.slf4j.Logger
022 import org.slf4j.LoggerFactory
023 
024 /**
025  @author Danno Ferrin
026  @author Andres Almiray
027  */
028 class UberInterceptorMetaClass extends DelegatingMetaClass {
029     private static final Logger LOG = LoggerFactory.getLogger(UberInterceptorMetaClass)
030     UberBuilder factory
031 
032     UberInterceptorMetaClass(MetaClass delegate, UberBuilder factory) {
033         super(delegate)
034         this.factory = factory
035     }
036 
037     private Object doInvokeInstanceMethod(Object object, String methodName, Object arguments) {
038         Class klass = object instanceof Class ? object : object.getClass()
039         try {
040             return MethodUtils.invokeMethod(object, methodName, arguments)
041         catch (NoSuchMethodException nsme) {
042             throw new MissingMethodException(methodName, klass, [argumentsas Object[])
043         catch (IllegalAccessException iae) {
044             throw new MissingMethodException(methodName, klass, [argumentsas Object[])
045         catch (InvocationTargetException ite) {
046             throw new MissingMethodException(methodName, klass, [argumentsas Object[])
047         }
048     }
049 
050     private Object doInvokeInstanceMethod(Object object, String methodName, Object[] arguments) {
051         Class klass = object instanceof Class ? object : object.getClass()
052         try {
053             return MethodUtils.invokeMethod(object, methodName, arguments)
054         catch (NoSuchMethodException nsme) {
055             throw new MissingMethodException(methodName, klass, arguments)
056         catch (IllegalAccessException iae) {
057             throw new MissingMethodException(methodName, klass, arguments)
058         catch (InvocationTargetException ite) {
059             throw new MissingMethodException(methodName, klass, arguments)
060         }
061     }
062 
063     private Object doInvokeStaticMethod(Object object, String methodName, Object[] arguments) {
064         Class klass = object instanceof Class ? object : object.getClass()
065         try {
066             return MethodUtils.invokeStaticMethod(klass, methodName, arguments)
067         catch (NoSuchMethodException nsme) {
068             throw new MissingMethodException(methodName, klass, arguments)
069         catch (IllegalAccessException iae) {
070             throw new MissingMethodException(methodName, klass, arguments)
071         catch (InvocationTargetException ite) {
072             throw new MissingMethodException(methodName, klass, arguments)
073         }
074     }
075 
076     private Object invokeFactoryMethod(String methodName, Object arguments, MissingMethodException mme) {
077         try {
078             return factory.invokeMethod(methodName, arguments)
079         catch (MissingMethodException mme2) {
080             if (mme2.method != methodName) {
081                 throw mme2
082             }
083             // chain secondary exception
084             Throwable root = mme
085             while (root.getCause() != null) {
086                 root = root.getCause()
087             }
088             root.initCause(mme2)
089             // throw original
090             throw mme
091         }
092     }
093 
094     private Object invokeFactoryMethod(String methodName, Object[] arguments, MissingMethodException mme) {
095         try {
096             return factory.invokeMethod(methodName, arguments)
097         catch (MissingMethodException mme2) {
098             if (mme2.method != methodName) {
099                 throw mme2
100             }
101             // chain secondary exception
102             Throwable root = mme
103             while (root.getCause() != null) {
104                 root = root.getCause()
105             }
106             root.initCause(mme2)
107             // throw original
108             throw mme
109         }
110     }
111 
112     private void exceptionIfMethodNotFound(String methodName, MissingMethodException mme) {
113         if (mme.method != methodName) {
114             throw mme
115         }
116     }
117 
118     Object invokeMethod(Object object, String methodName, Object arguments) {
119         // try {
120         //     return invokeMethod(object, methodName, arguments);
121         // } catch (MissingMethodException mme) {
122         //     exceptionIfMethodNotFound(methodName, mme);
123         try {
124             return delegate.invokeMethod(object, methodName, arguments)
125         catch (MissingMethodException mme2) {
126             exceptionIfMethodNotFound(methodName, mme2);
127             // attempt method resolution
128             for (UberBuilderRegistration reg in factory.builderRegistration) {
129                 try {
130                     def builder = reg.builder
131                     if (!builder.getMetaClass().respondsTo(builder, methodName).isEmpty()) {
132                         return InvokerHelper.invokeMethod(builder, methodName, arguments)
133                     }
134                 catch (MissingMethodException mme3) {
135                     exceptionIfMethodNotFound(methodName, mme3);
136                     // drop the exception, there will be many
137                 }
138             }
139             // dispatch to factories if it is not a literal method
140             return invokeFactoryMethod(methodName, arguments, mme2)
141         }
142         // }
143     }
144 
145     Object invokeMethod(Object object, String methodName, Object[] arguments) {
146         // try {
147         //     return invokeMethod(object, methodName, arguments);
148         // } catch (MissingMethodException mme) {
149         //     exceptionIfMethodNotFound(methodName, mme);
150         try {
151             return delegate.invokeMethod(object, methodName, arguments)
152         catch (MissingMethodException mme2) {
153             exceptionIfMethodNotFound(methodName, mme2);
154             // attempt method resolution
155             for (UberBuilderRegistration reg in factory.builderRegistration) {
156                 try {
157                     def builder = reg.builder
158                     if (!builder.getMetaClass().respondsTo(builder, methodName).isEmpty()) {
159                         return InvokerHelper.invokeMethod(builder, methodName, arguments)
160                     }
161                 catch (MissingMethodException mme3) {
162                     exceptionIfMethodNotFound(methodName, mme3);
163                     // drop the exception, there will be many
164                 }
165             }
166             // dispatch to factories if it is not a literal method
167             return invokeFactoryMethod(methodName, arguments, mme2)
168         }
169         // }
170     }
171 
172     Object invokeStaticMethod(Object object, String methodName, Object[] arguments) {
173         try {
174             if (object instanceof Class) {
175                 return doInvokeInstanceMethod(object, methodName, arguments)
176             else {
177                 return doInvokeStaticMethod(object, methodName, arguments)
178             }
179         catch (MissingMethodException mme) {
180             exceptionIfMethodNotFound(methodName, mme);
181             try {
182                 return delegate.invokeMethod(object, methodName, arguments)
183             catch (MissingMethodException mme2) {
184                 exceptionIfMethodNotFound(methodName, mme2);
185 
186                 // attempt method resolution
187                 for (UberBuilderRegistration reg in factory.builderRegistration) {
188                     try {
189                         def builder = reg.builder
190                         if (!builder.getMetaClass().respondsTo(builder, methodName).isEmpty()) {
191                             return InvokerHelper.invokeMethod(builder, methodName, arguments)
192                         }
193                     catch (MissingMethodException mme3) {
194                         exceptionIfMethodNotFound(methodName, mme3);
195 
196                         // drop the exception, there will be many
197                     }
198                 }
199                 // dispatch to factories if it is not a literal method
200                 return invokeFactoryMethod(methodName, arguments, mme2)
201             }
202         }
203     }
204 
205     Object getProperty(Object o, String s) {
206         try {
207             return super.getProperty(o, s)
208         catch (MissingPropertyException mpe) {
209             return factory.getProperty(s)
210         }
211     }
212 
213     void setProperty(Object o, String s, Object o1) {
214         try {
215             super.setProperty(o, s, o1)
216         catch (MissingPropertyException mpe) {
217             factory.setProperty(s, o1)
218         }
219     }
220 }