Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   * 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 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(s):
James Strachan
John Wilson
Jochen Theodorou
Graeme Rocher
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<MetaClass>(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(true);
     }
 
     public MetaClassRegistryImpl(int loadDefault) {
         this(loadDefaulttrue);
     }

    

Parameters:
useAccessible defines whether or not the java.lang.reflect.AccessibleObject.setAccessible(boolean) method will be called to enable access to all methods when using reflection
 
     public MetaClassRegistryImpl(boolean useAccessible) {
         this(useAccessible);
     }
     
     public MetaClassRegistryImpl(final int loadDefaultfinal boolean useAccessible) {
         this. = useAccessible;
 
         if (loadDefault == ) {
             HashMap map = new HashMap();
 
             // lets register the default methods
             registerMethods(DefaultGroovyMethods.classtruetruemap);
             Class[] pluginDGMs = VMPluginFactory.getPlugin().getPluginDefaultGroovyMethods();
             for (int i=0; i<pluginDGMs.lengthi++) {
                 registerMethods(pluginDGMs[i], falsetruemap);
             }
             registerMethods(DefaultGroovyStaticMethods.classfalsefalsemap);
 
             for (Iterator it = map.entrySet().iterator(); it.hasNext(); ) {
                 Map.Entry e = (Map.Entryit.next();
                 CachedClass cls = (CachedClasse.getKey();
                 ArrayList list = (ArrayListe.getValue();
                 cls.setNewMopMethods(list);
             }
         }
        final MetaClass emcMetaClass = .create(ExpandoMetaClass.classthis);
        emcMetaClass.initialize();
        ClassInfo.getClassInfo(ExpandoMetaClass.class).setStrongMetaClass(emcMetaClass);
        
            public void updateConstantMetaClass(MetaClassRegistryChangeEvent cmcu) {
                synchronized () {
                   .add(cmcu.getNewMetaClass());
                }
            }
        });
   }

    
Looks for a class called 'groovy.runtime.metaclass.CustomMetaClassCreationHandle' and if it exists uses it as the MetaClassCreationHandle otherwise uses the default

    private void installMetaClassCreationHandle() {
	       try {
	           final Class customMetaClassHandle = Class.forName("groovy.runtime.metaclass.CustomMetaClassCreationHandle");
	           final Constructor customMetaClassHandleConstructor = customMetaClassHandle.getConstructor(new Class[]{});
				 this. = (MetaClassCreationHandle)customMetaClassHandleConstructor.newInstance(new Object[]{});
	       } catch (final ClassNotFoundException e) {
	           this. = new MetaClassCreationHandle();
	       } catch (final Exception e) {
	           throw new GroovyRuntimeException("Could not instantiate custom Metaclass creation handle: "ee);
	       }
    }
    
    private void registerMethods(final Class theClassfinal boolean useMethodrapperfinal boolean useInstanceMethodsMap map) {
        CachedMethod[] methods = ReflectionCache.getCachedClass(theClass).getMethods();
        if (useMethodrapper) {
            // Here we instantiate objects representing MetaMethods for DGM methods.
            // Calls for such meta methods done without reflection, so more effectively.
            // It gives 7-8% improvement for benchmarks involving just several ariphmetic operations
            for (int i = 0; ; ++i) {
                try {
                    final String className = "org.codehaus.groovy.runtime.dgm$" + i;
                    final Class aClass = Class.forName(className);
                    createMetaMethodFromClass(mapaClass);
                } catch (ClassNotFoundException e){
                    break;
                }
            }
            final Class[] additionals = .;
            for (int i = 0; i != additionals.length; ++i ) {
                createMetaMethodFromClass(mapadditionals[i]);
            }
        } else {
            for (int i = 0; i < methods.lengthi++) {
                CachedMethod method = methods[i];
                final int mod = method.getModifiers();
                if (Modifier.isStatic(mod) && Modifier.isPublic(mod)) {
                    CachedClass[] paramTypes = method.getParameterTypes();
                    if (paramTypes.length > 0) {
                        ArrayList arr = (ArrayListmap.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);
                            .add(metaMethod);
                        } else {
                            final NewStaticMetaMethod metaMethod = new NewStaticMetaMethod(method);
                            arr.add(metaMethod);
                            .add(metaMethod);
                        }
                    }
                }
            }
        }
    }
    private void createMetaMethodFromClass(Map mapClass aClass) {
        try {
            MetaMethod method = (MetaMethodaClass.newInstance();
            final CachedClass declClass = method.getDeclaringClass();
            ArrayList arr = (ArrayListmap.get(declClass);
            if (arr == null) {
                arr = new ArrayList(4);
                map.put(declClass,arr);
            }
            arr.add(method);
            .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 theClassMetaClass oldMcMetaClass newMc) {
        final ClassInfo info = ClassInfo.getClassInfo(theClass);
        
        MetaClass mc = null;
        info.lock();
        try {        	
        	if (oldMc!=nullmc=info.getStrongMetaClass();
        	// mc==null means that mc will be null too, so the 
        	// condition is always fulfilled. 
        	if (mc==oldMcinfo.setStrongMetaClass(newMc);
        } finally {
            info.unlock();
        }
        if (oldMc!=mcfireConstantMetaClassUpdate(theClass,newMc);
    }
    
    public void removeMetaClass(Class theClass) {
    	setMetaClass(theClassnullnull);
    }
    
    
Registers a new MetaClass in the registry to customize the type

Parameters:
theClass
theMetaClass
    public void setMetaClass(Class theClassMetaClass theMetaClass) {
        setMetaClass(theClass,null,theMetaClass);
    }
    public void setMetaClass(Object objMetaClass theMetaClass) {
        Class theClass = obj.getClass ();
        final ClassInfo info = ClassInfo.getClassInfo(theClass);
        info.lock();
        try {
            info.setPerInstanceMetaClass(objtheMetaClass);
        }
        finally {
            info.unlock();
        }
        
        fireConstantMetaClassUpdate(theClasstheMetaClass);
    }
    public boolean useAccessible() {
        return ;
    }
    // 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

Returns:
the handle
    
        return ;
    }
    
    
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

Parameters:
handle the handle
    public void setMetaClassCreationHandle(MetaClassCreationHandle handle) {
		if(handle == nullthrow new IllegalArgumentException("Cannot set MetaClassCreationHandle to null value!");
        ClassInfo.clearModifiedExpandos();
         = handle;
    }    

    
Adds a listener for constant meta classes.

Parameters:
listener the listener
        synchronized () {
            .add(listener);
        }
    }

    
Removes a constant meta class listener.

Parameters:
listener the listener
    	synchronized () {
        	Object first = .getFirst();
            .remove(listener);
            // we want to keep the first entry!
            if (.size()==0) .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.

Parameters:
c the class
newMc the new MetaClass
    protected void fireConstantMetaClassUpdate(Class cMetaClass newMc) {
        MetaClassRegistryChangeEvent cmcu = new MetaClassRegistryChangeEvent(this,c,newMc);
        for (int i=0; i<listener.lengthi++) {
            listener[i].updateConstantMetaClass(cmcu);
        }
    }

    
Gets an array of of all registered ConstantMetaClassListener instances.
        synchronized () {
        }
    }
    
    
Singleton of MetaClassRegistry.

Parameters:
includeExtension
    public static MetaClassRegistry getInstance(int includeExtension) {
        if (includeExtension != ) {
            if ( == null) {
                 = new MetaClassRegistryImpl();
            }
            return ;
        } else {
            if ( == null) {
                 = new MetaClassRegistryImpl();
            }
            return ;
        }
    }
    public FastArray getInstanceMethods() {
        return ;
    }
    public FastArray getStaticMethods() {
        return ;
    }
    
    
Returns an iterator to iterate over all constant meta classes. This iterator can be seen as making a snapshot of the current state of the registry. The snapshot will include all meta classes that has been used unless they are already collected. Collected meta classes will be skipped automatically, so you can expect that each element of the iteration is not null. Calling this method is thread safe, the usage of the iterator is not.

Returns:
the iterator.
    
    public Iterator iterator() {
        final MetaClass[] refs;
        synchronized () {
            refs = (MetaClass[]) .toArray(new MetaClass[0]);
        }
        
        return new Iterator() {
        	// index in the ref array
            private int index=0;
            // the current meta class
            private MetaClass currentMeta;
            // used to ensure that hasNext has been called
            private boolean hasNextCalled=false;
            // the cached hasNext call value
            private boolean hasNext=false;
            public boolean hasNext() {
            	if (return ;
            	 = true;
            	if( < refs.length) {
                	=true;
                    refs[];
                    ++;
            	} else {
            		=false;
            	}
                return ;
            }
            
            private void ensureNext() {
            	// we ensure that hasNext has been called before 
            	// next is called
            	hasNext();
            	=false;            	
            }
            
            public Object next() {
            	ensureNext();
                return ;
            }
            
            public void remove() {
            	ensureNext();
            	setMetaClass(.getTheClass(),,null);
                =null;
            }
        };
    }
New to GrepCode? Check out our FAQ X