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

org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl Maven / Gradle / Ivy

There is a newer version: 3.0.22
Show newest version
/*
 * Copyright 2003-2007 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 org.codehaus.groovy.runtime.metaclass;

import groovy.lang.*;

import org.codehaus.groovy.reflection.*;
import org.codehaus.groovy.runtime.DefaultGroovyMethods;
import org.codehaus.groovy.runtime.DefaultGroovyStaticMethods;
import org.codehaus.groovy.vmplugin.VMPluginFactory;
import org.codehaus.groovy.util.FastArray;
import org.codehaus.groovy.util.ManagedLinkedList;
import org.codehaus.groovy.util.ReferenceBundle;

import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;

/**
 * A registry of MetaClass instances which caches introspection &
 * reflection information and allows methods to be dynamically added to
 * existing classes at runtime
 *
 * @author James Strachan
 * @author John Wilson
 * @author Jochen Theodorou
 * @author Graeme Rocher
 * @author Alex Tkachman
 *
 * @version $Revision: 16242 $
 */
public class MetaClassRegistryImpl implements MetaClassRegistry{
    private boolean useAccessible;

    private FastArray instanceMethods = new FastArray();
    private FastArray staticMethods = new FastArray();

    private LinkedList changeListenerList = new LinkedList();
    private ManagedLinkedList metaClassInfo = new ManagedLinkedList(ReferenceBundle.getWeakBundle());

    public static final int LOAD_DEFAULT = 0;
    public static final int DONT_LOAD_DEFAULT = 1;
    private static MetaClassRegistry instanceInclude;
    private static MetaClassRegistry instanceExclude;

    public MetaClassRegistryImpl() {
        this(LOAD_DEFAULT, true);
    }

    public MetaClassRegistryImpl(int loadDefault) {
        this(loadDefault, true);
    }

    /**
     * @param useAccessible defines whether or not the {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)}
     *                      method will be called to enable access to all methods when using reflection
     */
    public MetaClassRegistryImpl(boolean useAccessible) {
        this(LOAD_DEFAULT, useAccessible);
    }
    
