/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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 org.codehaus.groovy.runtime.GeneratedClosure; import org.codehaus.groovy.runtime.metaclass.ClosureMetaClass; import java.lang.reflect.Constructor; import java.util.Iterator; /** * A MetaClassRegistry is an object that is responsible for managing the a cache of MetaClass instances. Each * java.lang.Class instance has an associated MetaClass and client code can query this interface for the MetaClass for * a given associated java.lang.Class * * @see groovy.lang.MetaClass * * @author John Wilson * @author Graeme Rocher * @author <a href="mailto:blackdrag@gmx.org">Jochen Theodorou</a> * */ public interface MetaClassRegistry { /** * The main function of the registry * If a meta class exists then return it * otherwise create one, put it in the registry and return it */ MetaClass getMetaClass(Class theClass); /** * Adds a metaclass to the registry for the given class * * @param theClass The class * @param theMetaClass The MetaClass for theClass */ void setMetaClass(Class theClass, MetaClass theMetaClass); /** * Removes a cached MetaClass from the registry * * @param theClass The Java class of the MetaClass to remove */ void removeMetaClass(Class theClass); /** * Retrieves the MetaClassCreationHandle that is responsible for constructing MetaClass instances * * @return The MetaClassCreationHandle instance */ MetaClassCreationHandle getMetaClassCreationHandler(); /** * Sets the MetaClassCreationHandle instance that is responsible for constructing instances * * @param handle The handle instance */ void setMetaClassCreationHandle(MetaClassCreationHandle handle); /** * Adds a meta class change listener for constant meta classes * * @param listener - the update listener */ void addMetaClassRegistryChangeEventListener(MetaClassRegistryChangeEventListener listener); /** * Adds a meta class change listener for constant meta classes. * This listener cannot be removed! * * @param listener - the update listener */ void addNonRemovableMetaClassRegistryChangeEventListener(MetaClassRegistryChangeEventListener listener); /** * Removes a meta class change listener for constant meta classes * * @param listener - the update listener */ void removeMetaClassRegistryChangeEventListener(MetaClassRegistryChangeEventListener listener); /** * Returns all registered class change listener for constant meta classes. * * @return an array containing all change listener */ MetaClassRegistryChangeEventListener[] getMetaClassRegistryChangeEventListeners(); /** * Gets a snapshot of the current constant meta classes and returns it as Iterator. * Modifications done using this Iterator will not cause a ConcurrentModificationException. * If a MetaClass is removed using this Iterator, then the MetaClass will only * be removed if the MetaClass was not replaced by another MetaClass in the meantime. * If a MetaClass is added while using this Iterator, then it will be part of the Iteration. * If a MetaClass replaces another constant meta class, then the Iteration might show two * meta classes for the same class. * <p> * Note: This Iterator may not used with multiple threads. * * @return Iterator for the constant meta classes */ Iterator iterator(); /** * Class used as base for the creation of MetaClass implementations. * The Class defaults to MetaClassImpl, if the class loading fails to * find a special meta class. The name for such a meta class would be * the class name it is created for with the prefix * "groovy.runtime.metaclass." By replacing the handle in the registry * you can have any control over the creation of what MetaClass is used * for a class that you want to have. * WARNING: experimental code, likely to change soon * @author Jochen Theodorou */ class MetaClassCreationHandle { private boolean disableCustomMetaClassLookup; /** * Creates a metaclass implementation for theClass. * @param theClass The class to create a metaclass for * @param registry The metaclass registry the metaclass we be registered in. */ public final MetaClass create(Class theClass, MetaClassRegistry registry) { if (disableCustomMetaClassLookup) return createNormalMetaClass(theClass, registry); return createWithCustomLookup(theClass, registry); } private MetaClass createWithCustomLookup(Class theClass, MetaClassRegistry registry) { try { final Class customMetaClass = Class.forName("groovy.runtime.metaclass." + theClass.getName() + "MetaClass"); if (DelegatingMetaClass.class.isAssignableFrom(customMetaClass)) { final Constructor customMetaClassConstructor = customMetaClass.getConstructor(MetaClass.class); MetaClass normalMetaClass = createNormalMetaClass(theClass, registry); return (MetaClass)customMetaClassConstructor.newInstance(normalMetaClass); } else { final Constructor customMetaClassConstructor = customMetaClass.getConstructor(MetaClassRegistry.class, Class.class); return (MetaClass)customMetaClassConstructor.newInstance(registry, theClass); } } catch (final ClassNotFoundException e) { return createNormalMetaClass(theClass, registry); } catch (final Exception e) { throw new GroovyRuntimeException("Could not instantiate custom Metaclass for class: " + theClass.getName() + ". Reason: " + e, e); } } protected MetaClass createNormalMetaClass(Class theClass,MetaClassRegistry registry) { if (GeneratedClosure.class.isAssignableFrom(theClass)) { return new ClosureMetaClass(registry,theClass); } else { return new MetaClassImpl(registry, theClass); } } /** * Returns whether custom meta classes are disabled. */ public boolean isDisableCustomMetaClassLookup() { return disableCustomMetaClassLookup; } /** * Set flag saying to disable lookup of custom meta classes * It's enough to call this method only once in your application for handle which was set in to registry * as every new handle will inherit this property * @param disableCustomMetaClassLookup flag saying to disable lookup of custom meta classes */ public void setDisableCustomMetaClassLookup(boolean disableCustomMetaClassLookup) { this.disableCustomMetaClassLookup = disableCustomMetaClassLookup; } } }