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