    public MetaClassRegistryImpl(final int loadDefault, final boolean useAccessible) {
        this.useAccessible = useAccessible;

        if (loadDefault == LOAD_DEFAULT) {
            HashMap map = new HashMap();

            // lets register the default methods
            registerMethods(DefaultGroovyMethods.class, true, true, map);
            Class[] pluginDGMs = VMPluginFactory.getPlugin().getPluginDefaultGroovyMethods();
            for (int i=0; i 0) {
                        ArrayList arr = (ArrayList) map.get(paramTypes[0]);
                        if (arr == null) {
                            arr = new ArrayList(4);
                            map.put(paramTypes[0],arr);
                        }
                        if (useInstanceMethods) {
                            final NewInstanceMetaMethod metaMethod = new NewInstanceMetaMethod(method);
                            arr.add(metaMethod);
                            instanceMethods.add(metaMethod);
                        } else {
                            final NewStaticMetaMethod metaMethod = new NewStaticMetaMethod(method);
                            arr.add(metaMethod);
                            staticMethods.add(metaMethod);
                        }
                    }
                }
            }
        }
    }

    private void createMetaMethodFromClass(Map map, Class aClass) {
        try {
            MetaMethod method = (MetaMethod) aClass.newInstance();
            final CachedClass declClass = method.getDeclaringClass();
            ArrayList arr = (ArrayList) map.get(declClass);
            if (arr == null) {
                arr = new ArrayList(4);
                map.put(declClass,arr);
            }
            arr.add(method);
            instanceMethods.add(method);
        } catch (InstantiationException e) {
        } catch (IllegalAccessException e) {
        }
    }

    public final MetaClass getMetaClass(Class theClass) {
        return ClassInfo.getClassInfo(theClass).getMetaClass();
    }

    public MetaClass getMetaClass(Object obj) {
        return ClassInfo.getClassInfo(obj.getClass()).getMetaClass(obj);
    }

    /**
     * if oldMc is null, newMc will replace whatever meta class was used before.
     * if oldMc is not null, then newMc will be used only if he stored mc is
     * the same as oldMc
     */
    private void setMetaClass(Class theClass, MetaClass oldMc, MetaClass newMc) {
        final ClassInfo info = ClassInfo.getClassInfo(theClass);
        
        MetaClass mc = null;
        info.lock();
        try {        	
        	if (oldMc!=null) mc=info.getStrongMetaClass();
        	// mc==null means that mc will be null too, so the 
        	// condition is always fulfilled. 
        	if (mc==oldMc) info.setStrongMetaClass(newMc);
        } finally {
            info.unlock();
        }

        if (oldMc!=mc) fireConstantMetaClassUpdate(theClass,newMc);
    }
    
    public void removeMetaClass(Class theClass) {
    	setMetaClass(theClass, null, null);
    }
    
    /**
     * Registers a new MetaClass in the registry to customize the type
     *
     * @param theClass
     * @param theMetaClass
     */
    public void setMetaClass(Class theClass, MetaClass theMetaClass) {
        setMetaClass(theClass,null,theMetaClass);
    }


    public void setMetaClass(Object obj, MetaClass theMetaClass) {
        Class theClass = obj.getClass ();
        final ClassInfo info = ClassInfo.getClassInfo(theClass);

        info.lock();
        try {
            info.setPerInstanceMetaClass(obj, theMetaClass);
        }
        finally {
            info.unlock();
        }
        
        fireConstantMetaClassUpdate(theClass, theMetaClass);
    }


    public boolean useAccessible() {
        return useAccessible;
    }

    // the following is experimental code, not intended for stable use yet
    private volatile MetaClassCreationHandle metaClassCreationHandle = new MetaClassCreationHandle();
    
    /**
     * Gets a handle internally used to create MetaClass implementations
     * WARNING: experimental code, likely to change soon
     * @return the handle
     */    
    public MetaClassCreationHandle getMetaClassCreationHandler() {
        return metaClassCreationHandle;
    }
    
    /**
     * Sets a handle internally used to create MetaClass implementations.
     * When replacing the handle with a custom version, you should
     * reuse the old handle to keep custom logic and to use the
     * default logic as fall back.
     * WARNING: experimental code, likely to change soon
     * @param handle the handle
     */
    public void setMetaClassCreationHandle(MetaClassCreationHandle handle) {
		if(handle == null) throw new IllegalArgumentException("Cannot set MetaClassCreationHandle to null value!");
        ClassInfo.clearModifiedExpandos();
        metaClassCreationHandle = handle;
    }    

    /**
     * Adds a listener for constant meta classes.
     * @param listener the listener
     */
    public void addMetaClassRegistryChangeEventListener(MetaClassRegistryChangeEventListener listener) {
        synchronized (changeListenerList) {
            changeListenerList.add(listener);
        }
    }

    /**
     * Removes a constant meta class listener.
     * @param listener the listener
     */
    public void removeMetaClassRegistryChangeEventListener(MetaClassRegistryChangeEventListener listener) {
    	synchronized (changeListenerList) {
        	Object first = changeListenerList.getFirst();
            changeListenerList.remove(listener);
            // we want to keep the first entry!
            if (changeListenerList.size()==0) changeListenerList.addFirst(first); 
        }
    }

    /**
     * Causes the execution of all registered listeners. This method is used mostly
     * internal to kick of the listener notification. It can also be used by subclasses
     * to achieve the same.
     * 
     * @param c the class
     * @param newMc the new MetaClass
     */
    protected void fireConstantMetaClassUpdate(Class c, MetaClass newMc) {
        MetaClassRegistryChangeEventListener[]  listener = getMetaClassRegistryChangeEventListeners();
        MetaClassRegistryChangeEvent cmcu = new MetaClassRegistryChangeEvent(this,c,newMc);
        for (int i=0; i




© 2015 - 2024 Weber Informatics LLC | Privacy Policy