All Downloads are FREE. Search and download functionalities are using the official Maven repository.

groovy.lang.ProxyMetaClass Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2003-2013 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package groovy.lang;

import java.beans.IntrospectionException;

/**
 * As subclass of MetaClass, ProxyMetaClass manages calls from Groovy Objects to POJOs.
 * It enriches MetaClass with the feature of making method invokations interceptable by
 * an Interceptor. To this end, it acts as a decorator (decorator pattern) allowing
 * to add or withdraw this feature at runtime.
 * See groovy/lang/InterceptorTest.groovy for details.
 * 

* WARNING: This implementation of ProxyMetaClass is NOT thread-safe and hence should only be used for * as a per-instance MetaClass running in a single thread. Do not place this MetaClass in the MetaClassRegistry * as it will result in unpredictable behaviour * * @author Dierk Koenig * @author Graeme Rocher * @see groovy.lang.MetaClassRegistry */ public class ProxyMetaClass extends MetaClassImpl implements AdaptingMetaClass { protected MetaClass adaptee = null; protected Interceptor interceptor = null; /** * convenience factory method for the most usual case. */ public static ProxyMetaClass getInstance(Class theClass) throws IntrospectionException { MetaClassRegistry metaRegistry = GroovySystem.getMetaClassRegistry(); MetaClass meta = metaRegistry.getMetaClass(theClass); return new ProxyMetaClass(metaRegistry, theClass, meta); } /** * @param adaptee the MetaClass to decorate with interceptability */ public ProxyMetaClass(MetaClassRegistry registry, Class theClass, MetaClass adaptee) throws IntrospectionException { super(registry, theClass); this.adaptee = adaptee; if (null == adaptee) throw new IllegalArgumentException("adaptee must not be null"); super.initialize(); } public synchronized void initialize() { this.adaptee.initialize(); } /** * Use the ProxyMetaClass for the given Closure. * Cares for balanced register/unregister. * * @param closure piece of code to be executed with registered ProxyMetaClass */ public Object use(Closure closure) { // grab existing meta (usually adaptee but we may have nested use calls) MetaClass origMetaClass = registry.getMetaClass(theClass); registry.setMetaClass(theClass, this); try { return closure.call(); } finally { registry.setMetaClass(theClass, origMetaClass); } } /** * Use the ProxyMetaClass for the given Closure. * Cares for balanced setting/unsetting ProxyMetaClass. * * @param closure piece of code to be executed with ProxyMetaClass */ public Object use(GroovyObject object, Closure closure) { // grab existing meta (usually adaptee but we may have nested use calls) MetaClass origMetaClass = object.getMetaClass(); object.setMetaClass(this); try { return closure.call(); } finally { object.setMetaClass(origMetaClass); } } /** * @return the interceptor in use or null if no interceptor is used */ public Interceptor getInterceptor() { return interceptor; } /** * @param interceptor may be null to reset any interception */ public void setInterceptor(Interceptor interceptor) { this.interceptor = interceptor; } /** * Call invokeMethod on adaptee with logic like in MetaClass unless we have an Interceptor. * With Interceptor the call is nested in its beforeInvoke and afterInvoke methods. * The method call is suppressed if Interceptor.doInvoke() returns false. * See Interceptor for details. */ public Object invokeMethod(final Object object, final String methodName, final Object[] arguments) { return doCall(object, methodName, arguments, interceptor, new Callable() { public Object call() { return adaptee.invokeMethod(object, methodName, arguments); } }); } /** * Call invokeStaticMethod on adaptee with logic like in MetaClass unless we have an Interceptor. * With Interceptor the call is nested in its beforeInvoke and afterInvoke methods. * The method call is suppressed if Interceptor.doInvoke() returns false. * See Interceptor for details. */ public Object invokeStaticMethod(final Object object, final String methodName, final Object[] arguments) { return doCall(object, methodName, arguments, interceptor, new Callable() { public Object call() { return adaptee.invokeStaticMethod(object, methodName, arguments); } }); } /** * Call invokeConstructor on adaptee with logic like in MetaClass unless we have an Interceptor. * With Interceptor the call is nested in its beforeInvoke and afterInvoke methods. * The method call is suppressed if Interceptor.doInvoke() returns false. * See Interceptor for details. */ public Object invokeConstructor(final Object[] arguments) { return doCall(theClass, "ctor", arguments, interceptor, new Callable() { public Object call() { return adaptee.invokeConstructor(arguments); } }); } /** * Interceptors the call to getProperty if a PropertyAccessInterceptor is * available * * @param object the object to invoke the getter on * @param property the property name * @return the value of the property */ public Object getProperty(Class aClass, Object object, String property, boolean b, boolean b1) { if (null == interceptor) { return super.getProperty(aClass, object, property, b, b1); } if (interceptor instanceof PropertyAccessInterceptor) { PropertyAccessInterceptor pae = (PropertyAccessInterceptor) interceptor; Object result = pae.beforeGet(object, property); if (interceptor.doInvoke()) { result = super.getProperty(aClass, object, property, b, b1); } return result; } return super.getProperty(aClass, object, property, b, b1); } /** * Interceptors the call to a property setter if a PropertyAccessInterceptor * is available * * @param object The object to invoke the setter on * @param property The property name to set * @param newValue The new value of the property */ public void setProperty(Class aClass, Object object, String property, Object newValue, boolean b, boolean b1) { if (null == interceptor) { super.setProperty(aClass, object, property, newValue, b, b1); } if (interceptor instanceof PropertyAccessInterceptor) { PropertyAccessInterceptor pae = (PropertyAccessInterceptor) interceptor; pae.beforeSet(object, property, newValue); if (interceptor.doInvoke()) { super.setProperty(aClass, object, property, newValue, b, b1); } } else { super.setProperty(aClass, object, property, newValue, b, b1); } } public MetaClass getAdaptee() { return this.adaptee; } public void setAdaptee(MetaClass metaClass) { this.adaptee = metaClass; } // since Java has no Closures... private interface Callable { Object call(); } private Object doCall(Object object, String methodName, Object[] arguments, Interceptor interceptor, Callable howToInvoke) { if (null == interceptor) { return howToInvoke.call(); } Object result = interceptor.beforeInvoke(object, methodName, arguments); if (interceptor.doInvoke()) { result = howToInvoke.call(); } result = interceptor.afterInvoke(object, methodName, arguments, result); return result; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy