home | career | drupal | java | mac | mysql | perl | scala | uml | unix

Groovy example source code file (MetaMethodIndex.java)

This example Groovy source code file (MetaMethodIndex.java) is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Java - Groovy tags/keywords

cachedclass, class, entry, entry, entryiterator, fastarray, fastarray, header, header, metamethod, metamethod, metamethodindex, object, string, util

The Groovy MetaMethodIndex.java source code

/*
 * 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.MetaMethod;
import org.codehaus.groovy.reflection.CachedClass;
import org.codehaus.groovy.util.FastArray;
import org.codehaus.groovy.reflection.GeneratedMetaMethod;
import org.codehaus.groovy.util.SingleKeyHashMap;

import java.util.NoSuchElementException;

public class MetaMethodIndex {
    public SingleKeyHashMap methodHeaders = new SingleKeyHashMap();

    public static class Header {
        public Entry head;
        Class cls;
        public int clsHashCode31;
        public Class subclass;

        public Header(Class cls) {
            this (cls, null);
        }

        public Header(Class cls, Class subclass) {
            this.cls = cls;
            this.subclass = subclass;
            this.clsHashCode31 = 31 * cls.hashCode();
        }
    }

    public static class CacheEntry {
        public Class [] params;
        public MetaMethod method;
    }

    public static class Entry {
        public int hash;

        public Entry nextHashEntry, nextClassEntry;

        public String name;
        public Class cls;

        public Object methods, methodsForSuper, staticMethods;

        public CacheEntry cachedMethod, cachedMethodForSuper, cachedStaticMethod;

        public String toString () {
            return "[" + name + ", " + cls.getName() + "]";
        }
    }

    public MetaMethodIndex(CachedClass theCachedClass) {
        init(DEFAULT_CAPACITY);

        CachedClass last = null;
        if (!theCachedClass.isInterface()) {
            for (CachedClass c = theCachedClass; c != null; c = c.getCachedSuperClass()) {
              final SingleKeyHashMap.Entry e = methodHeaders.getOrPut(c.getTheClass());
              e.value = new Header (c.getTheClass(), last == null ? null : last.getTheClass());
              last = c;
            }
        }
        else {
            final SingleKeyHashMap.Entry e = methodHeaders.getOrPut(Object.class);
            e.value = new Header (Object.class, theCachedClass.getTheClass());
        }
    }

    protected Entry table[];

    protected static final int DEFAULT_CAPACITY = 32;
    protected static final int MINIMUM_CAPACITY = 4;
    protected static final int MAXIMUM_CAPACITY = 1 << 28;

    protected int size;
    protected transient int threshold;

    public static int hash(int h) {
        h += ~(h << 9);
        h ^= (h >>> 14);
        h += (h << 4);
        h ^= (h >>> 10);
        return h;
    }

    public int size() {
        return size;
    }

    public boolean isEmpty() {
        return size == 0;
    }

    public void clear() {
        Object[] tab = table;
        for (int i = 0; i < tab.length; i++)
            tab[i] = null;
        size = 0;
    }

    public void init(int initCapacity) {
        threshold = (initCapacity * 6) / 8;
        table = new Entry[initCapacity];
    }

    public void resize(int newLength) {
        Entry[] oldTable = table;
        int oldLength = table.length;

        Entry[] newTable = new Entry[newLength];

        for (int j = 0; j < oldLength; j++) {

            for (Entry e = oldTable[j]; e != null;) {
                Entry next = e.nextHashEntry;
                int index = e.hash & (newLength - 1);

                e.nextHashEntry = newTable[index];
                newTable[index] = e;

                e = next;
            }
        }

        table = newTable;
        threshold = (6 * newLength) / 8;
    }

    public interface EntryIterator {
        boolean hasNext();

        Entry next();
    }


    public Entry[] getTable() {
        return table;
    }

    public EntryIterator getEntrySetIterator() {
        return new EntryIterator() {
            Entry next;    // next entry to return
            int index;        // current slot
            Entry current;    // current entry

            {
                Entry[] t = table;
                int i = t.length;
                Entry n = null;
                if (size != 0) { // advance to first entry
                    while (i > 0 && (n = t[--i]) == null) {
                    }
                }
                next = n;
                index = i;
            }

            public boolean hasNext() {
                return next != null;
            }

            public Entry next() {
                return nextEntry();
            }

            Entry nextEntry() {
                Entry e = next;
                if (e == null)
                    throw new NoSuchElementException();

                Entry n = e.nextHashEntry;
                Entry[] t = table;
                int i = index;
                while (n == null && i > 0)
                    n = t[--i];
                index = i;
                next = n;
                return current = e;
            }
        };
    }

    public final Entry getMethods(Class cls, String name) {
        int h = hash(31 * cls.hashCode() + name.hashCode());
        Entry e = table[h & (table.length - 1)];
        for (; e != null; e = e.nextHashEntry)
            if (e.hash == h && cls == e.cls && (e.name == name || e.name.equals(name)) )
                return e;

        return null;
    }

    public Entry getOrPutMethods(String name, Header header) {
        final Class cls = header.cls;
        int h = hash(header.clsHashCode31 + name.hashCode());
        final Entry[] t = table;
        final int index = h & (t.length - 1);
        Entry e = t[index];
        for (; e != null; e = e.nextHashEntry)
            if (e.hash == h && cls == e.cls && (e.name == name || e.name.equals(name)) )
                return e;

        Entry entry = new Entry();
        entry.nextHashEntry = t[index];
        entry.hash = h;
        entry.name = name.intern();
        entry.cls = cls;
        t[index] = entry;

        entry.nextClassEntry = header.head;
        header.head = entry;

        if (++size == threshold)
            resize(2 * t.length);

        return entry;
    }

    public Header getHeader(Class cls) {
        Header header;
        final SingleKeyHashMap.Entry head = methodHeaders.getOrPut(cls);
        if (head.value == null) {
            head.value = new Header(cls);
        }
        header = (Header) head.value;
        return header;
    }

    public void copyNonPrivateMethods(Class from, Class to) {
        copyNonPrivateMethods(getHeader(from), getHeader(to));
    }

    public void copyNonPrivateMethods(Header from, Header to) {
        for (Entry e = from.head; e != null; e = e.nextClassEntry)
            copyNonPrivateMethods(e, to);
    }

    public void copyAllMethodsToSuper(Header from, Header to) {
        for (Entry e = from.head; e != null; e = e.nextClassEntry)
            copyAllMethodsToSuper(e, to);
    }

    public void copyNonPrivateMethodsFromSuper(Header from) {
        for (Entry e = from.head; e != null; e = e.nextClassEntry)
            copyNonPrivateMethodsFromSuper(e);
    }

    private void copyNonPrivateMethods(Entry from, Header to) {
        Object oldListOrMethod = from.methods;
        if (oldListOrMethod instanceof FastArray) {
            FastArray oldList = (FastArray) oldListOrMethod;
            Entry e = null;
            int len1 = oldList.size();
            Object list[] = oldList.getArray();
            for (int j = 0; j != len1; ++j) {
                MetaMethod method = (MetaMethod) list[j];
                if (method.isPrivate()) continue;
                if (e == null)
                    e = getOrPutMethods(from.name, to);
                e.methods = addMethodToList(e.methods, method);
            }
        } else {
            MetaMethod method = (MetaMethod) oldListOrMethod;
            if (!method.isPrivate()) {
                Entry e = getOrPutMethods(from.name, to);
                e.methods = addMethodToList(e.methods, method);
            }
        }
    }

    private void copyAllMethodsToSuper(Entry from, Header to) {
        Object oldListOrMethod = from.methods;
        if (oldListOrMethod instanceof FastArray) {
            FastArray oldList = (FastArray) oldListOrMethod;
            Entry e = null;
            int len1 = oldList.size();
            Object list[] = oldList.getArray();
            for (int j = 0; j != len1; ++j) {
                MetaMethod method = (MetaMethod) list[j];
                if (e == null)
                    e = getOrPutMethods(from.name, to);
                e.methodsForSuper = addMethodToList(e.methodsForSuper, method);
            }
        } else {
            MetaMethod method = (MetaMethod) oldListOrMethod;
            Entry e = getOrPutMethods(from.name, to);
            e.methodsForSuper = addMethodToList(e.methodsForSuper, method);
        }
    }

    private void copyNonPrivateMethodsFromSuper(Entry e) {
        Object oldListOrMethod = e.methodsForSuper;
        if (oldListOrMethod == null)
          return;
        
        if (oldListOrMethod instanceof FastArray) {
            FastArray oldList = (FastArray) oldListOrMethod;
            int len1 = oldList.size();
            Object list[] = oldList.getArray();
            for (int j = 0; j != len1; ++j) {
                MetaMethod method = (MetaMethod) list[j];
                if (method.isPrivate()) continue;
                e.methods = addMethodToList(e.methods, method);
            }
        } else {
            MetaMethod method = (MetaMethod) oldListOrMethod;
            if (!method.isPrivate()) {
                e.methods = addMethodToList(e.methods, method);
            }
        }
    }

    public void copyNonPrivateMethodsDown(Class from, Class to) {
        copyNonPrivateNonNewMetaMethods(getHeader(from), getHeader(to));
    }

    public void copyNonPrivateNonNewMetaMethods(Header from, Header to) {
        for (Entry e = from.head; e != null; e = e.nextClassEntry)
            copyNonPrivateNonNewMetaMethods(e, to);
    }

    private void copyNonPrivateNonNewMetaMethods(Entry from, Header to) {
        Object oldListOrMethod = from.methods;
        if (oldListOrMethod == null)
          return;
        
        if (oldListOrMethod instanceof FastArray) {
            FastArray oldList = (FastArray) oldListOrMethod;
            Entry e = null;
            int len1 = oldList.size();
            Object list[] = oldList.getArray();
            for (int j = 0; j != len1; ++j) {
                MetaMethod method = (MetaMethod) list[j];
                if (method instanceof NewMetaMethod || method.isPrivate()) continue;
                if (e == null)
                    e = getOrPutMethods(from.name, to);
                e.methods = addMethodToList(e.methods, method);
            }
        } else {
            MetaMethod method = (MetaMethod) oldListOrMethod;
            if (method instanceof NewMetaMethod || method.isPrivate()) return;
            Entry e = getOrPutMethods(from.name, to);
            e.methods = addMethodToList(e.methods, method);
        }
    }

    public Object addMethodToList(Object o, MetaMethod method) {
        if (o == null) {
            return method;
        }

        if (o instanceof MetaMethod) {
            MetaMethod match = (MetaMethod) o;
            if (!isMatchingMethod(match, method)) {
                FastArray list = new FastArray(2);
                list.add(match);
                list.add(method);
                return list;
            } else {
                if (match.isPrivate()
                        || (!isNonRealMethod(match) && match.getDeclaringClass().isInterface() && !method.getDeclaringClass().isInterface())) {
                    // do not overwrite interface methods with instance methods
                    // do not overwrite private methods
                    // Note: private methods from parent classes are not shown here,
                    // but when doing the multimethod connection step, we overwrite
                    // methods of the parent class with methods of a subclass and
                    // in that case we want to keep the private methods
                } else {
                    CachedClass methodC = method.getDeclaringClass();
                    CachedClass matchC = match.getDeclaringClass();
                    if (methodC == matchC) {
                        if (isNonRealMethod(method)) {
                            return method;
                        }
                    } else if (!methodC.isAssignableFrom(matchC.getTheClass())) {
                        return method;
                    }
                }
            }
            return o;
        }

        if (o instanceof FastArray) {
            FastArray list = (FastArray) o;
            int found = findMatchingMethod(list, method);

            if (found == -1) {
                list.add(method);
            } else {
                MetaMethod match = (MetaMethod) list.get(found);
                if (match==method) return o;
                if (match.isPrivate()
                        || (!isNonRealMethod(match) && match.getDeclaringClass().isInterface() && !method.getDeclaringClass().isInterface())) {
                    // do not overwrite interface methods with instance methods
                    // do not overwrite private methods
                    // Note: private methods from parent classes are not shown here,
                    // but when doing the multimethod connection step, we overwrite
                    // methods of the parent class with methods of a subclass and
                    // in that case we want to keep the private methods
                } else {
                    CachedClass  methodC = method.getDeclaringClass();
                    CachedClass matchC = match.getDeclaringClass();
                    if (methodC == matchC) {
                        if (isNonRealMethod(method)) {
                            list.set(found, method);
                        }
                    } else if (!methodC.isAssignableFrom(matchC.getTheClass())) {
                        list.set(found, method);
                    }
                }
            }
        }

        return o;
    }

    private boolean isNonRealMethod(MetaMethod method) {
        return method instanceof NewInstanceMetaMethod ||
                method instanceof NewStaticMetaMethod ||
                method instanceof ClosureMetaMethod ||
                method instanceof GeneratedMetaMethod ||
                method instanceof ClosureStaticMetaMethod ||
                method instanceof MixinInstanceMetaMethod ||
                method instanceof ClosureMetaMethod.AnonymousMetaMethod;
    }

    private boolean isMatchingMethod(MetaMethod aMethod, MetaMethod method) {
        if (aMethod==method) return true;
        CachedClass[] params1 = aMethod.getParameterTypes();
        CachedClass[] params2 = method.getParameterTypes();
        if (params1.length != params2.length) {
            return false;
        }

        boolean matches = true;
        for (int i = 0; i < params1.length; i++) {
            if (params1[i] != params2[i]) {
                matches = false;
                break;
            }
        }
        return matches;
    }

    private int findMatchingMethod(FastArray list, MetaMethod method) {
        int len = list.size();
        Object data[] = list.getArray();
        for (int j = 0; j != len; ++j) {
            MetaMethod aMethod = (MetaMethod) data[j];
            if (isMatchingMethod(aMethod, method))
                return j;
        }
        return -1;
    }

    public void copyMethodsToSuper() {
        Entry[] table = this.table;
        int length = table.length;

        for (int j = 0; j < length; j++) {
            for (Entry e = table[j]; e != null; e = e.nextHashEntry) {
                if (e.methods instanceof FastArray)
                    e.methodsForSuper = ((FastArray) e.methods).copy();
                else
                    e.methodsForSuper = e.methods;
            }
        }

    }

    public void copy(Class c, Header index) {
        copy(getHeader(c), index);
    }

    public void copy(Header from, Header to) {
        for (Entry e = from.head; e != null; e = e.nextClassEntry)
            copyAllMethods(e, to);
    }

    private void copyAllMethods(Entry from, Header to) {
        Object oldListOrMethod = from.methods;
        if (oldListOrMethod instanceof FastArray) {
            FastArray oldList = (FastArray) oldListOrMethod;
            Entry e = null;
            int len1 = oldList.size();
            Object list[] = oldList.getArray();
            for (int j = 0; j != len1; ++j) {
                MetaMethod method = (MetaMethod) list[j];
                if (e == null)
                    e = getOrPutMethods(from.name, to);
                e.methods = addMethodToList(e.methods, method);
            }
        } else {
            MetaMethod method = (MetaMethod) oldListOrMethod;
            if (!method.isPrivate()) {
                Entry e = getOrPutMethods(from.name, to);
                e.methods = addMethodToList(e.methods, method);
            }
        }
    }

    public void clearCaches() {
        for (int i = 0; i != table.length; ++i )
          for (Entry e = table [i]; e != null; e = e.nextHashEntry ) {
              e.cachedMethod = e.cachedMethodForSuper = e.cachedStaticMethod = null;
          }
    }

    public void clearCaches(String name) {
        for (int i = 0; i != table.length; ++i )
          for (Entry e = table [i]; e != null; e = e.nextHashEntry ) {
              if (e.name.equals(name)) {
                  e.cachedMethod = e.cachedMethodForSuper = e.cachedStaticMethod = null;
              }
          }
    }
}

Other Groovy examples (source code examples)

Here is a short list of links related to this Groovy MetaMethodIndex.java source code file:

new blog posts

 

Copyright 1998-2013 Alvin Alexander, alvinalexander.com
All Rights Reserved.