You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by su...@apache.org on 2017/12/20 04:29:44 UTC

[36/47] groovy git commit: Move source files to proper packages

http://git-wip-us.apache.org/repos/asf/groovy/blob/0ad8c07c/src/main/groovy/groovy/lang/GroovyShell.java
----------------------------------------------------------------------
diff --git a/src/main/groovy/groovy/lang/GroovyShell.java b/src/main/groovy/groovy/lang/GroovyShell.java
new file mode 100644
index 0000000..4dc51c9
--- /dev/null
+++ b/src/main/groovy/groovy/lang/GroovyShell.java
@@ -0,0 +1,611 @@
+/*
+ *  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 groovy.security.GroovyCodeSourcePermission;
+import groovy.ui.GroovyMain;
+import org.apache.groovy.plugin.GroovyRunner;
+import org.apache.groovy.plugin.GroovyRunnerRegistry;
+import org.codehaus.groovy.control.CompilationFailedException;
+import org.codehaus.groovy.control.CompilerConfiguration;
+import org.codehaus.groovy.runtime.InvokerHelper;
+import org.codehaus.groovy.runtime.InvokerInvocationException;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.Reader;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.net.URI;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.List;
+
+import static org.codehaus.groovy.runtime.InvokerHelper.MAIN_METHOD_NAME;
+
+/**
+ * Represents a groovy shell capable of running arbitrary groovy scripts
+ *
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @author Guillaume Laforge
+ * @author Paul King
+ */
+public class GroovyShell extends GroovyObjectSupport {
+
+    public static final String DEFAULT_CODE_BASE = "/groovy/shell";
+
+    private final Binding context;
+    private int counter;
+    private final CompilerConfiguration config;
+    private GroovyClassLoader loader;
+
+    public static void main(String[] args) {
+        GroovyMain.main(args);
+    }
+
+    public GroovyShell() {
+        this(null, new Binding());
+    }
+
+    public GroovyShell(Binding binding) {
+        this(null, binding);
+    }
+
+    public GroovyShell(ClassLoader parent, CompilerConfiguration config) {
+        this(parent, new Binding(), config);
+    }
+
+    public GroovyShell(CompilerConfiguration config) {
+        this(new Binding(), config);
+    }
+
+    public GroovyShell(Binding binding, CompilerConfiguration config) {
+        this(null, binding, config);
+    }
+
+    public GroovyShell(ClassLoader parent, Binding binding) {
+        this(parent, binding, CompilerConfiguration.DEFAULT);
+    }
+
+    public GroovyShell(ClassLoader parent) {
+        this(parent, new Binding(), CompilerConfiguration.DEFAULT);
+    }
+    
+    public GroovyShell(ClassLoader parent, Binding binding, final CompilerConfiguration config) {
+        if (binding == null) {
+            throw new IllegalArgumentException("Binding must not be null.");
+        }
+        if (config == null) {
+            throw new IllegalArgumentException("Compiler configuration must not be null.");
+        }
+        final ClassLoader parentLoader = (parent!=null)?parent:GroovyShell.class.getClassLoader();
+        this.loader = AccessController.doPrivileged(new PrivilegedAction<GroovyClassLoader>() {
+            public GroovyClassLoader run() {
+                return new GroovyClassLoader(parentLoader,config);
+            }
+        });
+        this.context = binding;        
+        this.config = config;
+    }
+    
+    public void resetLoadedClasses() {
+        loader.clearCache();
+    }
+
+    /**
+     * Creates a child shell using a new ClassLoader which uses the parent shell's
+     * class loader as its parent
+     *
+     * @param shell is the parent shell used for the variable bindings and the parent class loader
+     */
+    public GroovyShell(GroovyShell shell) {
+        this(shell.loader, shell.context);
+    }
+
+    public Binding getContext() {
+        return context;
+    }
+
+    public GroovyClassLoader getClassLoader() {
+        return loader;
+    }
+
+    public Object getProperty(String property) {
+        Object answer = getVariable(property);
+        if (answer == null) {
+            answer = super.getProperty(property);
+        }
+        return answer;
+    }
+
+    public void setProperty(String property, Object newValue) {
+        setVariable(property, newValue);
+        try {
+            super.setProperty(property, newValue);
+        } catch (GroovyRuntimeException e) {
+            // ignore, was probably a dynamic property
+        }
+    }
+
+    //
+    // FIXME: Use List<String> here, current version is not safe
+    //
+
+    /**
+     * A helper method which runs the given script file with the given command line arguments
+     *
+     * @param scriptFile the file of the script to run
+     * @param list       the command line arguments to pass in
+     */
+    public Object run(File scriptFile, List list) throws CompilationFailedException, IOException {
+        String[] args = new String[list.size()];
+        return run(scriptFile, (String[]) list.toArray(args));
+    }
+
+    /**
+     * A helper method which runs the given cl script with the given command line arguments
+     *
+     * @param scriptText is the text content of the script
+     * @param fileName   is the logical file name of the script (which is used to create the class name of the script)
+     * @param list       the command line arguments to pass in
+     */
+    public Object run(String scriptText, String fileName, List list) throws CompilationFailedException {
+        String[] args = new String[list.size()];
+        list.toArray(args);
+        return run(scriptText, fileName, args);
+    }
+
+    /**
+     * Runs the given script file name with the given command line arguments
+     *
+     * @param scriptFile the file name of the script to run
+     * @param args       the command line arguments to pass in
+     */
+    public Object run(final File scriptFile, String[] args) throws CompilationFailedException, IOException {
+        String scriptName = scriptFile.getName();
+        int p = scriptName.lastIndexOf(".");
+        if (p++ >= 0) {
+            if (scriptName.substring(p).equals("java")) {
+                throw new CompilationFailedException(0, null);
+            }
+        }
+
+        // Get the current context classloader and save it on the stack
+        final Thread thread = Thread.currentThread();
+        //ClassLoader currentClassLoader = thread.getContextClassLoader();
+
+        class DoSetContext implements PrivilegedAction {
+            ClassLoader classLoader;
+
+            public DoSetContext(ClassLoader loader) {
+                classLoader = loader;
+            }
+
+            public Object run() {
+                thread.setContextClassLoader(classLoader);
+                return null;
+            }
+        }
+
+        AccessController.doPrivileged(new DoSetContext(loader));
+
+        // Parse the script, generate the class, and invoke the main method.  This is a little looser than
+        // if you are compiling the script because the JVM isn't executing the main method.
+        Class scriptClass;
+        try {
+            scriptClass = AccessController.doPrivileged(new PrivilegedExceptionAction<Class>() {
+                public Class run() throws CompilationFailedException, IOException {
+                    return loader.parseClass(scriptFile);
+                }
+            });
+        } catch (PrivilegedActionException pae) {
+            Exception e = pae.getException();
+            if (e instanceof CompilationFailedException) {
+                throw (CompilationFailedException) e;
+            } else if (e instanceof IOException) {
+                throw (IOException) e;
+            } else {
+                throw (RuntimeException) pae.getException();
+            }
+        }
+
+        return runScriptOrMainOrTestOrRunnable(scriptClass, args);
+
+        // Set the context classloader back to what it was.
+        //AccessController.doPrivileged(new DoSetContext(currentClassLoader));
+    }
+
+    /**
+     * if (theClass is a Script) {
+     * run it like a script
+     * } else if (theClass has a main method) {
+     * run the main method
+     * } else if (theClass instanceof GroovyTestCase) {
+     * use the test runner to run it
+     * } else if (theClass implements Runnable) {
+     * if (theClass has a constructor with String[] params)
+     * instantiate theClass with this constructor and run
+     * else if (theClass has a no-args constructor)
+     * instantiate theClass with the no-args constructor and run
+     * }
+     */
+    private Object runScriptOrMainOrTestOrRunnable(Class scriptClass, String[] args) {
+        // Always set the "args" property, regardless of what path we take in the code.
+        // Bad enough to have side effects but worse if their behavior is wonky.
+        context.setProperty("args", args);
+
+        if (scriptClass == null) {
+            return null;
+        }
+
+        //TODO: This logic mostly duplicates InvokerHelper.createScript.  They should probably be unified.
+
+        if (Script.class.isAssignableFrom(scriptClass)) {
+            // treat it just like a script if it is one
+            try {
+                Script script = InvokerHelper.newScript(scriptClass, context);
+                return script.run();
+            } catch (InstantiationException e) {
+                // ignore instantiation errors,, try to do main
+            } catch (IllegalAccessException e) {
+               // ignore instantiation errors, try to do main
+            } catch (InvocationTargetException e) {
+                // ignore instantiation errors, try to do main
+            }
+        }
+        try {
+            // let's find a main method
+            scriptClass.getMethod(MAIN_METHOD_NAME, String[].class);
+            // if that main method exist, invoke it
+            return InvokerHelper.invokeMethod(scriptClass, MAIN_METHOD_NAME, new Object[]{args});
+        } catch (NoSuchMethodException e) {
+            // if it implements Runnable, try to instantiate it
+            if (Runnable.class.isAssignableFrom(scriptClass)) {
+                return runRunnable(scriptClass, args);
+            }
+            GroovyRunnerRegistry runnerRegistry = GroovyRunnerRegistry.getInstance();
+            for (GroovyRunner runner : runnerRegistry) {
+                if (runner.canRun(scriptClass, this.loader)) {
+                    return runner.run(scriptClass, this.loader);
+                }
+            }
+            StringBuilder message = new StringBuilder("This script or class could not be run.\n" +
+                    "It should either:\n" +
+                    "- have a main method,\n" +
+                    "- be a JUnit test or extend GroovyTestCase,\n" +
+                    "- implement the Runnable interface,\n" +
+                    "- or be compatible with a registered script runner. Known runners:\n");
+            if (runnerRegistry.isEmpty()) {
+                message.append("  * <none>");
+            } else {
+                for (String key : runnerRegistry.keySet()) {
+                    message.append("  * ").append(key).append("\n");
+                }
+            }
+            throw new GroovyRuntimeException(message.toString());
+        }
+    }
+
+    private static Object runRunnable(Class scriptClass, String[] args) {
+        Constructor constructor = null;
+        Runnable runnable = null;
+        Throwable reason = null;
+        try {
+            // first, fetch the constructor taking String[] as parameter
+            constructor = scriptClass.getConstructor((new String[]{}).getClass());
+            try {
+                // instantiate a runnable and run it
+                runnable = (Runnable) constructor.newInstance(new Object[]{args});
+            } catch (Throwable t) {
+                reason = t;
+            }
+        } catch (NoSuchMethodException e1) {
+            try {
+                // otherwise, find the default constructor
+                constructor = scriptClass.getConstructor();
+                try {
+                    // instantiate a runnable and run it
+                    runnable = (Runnable) constructor.newInstance();
+                } catch (InvocationTargetException ite) {
+                    throw new InvokerInvocationException(ite.getTargetException());
+                } catch (Throwable t) {
+                    reason = t;
+                }
+            } catch (NoSuchMethodException nsme) {
+                reason = nsme;
+            }
+        }
+        if (constructor != null && runnable != null) {
+            runnable.run();
+        } else {
+            throw new GroovyRuntimeException("This script or class was runnable but could not be run. ", reason);
+        }
+        return null;
+    }
+
+    /**
+     * Runs the given script text with command line arguments
+     *
+     * @param scriptText is the text content of the script
+     * @param fileName   is the logical file name of the script (which is used to create the class name of the script)
+     * @param args       the command line arguments to pass in
+     */
+    public Object run(final String scriptText, final String fileName, String[] args) throws CompilationFailedException {
+        GroovyCodeSource gcs = AccessController.doPrivileged(new PrivilegedAction<GroovyCodeSource>() {
+            public GroovyCodeSource run() {
+                return new GroovyCodeSource(scriptText, fileName, DEFAULT_CODE_BASE);
+            }
+        });
+        return run(gcs, args);
+    }
+
+    /**
+     * Runs the given script source with command line arguments
+     *
+     * @param source    is the source content of the script
+     * @param args      the command line arguments to pass in
+     */
+    public Object run(GroovyCodeSource source, List args) throws CompilationFailedException {
+        return run(source, ((String[]) args.toArray(new String[args.size()])));
+    }
+
+    /**
+     * Runs the given script source with command line arguments
+     *
+     * @param source    is the source content of the script
+     * @param args      the command line arguments to pass in
+     */
+    public Object run(GroovyCodeSource source, String[] args) throws CompilationFailedException {
+        Class scriptClass = parseClass(source);
+        return runScriptOrMainOrTestOrRunnable(scriptClass, args);
+    }
+
+    /**
+     * Runs the given script source with command line arguments
+     *
+     * @param source    is the source content of the script
+     * @param args      the command line arguments to pass in
+     */
+    public Object run(URI source, List args) throws CompilationFailedException, IOException {
+        return run(new GroovyCodeSource(source), ((String[]) args.toArray(new String[args.size()])));
+    }
+
+    /**
+     * Runs the given script source with command line arguments
+     *
+     * @param source    is the source content of the script
+     * @param args      the command line arguments to pass in
+     */
+    public Object run(URI source, String[] args) throws CompilationFailedException, IOException {
+        return run(new GroovyCodeSource(source), args);
+    }
+
+    /**
+     * Runs the given script with command line arguments
+     *
+     * @param in       the stream reading the script
+     * @param fileName is the logical file name of the script (which is used to create the class name of the script)
+     * @param list     the command line arguments to pass in
+     */
+    public Object run(final Reader in, final String fileName, List list) throws CompilationFailedException {
+        return run(in, fileName, (String[]) list.toArray(new String[list.size()]));
+    }
+
+    /**
+     * Runs the given script with command line arguments
+     *
+     * @param in       the stream reading the script
+     * @param fileName is the logical file name of the script (which is used to create the class name of the script)
+     * @param args     the command line arguments to pass in
+     */
+    public Object run(final Reader in, final String fileName, String[] args) throws CompilationFailedException {
+        GroovyCodeSource gcs = AccessController.doPrivileged(new PrivilegedAction<GroovyCodeSource>() {
+                    public GroovyCodeSource run() {
+                        return new GroovyCodeSource(in, fileName, DEFAULT_CODE_BASE);
+                    }
+        });
+        Class scriptClass = parseClass(gcs);
+        return runScriptOrMainOrTestOrRunnable(scriptClass, args);
+    }
+
+    public Object getVariable(String name) {
+        return context.getVariables().get(name);
+    }
+
+    public void setVariable(String name, Object value) {
+        context.setVariable(name, value);
+    }
+
+    /**
+     * Evaluates some script against the current Binding and returns the result
+     *
+     * @param codeSource
+     * @throws CompilationFailedException
+     */
+    public Object evaluate(GroovyCodeSource codeSource) throws CompilationFailedException {
+        Script script = parse(codeSource);
+        return script.run();
+    }
+
+    /**
+     * Evaluates some script against the current Binding and returns the result
+     *
+     * @param scriptText the text of the script
+     */
+    public Object evaluate(final String scriptText) throws CompilationFailedException {
+        return evaluate(scriptText, generateScriptName(), DEFAULT_CODE_BASE);
+    }
+
+    /**
+     * Evaluates some script against the current Binding and returns the result
+     *
+     * @param scriptText the text of the script
+     * @param fileName   is the logical file name of the script (which is used to create the class name of the script)
+     */
+    public Object evaluate(String scriptText, String fileName) throws CompilationFailedException {
+        return evaluate(scriptText, fileName, DEFAULT_CODE_BASE);
+    }
+
+    /**
+     * Evaluates some script against the current Binding and returns the result.
+     * The .class file created from the script is given the supplied codeBase
+     */
+    public Object evaluate(final String scriptText, final String fileName, final String codeBase) throws CompilationFailedException {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkPermission(new GroovyCodeSourcePermission(codeBase));
+        }
+
+        GroovyCodeSource gcs = AccessController.doPrivileged(new PrivilegedAction<GroovyCodeSource>() {
+            public GroovyCodeSource run() {
+                return new GroovyCodeSource(scriptText, fileName, codeBase);
+            }
+        });
+
+        return evaluate(gcs);
+    }
+
+    /**
+     * Evaluates some script against the current Binding and returns the result
+     *
+     * @param file is the file of the script (which is used to create the class name of the script)
+     */
+    public Object evaluate(File file) throws CompilationFailedException, IOException {
+        return evaluate(new GroovyCodeSource(file, config.getSourceEncoding()));
+    }
+
+    /**
+     * Evaluates some script against the current Binding and returns the result
+     *
+     * @param uri is the URI of the script (which is used to create the class name of the script)
+     */
+    public Object evaluate(URI uri) throws CompilationFailedException, IOException {
+        return evaluate(new GroovyCodeSource(uri));
+    }
+
+    /**
+     * Evaluates some script against the current Binding and returns the result
+     *
+     * @param in the stream reading the script
+     */
+    public Object evaluate(Reader in) throws CompilationFailedException {
+        return evaluate(in, generateScriptName());
+    }
+
+    /**
+     * Evaluates some script against the current Binding and returns the result
+     *
+     * @param in       the stream reading the script
+     * @param fileName is the logical file name of the script (which is used to create the class name of the script)
+     */
+    public Object evaluate(Reader in, String fileName) throws CompilationFailedException {
+        Script script = null;
+        try {
+            script = parse(in, fileName);
+            return script.run();
+        } finally {
+            if (script != null) {
+                InvokerHelper.removeClass(script.getClass());
+            }
+        }
+    }
+
+
+    /**
+     * Parses the given script and returns it ready to be run
+     *
+     * @param reader    the stream reading the script
+     * @param fileName  is the logical file name of the script (which is used to create the class name of the script)
+     * @return the parsed script which is ready to be run via {@link Script#run()}
+     */
+    public Script parse(final Reader reader, final String fileName) throws CompilationFailedException {
+        return parse(new GroovyCodeSource(reader, fileName, DEFAULT_CODE_BASE));
+    }
+
+    /**
+     * Parses the groovy code contained in codeSource and returns a java class.
+     */
+    private Class parseClass(final GroovyCodeSource codeSource) throws CompilationFailedException {
+        // Don't cache scripts
+        return loader.parseClass(codeSource, false);
+    }
+
+    /**
+     * Parses the given script and returns it ready to be run.  When running in a secure environment
+     * (-Djava.security.manager) codeSource.getCodeSource() determines what policy grants should be
+     * given to the script.
+     *
+     * @param codeSource
+     * @return ready to run script
+     */
+    public Script parse(final GroovyCodeSource codeSource) throws CompilationFailedException {
+        return InvokerHelper.createScript(parseClass(codeSource), context);
+    }
+
+    /**
+     * Parses the given script and returns it ready to be run
+     *
+     * @param file is the file of the script (which is used to create the class name of the script)
+     */
+    public Script parse(File file) throws CompilationFailedException, IOException {
+        return parse(new GroovyCodeSource(file, config.getSourceEncoding()));
+    }
+
+    /**
+     * Parses the given script and returns it ready to be run
+     *
+     * @param uri is the URI of the script (which is used to create the class name of the script)
+     */
+    public Script parse(URI uri) throws CompilationFailedException, IOException {
+        return parse(new GroovyCodeSource(uri));
+    }
+
+    /**
+     * Parses the given script and returns it ready to be run
+     *
+     * @param scriptText the text of the script
+     */
+    public Script parse(String scriptText) throws CompilationFailedException {
+        return parse(scriptText, generateScriptName());
+    }
+
+    public Script parse(final String scriptText, final String fileName) throws CompilationFailedException {
+        GroovyCodeSource gcs = AccessController.doPrivileged(new PrivilegedAction<GroovyCodeSource>() {
+            public GroovyCodeSource run() {
+                return new GroovyCodeSource(scriptText, fileName, DEFAULT_CODE_BASE);
+            }
+        });
+        return parse(gcs);
+    }
+
+    /**
+     * Parses the given script and returns it ready to be run
+     *
+     * @param in the stream reading the script
+     */
+    public Script parse(Reader in) throws CompilationFailedException {
+        return parse(in, generateScriptName());
+    }
+
+    protected synchronized String generateScriptName() {
+        return "Script" + (++counter) + ".groovy";
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0ad8c07c/src/main/groovy/groovy/lang/GroovySystem.java
----------------------------------------------------------------------
diff --git a/src/main/groovy/groovy/lang/GroovySystem.java b/src/main/groovy/groovy/lang/GroovySystem.java
new file mode 100644
index 0000000..cb5ea98
--- /dev/null
+++ b/src/main/groovy/groovy/lang/GroovySystem.java
@@ -0,0 +1,103 @@
+/*
+ *  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.apache.groovy.plugin.GroovyRunner;
+import org.apache.groovy.plugin.GroovyRunnerRegistry;
+import org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl;
+import org.codehaus.groovy.util.ReferenceBundle;
+import org.codehaus.groovy.util.ReleaseInfo;
+
+import java.util.Map;
+
+public final class GroovySystem {
+    //
+    //  TODO: make this initialization able to set useReflection true
+    //  TODO: have some way of specifying another MetaClass Registry implementation
+    //
+    static {
+        USE_REFLECTION = true;
+        META_CLASS_REGISTRY = new MetaClassRegistryImpl();
+    }
+    
+    /**
+     * If true then the MetaClass will only use reflection for method dispatch, property access, etc.
+     */
+    @Deprecated
+    private static final boolean USE_REFLECTION;
+
+    /**
+     * Reference to the MetaClass Registry to be used by the Groovy run-time system to map classes to MetaClasses
+     */
+    private static final MetaClassRegistry META_CLASS_REGISTRY;
+
+    /**
+     * Reference to the Runtime Registry to be used by the Groovy run-time system to find classes capable of running scripts
+     *
+     * @deprecated use {@link GroovyRunnerRegistry}
+     */
+    @Deprecated
+    public static final Map<String, GroovyRunner> RUNNER_REGISTRY = GroovyRunnerRegistry.getInstance();
+
+    private static boolean keepJavaMetaClasses=false;
+    
+    private GroovySystem() {
+        // Do not allow this class to be instantiated
+    }
+
+    @Deprecated
+    public static boolean isUseReflection() {
+        return USE_REFLECTION;
+    }
+
+    public static MetaClassRegistry getMetaClassRegistry() {
+        return META_CLASS_REGISTRY;
+    }
+    
+    public static void setKeepJavaMetaClasses(boolean keepJavaMetaClasses) {
+        GroovySystem.keepJavaMetaClasses = keepJavaMetaClasses;
+    }
+    
+    public static boolean isKeepJavaMetaClasses() {
+        return keepJavaMetaClasses;
+    }
+    
+    /**
+     * This method can be used to ensure that no threaded created
+     * by a reference manager will be active. This is useful if the Groovy
+     * runtime itself is loaded through a class loader which should be disposed
+     * off. Without calling this method and if a threaded reference manager is
+     * active the class loader cannot be unloaded!
+     * 
+     * Per default no threaded manager will be used.
+     * 
+     * @since 1.6
+     */
+    public static void stopThreadedReferenceManager() {
+        ReferenceBundle.getSoftBundle().getManager().stopThread();
+        ReferenceBundle.getWeakBundle().getManager().stopThread();
+    }
+
+    /**
+     * Returns the groovy version
+     */
+    public static String getVersion() {
+        return ReleaseInfo.getVersion();
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0ad8c07c/src/main/groovy/groovy/lang/IllegalPropertyAccessException.java
----------------------------------------------------------------------
diff --git a/src/main/groovy/groovy/lang/IllegalPropertyAccessException.java b/src/main/groovy/groovy/lang/IllegalPropertyAccessException.java
new file mode 100644
index 0000000..8227e3f
--- /dev/null
+++ b/src/main/groovy/groovy/lang/IllegalPropertyAccessException.java
@@ -0,0 +1,49 @@
+/*
+ *  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 java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+
+/**
+ * An exception occurred if a dynamic property dispatch fails with a 
+ * field not accessible.
+ * 
+ * @author <a href="mailto:blackdrag@uni.de">Jochen Theodorou</a>
+ */
+public class IllegalPropertyAccessException extends MissingPropertyException {
+    
+    private static String makeMessage(String propertyName, Class clazz, int modifiers, boolean isField) {
+        String access = "private";
+        if (Modifier.isProtected(modifiers)) access = "protected";
+        if (Modifier.isPublic(modifiers)) access = "public";
+        String propertyType = "property";
+        if (isField) propertyType = "field";
+        return  "Can not access the "+access+" "+propertyType+" "+propertyName+" in class "+clazz.getName();
+    }
+    
+    public IllegalPropertyAccessException(String propertyName, Class clazz, int modifiers) {
+        super(makeMessage(propertyName,clazz,modifiers,false),propertyName,clazz);
+    }
+    
+    public IllegalPropertyAccessException(Field field, Class clazz) {
+        super(makeMessage(field.getName(),clazz,field.getModifiers(),true),field.getName(),clazz);
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0ad8c07c/src/main/groovy/groovy/lang/IncorrectClosureArgumentsException.java
----------------------------------------------------------------------
diff --git a/src/main/groovy/groovy/lang/IncorrectClosureArgumentsException.java b/src/main/groovy/groovy/lang/IncorrectClosureArgumentsException.java
new file mode 100644
index 0000000..f5b23f5
--- /dev/null
+++ b/src/main/groovy/groovy/lang/IncorrectClosureArgumentsException.java
@@ -0,0 +1,60 @@
+/*
+ *  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.InvokerHelper;
+
+/**
+ * An exception occurred when invoking a Closure with the wrong number and/or
+ * types of arguments
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ */
+public class IncorrectClosureArgumentsException extends GroovyRuntimeException {
+
+    private final Closure closure;
+    private final Object arguments;
+    private final Class[] expected;
+
+    public IncorrectClosureArgumentsException(Closure closure, Object arguments, Class[] expected) {
+        super(
+            "Incorrect arguments to closure: "
+                + closure
+                + ". Expected: "
+                + InvokerHelper.toString(expected)
+                + ", actual: "
+                + InvokerHelper.toString(arguments));
+        this.closure = closure;
+        this.arguments = arguments;
+        this.expected = expected;
+    }
+
+    public Object getArguments() {
+        return arguments;
+    }
+
+    public Closure getClosure() {
+        return closure;
+    }
+
+    public Class[] getExpected() {
+        return expected;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0ad8c07c/src/main/groovy/groovy/lang/IntRange.java
----------------------------------------------------------------------
diff --git a/src/main/groovy/groovy/lang/IntRange.java b/src/main/groovy/groovy/lang/IntRange.java
new file mode 100644
index 0000000..1ca3820
--- /dev/null
+++ b/src/main/groovy/groovy/lang/IntRange.java
@@ -0,0 +1,440 @@
+/*
+ *  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.IteratorClosureAdapter;
+import org.codehaus.groovy.runtime.RangeInfo;
+
+import java.math.BigInteger;
+import java.util.AbstractList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+
+/**
+ * Represents a list of Integer objects starting at a specified {@code from} value up (or down)
+ * to and potentially including a given {@code to} value.
+ * <p>
+ * Instances of this class may be either inclusive aware or non-inclusive aware. See the
+ * relevant constructors for creating each type. Inclusive aware IntRange instances are
+ * suitable for use with Groovy's range indexing - in particular if the from or to values
+ * might be negative. This normally happens underneath the covers but is worth keeping
+ * in mind if creating these ranges yourself explicitly.
+ * <p>
+ * Note: the design of this class might seem a little strange at first. It contains a Boolean
+ * field, {@code inclusive}, which can be {@code true}, {@code false} or {@code null}. This
+ * design is for backwards compatibility reasons. Groovy uses this class under the covers
+ * to represent range indexing, e.g. {@code someList[x..y]} and {@code someString[x..<y]}.
+ * In early versions of Groovy the ranges in these expressions were represented under the
+ * covers by the {@code new IntRange(x, y)} and {@code new IntRange(x, y-1)}. This turns
+ * out to be a lossy abstraction when x and/or y are negative values. Now the latter case
+ * is represented by {@code new IntRange(false, x, y)}.
+ * <p>
+ * Note: This class is a copy of {@link ObjectRange} optimized for <code>int</code>. If you make any
+ * changes to this class, you might consider making parallel changes to {@link ObjectRange}.
+ */
+public class IntRange extends AbstractList<Integer> implements Range<Integer> {
+
+    /**
+     * Iterates through each number in an <code>IntRange</code>.
+     */
+    private class IntRangeIterator implements Iterator<Integer> {
+        /**
+         * Counts from 0 up to size - 1.
+         */
+        private int index;
+
+        /**
+         * The number of values in the range.
+         */
+        private int size = size();
+
+        /**
+         * The next value to return.
+         */
+        private int value = isReverse() ? getTo() : getFrom();
+
+        @Override
+        public boolean hasNext() {
+            return index < size;
+        }
+
+        @Override
+        public Integer next() {
+            if (!hasNext()) {
+                throw new NoSuchElementException();
+            }
+            if (index++ > 0) {
+                if (isReverse()) {
+                    --value;
+                } else {
+                    ++value;
+                }
+            }
+            return value;
+        }
+
+        /**
+         * Not supported.
+         *
+         * @throws java.lang.UnsupportedOperationException always
+         */
+        @Override
+        public void remove() {
+            IntRange.this.remove(index);
+        }
+    }
+
+    /**
+     * For non-inclusive aware ranges, the first number in the range; <code>from</code> is always less than or equal to <code>to</code>.
+     * For inclusive aware ranges, the <code>from</code> argument supplied to the constructor.
+     */
+    private final int from;
+
+    /**
+     * For non-inclusive aware ranges, the last number in the range; <code>to</code> is always greater than or equal to <code>from</code>.
+     * For inclusive aware ranges, the <code>from</code> argument supplied to the constructor.
+     */
+    private final int to;
+
+    /**
+     * If <code>false</code>, counts up from <code>from</code> to <code>to</code>.  Otherwise, counts down
+     * from <code>to</code> to <code>from</code>. Not used for inclusive-aware ranges (inclusive = true|false).
+     */
+    private final boolean reverse;
+
+    /**
+     * If <code>true</code> or null, <code>to</code> is included in the range.
+     * If <code>false</code>, the range stops before the <code>to</code> value.
+     * <p>
+     * Null for non-inclusive-aware ranges (which are inclusive).
+     * <p>
+     * If true or false, the reverse flag is discarded.
+     */
+    private final Boolean inclusive;
+
+    /**
+     * Creates a new non-inclusive aware <code>IntRange</code>. If <code>from</code> is greater than
+     * <code>to</code>, a reverse range is created with <code>from</code> and <code>to</code> swapped.
+     *
+     * @param from the first number in the range.
+     * @param to   the last number in the range.
+     * @throws IllegalArgumentException if the range would contain more than {@link Integer#MAX_VALUE} values.
+     */
+    public IntRange(int from, int to) {
+        this.inclusive = null;
+        if (from > to) {
+            this.from = to;
+            this.to = from;
+            this.reverse = true;
+        } else {
+            this.from = from;
+            this.to = to;
+            this.reverse = false;
+        }
+        checkSize();
+    }
+
+    /**
+     * Creates a new non-inclusive aware <code>IntRange</code>.
+     *
+     * @param from    the first value in the range.
+     * @param to      the last value in the range.
+     * @param reverse <code>true</code> if the range should count from
+     *                <code>to</code> to <code>from</code>.
+     * @throws IllegalArgumentException if <code>from</code> is greater than <code>to</code>.
+     */
+    protected IntRange(int from, int to, boolean reverse) {
+        this.inclusive = null;
+        if (from > to) {
+            throw new IllegalArgumentException("'from' must be less than or equal to 'to'");
+        }
+
+        this.from = from;
+        this.to = to;
+        this.reverse = reverse;
+        checkSize();
+    }
+
+    /**
+     * Creates a new inclusive aware <code>IntRange</code>.
+     *
+     * @param from      the first value in the range.
+     * @param to        the last value in the range.
+     * @param inclusive <code>true</code> if the to value is included in the range.
+     */
+    public IntRange(boolean inclusive, int from, int to) {
+        this.from = from;
+        this.to = to;
+        this.inclusive = inclusive;
+        this.reverse = false; // range may still be reversed, this value is ignored for inclusive-aware ranges
+        checkSize();
+    }
+
+    /**
+     * Creates a new NumberRange with the same <code>from</code> and <code>to</code> as this
+     * IntRange but with a step size of <code>stepSize</code>.
+     *
+     * @param stepSize the desired step size
+     * @return a new NumberRange
+     * @since 2.5
+     */
+    public <T extends Number & Comparable> NumberRange by(T stepSize) {
+        return new NumberRange(NumberRange.comparableNumber((Number)from), NumberRange.comparableNumber((Number)to), stepSize, inclusive);
+    }
+
+    private void checkSize() {
+        // size() in the Collection interface returns an integer, so ranges can have no more than Integer.MAX_VALUE elements
+        final Long size = (long) to - from + 1;
+        if (size > Integer.MAX_VALUE) {
+            throw new IllegalArgumentException("A range must have no more than " + Integer.MAX_VALUE + " elements but attempted " + size + " elements");
+        }
+    }
+
+    /**
+     * A method for determining from and to information when using this IntRange to index an aggregate object of the specified size.
+     * Normally only used internally within Groovy but useful if adding range indexing support for your own aggregates.
+     *
+     * @param size the size of the aggregate being indexed
+     * @return the calculated range information (with 1 added to the to value, ready for providing to subList
+     */
+    public RangeInfo subListBorders(int size) {
+        if (inclusive == null) {
+            throw new IllegalStateException("Should not call subListBorders on a non-inclusive aware IntRange");
+        }
+        int tempFrom = from;
+        if (tempFrom < 0) {
+            tempFrom += size;
+        }
+        int tempTo = to;
+        if (tempTo < 0) {
+            tempTo += size;
+        }
+        if (tempFrom > tempTo) {
+            return new RangeInfo(inclusive ? tempTo : tempTo + 1, tempFrom + 1, true);
+        }
+        return new RangeInfo(tempFrom, inclusive ? tempTo + 1 : tempTo, false);
+    }
+
+    /**
+     * Determines if this object is equal to another object. Delegates to
+     * {@link AbstractList#equals(Object)} if <code>that</code> is anything
+     * other than an {@link IntRange}.
+     * <p>
+     * It is not necessary to override <code>hashCode</code>, as
+     * {@link AbstractList#hashCode()} provides a suitable hash code.<p>
+     * <p>
+     * Note that equals is generally handled by {@link org.codehaus.groovy.runtime.DefaultGroovyMethods#equals(List, List)}
+     * instead of this method.
+     *
+     * @param that the object to compare
+     * @return <code>true</code> if the objects are equal
+     */
+    public boolean equals(Object that) {
+        return that instanceof IntRange ? equals((IntRange) that) : super.equals(that);
+    }
+
+    /**
+     * Compares an {@link IntRange} to another {@link IntRange}.
+     *
+     * @param that the object to compare for equality
+     * @return <code>true</code> if the ranges are equal
+     */
+    public boolean equals(IntRange that) {
+        return that != null && ((inclusive == null && reverse == that.reverse && from == that.from && to == that.to)
+                || (inclusive != null && inclusive == that.inclusive && from == that.from && to == that.to));
+    }
+
+    @Override
+    public Integer getFrom() {
+        if (inclusive == null || from <= to) {
+            return from;
+        }
+        return inclusive ? to : to + 1;
+    }
+
+    @Override
+    public Integer getTo() {
+        if (inclusive == null) {
+            return to;
+        }
+        if (from <= to) {
+            return inclusive ? to : to - 1;
+        }
+        return from;
+    }
+
+    /**
+     * Returns the inclusive flag. Null for non-inclusive aware ranges or non-null for inclusive aware ranges.
+     */
+    public Boolean getInclusive() {
+        return inclusive;
+    }
+
+    /**
+     * Gets the 'from' value as a primitive integer.
+     *
+     * @return the 'from' value as a primitive integer.
+     */
+    public int getFromInt() {
+        return getFrom();
+    }
+
+    /**
+     * Gets the 'to' value as a primitive integer.
+     *
+     * @return the 'to' value as a primitive integer.
+     */
+    public int getToInt() {
+        return getTo();
+    }
+
+    @Override
+    public boolean isReverse() {
+        return inclusive == null ? reverse : (from > to);
+    }
+
+    @Override
+    public boolean containsWithinBounds(Object o) {
+        return contains(o);
+    }
+
+    @Override
+    public Integer get(int index) {
+        if (index < 0) {
+            throw new IndexOutOfBoundsException("Index: " + index + " should not be negative");
+        }
+        if (index >= size()) {
+            throw new IndexOutOfBoundsException("Index: " + index + " too big for range: " + this);
+        }
+        return isReverse() ? getTo() - index : index + getFrom();
+    }
+
+    @Override
+    public int size() {
+        return getTo() - getFrom() + 1;
+    }
+
+    @Override
+    public Iterator<Integer> iterator() {
+        return new IntRangeIterator();
+    }
+
+    @Override
+    public List<Integer> subList(int fromIndex, int toIndex) {
+        if (fromIndex < 0) {
+            throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);
+        }
+        if (toIndex > size()) {
+            throw new IndexOutOfBoundsException("toIndex = " + toIndex);
+        }
+        if (fromIndex > toIndex) {
+            throw new IllegalArgumentException("fromIndex(" + fromIndex + ") > toIndex(" + toIndex + ")");
+        }
+
+        if (fromIndex == toIndex) {
+            return new EmptyRange<Integer>(getFrom());
+        }
+
+        return new IntRange(fromIndex + getFrom(), toIndex + getFrom() - 1, isReverse());
+    }
+
+    public String toString() {
+        return inclusive != null ? ("" + from + ".." + (inclusive ? "" : "<") + to)
+                : (reverse ? "" + to + ".." + from : "" + from + ".." + to);
+    }
+
+    @Override
+    public String inspect() {
+        return toString();
+    }
+
+    @Override
+    public boolean contains(Object value) {
+        if (value instanceof Integer) {
+            return (Integer) value >= getFrom() && (Integer) value <= getTo();
+        }
+        if (value instanceof BigInteger) {
+            final BigInteger bigint = (BigInteger) value;
+            return bigint.compareTo(BigInteger.valueOf(getFrom())) >= 0 &&
+                    bigint.compareTo(BigInteger.valueOf(getTo())) <= 0;
+        }
+        return false;
+    }
+
+    @Override
+    public boolean containsAll(Collection other) {
+        if (other instanceof IntRange) {
+            final IntRange range = (IntRange) other;
+            return getFrom() <= range.getFrom() && range.getTo() <= getTo();
+        }
+        return super.containsAll(other);
+    }
+
+    @Override
+    public void step(int step, Closure closure) {
+        if (step == 0) {
+            if (!getFrom().equals(getTo())) {
+                throw new GroovyRuntimeException("Infinite loop detected due to step size of 0");
+            }
+            return; // from == to and step == 0, nothing to do, so return
+        }
+
+        if (isReverse()) {
+            step = -step;
+        }
+        if (step > 0) {
+            int value = getFrom();
+            while (value <= getTo()) {
+                closure.call(value);
+                if (((long) value + step) >= Integer.MAX_VALUE) {
+                    break;
+                }
+                value = value + step;
+            }
+        } else {
+            int value = getTo();
+            while (value >= getFrom()) {
+                closure.call(value);
+                if (((long) value + step) <= Integer.MIN_VALUE) {
+                    break;
+                }
+                value = value + step;
+            }
+        }
+    }
+
+    @Override
+    public List<Integer> step(int step) {
+        final IteratorClosureAdapter<Integer> adapter = new IteratorClosureAdapter<Integer>(this);
+        step(step, adapter);
+        return adapter.asList();
+    }
+
+    @Override
+    public int hashCode(){
+        int hashCode;
+        final int from = this.getFrom();
+        final int to = this.getTo();
+
+        hashCode = ((from+to+1)*(from+to))/2+to;
+        return hashCode;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0ad8c07c/src/main/groovy/groovy/lang/Interceptor.java
----------------------------------------------------------------------
diff --git a/src/main/groovy/groovy/lang/Interceptor.java b/src/main/groovy/groovy/lang/Interceptor.java
new file mode 100644
index 0000000..e496f1d
--- /dev/null
+++ b/src/main/groovy/groovy/lang/Interceptor.java
@@ -0,0 +1,52 @@
+/*
+ *  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;
+
+/**
+ * Implementers of this interface can be registered in the ProxyMetaClass for
+ * notifications about method calls for objects managed by the ProxyMetaClass.
+ * See groovy/lang/InterceptorTest.groovy for details.
+ * @author Dierk Koenig
+ */
+public interface Interceptor {
+    /**
+     * This code is executed before the method is optionally called.
+     * @param object        receiver object for the method call
+     * @param methodName    name of the method to call
+     * @param arguments     arguments to the method call
+     * @return any arbitrary result that replaces the result of the
+     * original method call only if doInvoke() returns false and afterInvoke()
+     * relays this result.
+     */
+    Object beforeInvoke(Object object, String methodName, Object[] arguments);
+    /**
+     * This code is executed after the method is optionally called.
+     * @param object        receiver object for the called method
+     * @param methodName    name of the called method
+     * @param arguments     arguments to the called method
+     * @param result        result of the executed method call or result of beforeInvoke if method was not called
+     * @return any arbitrary result that can replace the result of the
+     * original method call. Typically, the result parameter is returned.
+     */
+    Object afterInvoke(Object object, String methodName, Object[] arguments, Object result);
+    /**
+     * @return whether the target method should be invoked at all.
+     */
+    boolean doInvoke();
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0ad8c07c/src/main/groovy/groovy/lang/Lazy.java
----------------------------------------------------------------------
diff --git a/src/main/groovy/groovy/lang/Lazy.java b/src/main/groovy/groovy/lang/Lazy.java
new file mode 100644
index 0000000..17f044f
--- /dev/null
+++ b/src/main/groovy/groovy/lang/Lazy.java
@@ -0,0 +1,156 @@
+/*
+ *  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.transform.GroovyASTTransformationClass;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Field annotation to simplify lazy initialization.
+ * <p>
+ * Example usage without any special modifiers just defers initialization until the first call but is not thread-safe:
+ * <pre>
+ * {@code @Lazy} T x
+ * </pre>
+ * becomes
+ * <pre>
+ * private T $x
+ *
+ * T getX() {
+ *    if ($x != null)
+ *       return $x
+ *    else {
+ *       $x = new T()
+ *       return $x
+ *    }
+ * }
+ * </pre>
+ *
+ * If the field is declared volatile then initialization will be synchronized using
+ * the <a href="http://en.wikipedia.org/wiki/Double-checked_locking">double-checked locking</a> pattern as shown here:
+ *
+ * <pre>
+ * {@code @Lazy} volatile T x
+ * </pre>
+ * becomes
+ * <pre>
+ * private volatile T $x
+ *
+ * T getX() {
+ *    T $x_local = $x
+ *    if ($x_local != null)
+ *       return $x_local
+ *    else {
+ *       synchronized(this) {
+ *          if ($x == null) {
+ *             $x = new T()
+ *          }
+ *          return $x
+ *       }
+ *    }
+ * }
+ * </pre>
+ *
+ * By default a field will be initialized by calling its default constructor.
+ *
+ * If the field has an initial value expression then this expression will be used instead of calling the default constructor.
+ * In particular, it is possible to use closure <code>{ ... } ()</code> syntax as follows:
+ *
+ * <pre>
+ * {@code @Lazy} T x = { [1, 2, 3] } ()
+ * </pre>
+ * becomes
+ * <pre>
+ * private T $x
+ *
+ * T getX() {
+ *    T $x_local = $x
+ *    if ($x_local != null)
+ *       return $x_local
+ *    else {
+ *       synchronized(this) {
+ *          if ($x == null) {
+ *             $x = { [1, 2, 3] } ()
+ *          }
+ *          return $x
+ *       }
+ *    }
+ * }
+ * </pre>
+ * <p>
+ * <code>@Lazy(soft=true)</code> will use a soft reference instead of the field and use the above rules each time re-initialization is required.
+ * <p>
+ * If the <code>soft</code> flag for the annotation is not set but the field is static, then
+ * the <a href="http://en.wikipedia.org/wiki/Initialization_on_demand_holder_idiom">initialization on demand holder idiom</a> is
+ * used as follows:
+ * <pre>
+ * {@code @Lazy} static FieldType field
+ * {@code @Lazy} static Date date1
+ * {@code @Lazy} static Date date2 = { new Date().copyWith(year: 2000) }()
+ * {@code @Lazy} static Date date3 = new GregorianCalendar(2009, Calendar.JANUARY, 1).time
+ * </pre>
+ * becomes these methods and inners classes within the class containing the above definitions:
+ * <pre>
+ * private static class FieldTypeHolder_field {
+ *     private static final FieldType INSTANCE = new FieldType()
+ * }
+ *
+ * private static class DateHolder_date1 {
+ *     private static final Date INSTANCE = new Date()
+ * }
+ *
+ * private static class DateHolder_date2 {
+ *     private static final Date INSTANCE = { new Date().copyWith(year: 2000) }()
+ * }
+ *
+ * private static class DateHolder_date3 {
+ *     private static final Date INSTANCE = new GregorianCalendar(2009, Calendar.JANUARY, 1).time
+ * }
+ *
+ * static FieldType getField() {
+ *     return FieldTypeHolder_field.INSTANCE
+ * }
+ *
+ * static Date getDate1() {
+ *     return DateHolder_date1.INSTANCE
+ * }
+ *
+ * static Date getDate2() {
+ *     return DateHolder_date2.INSTANCE
+ * }
+ *
+ * static Date getDate3() {
+ *     return DateHolder_date3.INSTANCE
+ * }
+ * </pre>
+ */
+@java.lang.annotation.Documented
+@Retention(RetentionPolicy.SOURCE)
+@Target({ElementType.FIELD})
+@GroovyASTTransformationClass("org.codehaus.groovy.transform.LazyASTTransformation")
+public @interface Lazy {
+    /**
+     * @return if field should be soft referenced instead of hard referenced
+     */
+    boolean soft () default false;
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0ad8c07c/src/main/groovy/groovy/lang/ListWithDefault.java
----------------------------------------------------------------------
diff --git a/src/main/groovy/groovy/lang/ListWithDefault.java b/src/main/groovy/groovy/lang/ListWithDefault.java
new file mode 100644
index 0000000..6b87548
--- /dev/null
+++ b/src/main/groovy/groovy/lang/ListWithDefault.java
@@ -0,0 +1,257 @@
+/*
+ *  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 java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+
+/**
+ * A wrapper for {@link List} which automatically grows the list when either {@link #get(int)} or
+ * {@link #getAt(int)} is called with an index greater than or equal to {@code size()}.
+ *
+ * @author Andre Steingress
+ * @since 1.8.7
+ */
+public final class ListWithDefault<T> implements List<T> {
+
+    private final List<T> delegate;
+    private final boolean lazyDefaultValues;
+
+    private final Closure initClosure;
+
+    private ListWithDefault(List<T> items, boolean lazyDefaultValues, Closure initClosure) {
+        this.delegate = items;
+        this.lazyDefaultValues = lazyDefaultValues;
+        this.initClosure = initClosure;
+    }
+
+    public List<T> getDelegate() {
+        return delegate != null ? new ArrayList<T>(delegate) : null;
+    }
+
+    public boolean isLazyDefaultValues() {
+        return lazyDefaultValues;
+    }
+
+    public Closure getInitClosure() {
+        return initClosure != null ? (Closure) initClosure.clone() : null;
+    }
+
+    public static <T> ListWithDefault<T> newInstance(List<T> items, boolean lazyDefaultValues, Closure initClosure) {
+        if (items == null)
+            throw new IllegalArgumentException("Parameter \"items\" must not be null");
+        if (initClosure == null)
+            throw new IllegalArgumentException("Parameter \"initClosure\" must not be null");
+
+        return new ListWithDefault<T>(new ArrayList<T>(items), lazyDefaultValues, (Closure) initClosure.clone());
+    }
+
+    public int size() {
+        return delegate.size();
+    }
+
+    public boolean isEmpty() {
+        return delegate.isEmpty();
+    }
+
+    public boolean contains(Object o) {
+        return delegate.contains(o);
+    }
+
+    public Iterator<T> iterator() {
+        return delegate.iterator();
+    }
+
+    public Object[] toArray() {
+        return delegate.toArray();
+    }
+
+    public <T> T[] toArray(T[] ts) {
+        return delegate.toArray(ts);
+    }
+
+    public boolean add(T t) {
+        return delegate.add(t);
+    }
+
+    public boolean remove(Object o) {
+        return delegate.remove(o);
+    }
+
+    public boolean containsAll(Collection<?> objects) {
+        return delegate.containsAll(objects);
+    }
+
+    public boolean addAll(Collection<? extends T> ts) {
+        return delegate.addAll(ts);
+    }
+
+    public boolean addAll(int i, Collection<? extends T> ts) {
+        return delegate.addAll(i, ts);
+    }
+
+    public boolean removeAll(Collection<?> objects) {
+        return delegate.removeAll(objects);
+    }
+
+    public boolean retainAll(Collection<?> objects) {
+        return delegate.retainAll(objects);
+    }
+
+    public void clear() {
+        delegate.clear();
+    }
+
+    /**
+     * Overwrites subscript operator handling by redirecting to {@link #get(int)}.
+     *
+     * @param index an index (might be greater or equal to {@code size()}, or smaller than 0)
+     * @return the value at the given {@code index} or the default value
+     */
+    public T getAt(int index) {
+        return get(index);
+    }
+
+    /**
+     * Returns the element at the given index but grows the list if needed. If the requested {@code index} is
+     * greater than or equal to {@code size()}, the list will grow to the new size and a default value calculated
+     * using the <code>initClosure</code> will be used to populate the missing value and returned.
+     * <p>
+     * If <code>lazyDefaultValues</code> is <code>true</code> any gaps when growing the list are filled
+     * with nulls. Subsequent attempts to retrieve items from the list from those gap index values
+     * will, upon finding null, call the <code>initClosure</code> to populate the list for the
+     * given list value. Hence, when in this mode, nulls cannot be stored in this list.
+     * If <code>lazyDefaultValues</code> is <code>false</code> any gaps when growing the list are filled
+     * eagerly by calling the <code>initClosure</code> for all gap indexes during list growth.
+     * No calls to <code>initClosure</code> are made except during list growth and it is ok to
+     * store null values in the list when in this mode.
+     * <p>
+     * This implementation breaks
+     * the contract of {@link java.util.List#get(int)} as it a) possibly modifies the underlying list and b) does
+     * NOT throw an {@link IndexOutOfBoundsException} when {@code index < 0 || index >= size()}.
+     *
+     * @param index an index (might be greater or equal to {@code size()}, or smaller than 0)
+     * @return the value at the given {@code index} or the default value
+     */
+    public T get(int index) {
+
+        final int size = size();
+        int normalisedIndex = normaliseIndex(index, size);
+        if (normalisedIndex < 0) {
+            throw new IndexOutOfBoundsException("Negative index [" + normalisedIndex + "] too large for list size " + size);
+        }
+
+        // either index >= size or the normalised index is negative
+        if (normalisedIndex >= size) {
+            // find out the number of gaps to fill with null/the default value
+            final int gapCount = normalisedIndex - size;
+
+            // fill all gaps
+            for (int i = 0; i < gapCount; i++) {
+                final int idx = size();
+
+                // if we lazily create default values, use 'null' as placeholder
+                if (lazyDefaultValues)
+                    delegate.add(idx, null);
+                else
+                    delegate.add(idx, getDefaultValue(idx));
+            }
+
+            // add the first/last element being always the default value
+            final int idx = normalisedIndex;
+            delegate.add(idx, getDefaultValue(idx));
+
+            // normalise index again to get positive index
+            normalisedIndex = normaliseIndex(index, size());
+        }
+
+        T item = delegate.get(normalisedIndex);
+        if (item == null && lazyDefaultValues) {
+            item = getDefaultValue(normalisedIndex);
+            delegate.set(normalisedIndex, item);
+        }
+
+        return item;
+    }
+
+    @SuppressWarnings("unchecked")
+    private T getDefaultValue(int idx) {
+        return (T) initClosure.call(new Object[]{idx});
+    }
+
+    private static int normaliseIndex(int index, int size) {
+        if (index < 0) {
+            index += size;
+        }
+        return index;
+    }
+
+    public T set(int i, T t) {
+        return delegate.set(i, t);
+    }
+
+    public void add(int i, T t) {
+        delegate.add(i, t);
+    }
+
+    public T remove(int i) {
+        return delegate.remove(i);
+    }
+
+    public int indexOf(Object o) {
+        return delegate.indexOf(o);
+    }
+
+    public int lastIndexOf(Object o) {
+        return delegate.lastIndexOf(o);
+    }
+
+    public ListIterator<T> listIterator() {
+        return delegate.listIterator();
+    }
+
+    public ListIterator<T> listIterator(int i) {
+        return delegate.listIterator(i);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        return delegate.equals(obj);
+    }
+
+    @Override
+    public int hashCode() {
+        return delegate.hashCode();
+    }
+
+    /**
+     * Returns a view of a portion of this list. This method returns a list with the same
+     * lazy list settings as the original list.
+     *
+     * @param fromIndex low endpoint of the subList (inclusive)
+     * @param toIndex   upper endpoint of the subList (exclusive)
+     * @return a view of a specified range within this list, keeping all lazy list settings
+     */
+    public ListWithDefault<T> subList(int fromIndex, int toIndex) {
+        return new ListWithDefault<T>(delegate.subList(fromIndex, toIndex), lazyDefaultValues, (Closure) initClosure.clone());
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0ad8c07c/src/main/groovy/groovy/lang/MapWithDefault.java
----------------------------------------------------------------------
diff --git a/src/main/groovy/groovy/lang/MapWithDefault.java b/src/main/groovy/groovy/lang/MapWithDefault.java
new file mode 100644
index 0000000..166e06b
--- /dev/null
+++ b/src/main/groovy/groovy/lang/MapWithDefault.java
@@ -0,0 +1,105 @@
+/*
+ *  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 java.util.Collection;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * A wrapper for Map which allows a default value to be specified.
+ *
+ * @author Paul King
+ * @since 1.7.1
+ */
+public final class MapWithDefault<K, V> implements Map<K, V> {
+
+    private final Map<K, V> delegate;
+    private final Closure initClosure;
+
+    private MapWithDefault(Map<K, V> m, Closure initClosure) {
+        delegate = m;
+        this.initClosure = initClosure;
+    }
+
+    public static <K, V> Map<K, V> newInstance(Map<K, V> m, Closure initClosure) {
+        return new MapWithDefault<K, V>(m, initClosure);
+    }
+
+    public int size() {
+        return delegate.size();
+    }
+
+    public boolean isEmpty() {
+        return delegate.isEmpty();
+    }
+
+    public boolean containsKey(Object key) {
+        return delegate.containsKey(key);
+    }
+
+    public boolean containsValue(Object value) {
+        return delegate.containsValue(value);
+    }
+
+    public V get(Object key) {
+        if (!delegate.containsKey(key)) {
+            delegate.put((K)key, (V)initClosure.call(new Object[]{key}));
+        }
+        return delegate.get(key);
+    }
+
+    public V put(K key, V value) {
+        return delegate.put(key, value);
+    }
+
+    public V remove(Object key) {
+        return delegate.remove(key);
+    }
+
+    public void putAll(Map<? extends K, ? extends V> m) {
+        delegate.putAll(m);
+    }
+
+    public void clear() {
+        delegate.clear();
+    }
+
+    public Set<K> keySet() {
+        return delegate.keySet();
+    }
+
+    public Collection<V> values() {
+        return delegate.values();
+    }
+
+    public Set<Map.Entry<K, V>> entrySet() {
+        return delegate.entrySet();
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        return delegate.equals(obj);
+    }
+
+    @Override
+    public int hashCode() {
+        return delegate.hashCode();
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/groovy/blob/0ad8c07c/src/main/groovy/groovy/lang/MetaArrayLengthProperty.java
----------------------------------------------------------------------
diff --git a/src/main/groovy/groovy/lang/MetaArrayLengthProperty.java b/src/main/groovy/groovy/lang/MetaArrayLengthProperty.java
new file mode 100644
index 0000000..8310386
--- /dev/null
+++ b/src/main/groovy/groovy/lang/MetaArrayLengthProperty.java
@@ -0,0 +1,56 @@
+/*
+ *  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;
+
+
+/**
+ * Represents the length property of an array
+ *
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ */
+public class MetaArrayLengthProperty extends MetaProperty {
+
+    /**
+     * Sole constructor setting name to "length" and type to int
+     */
+    public MetaArrayLengthProperty() {
+        super("length", int.class);
+    }
+
+    /**
+     * Get this property from the given object.
+     * @param object an array
+     * @return the length of the array object
+     * @throws IllegalArgumentException if object is not an array
+     */
+    public Object getProperty(Object object) {
+        return java.lang.reflect.Array.getLength(object);
+    }
+
+    /**
+     * Sets the property on the given object to the new value
+     *
+     * @param object   on which to set the property
+     * @param newValue the new value of the property
+     * @throws RuntimeException if the property could not be set
+     */
+    public void setProperty(Object object, Object newValue) {
+        throw new ReadOnlyPropertyException("length", object.getClass());
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0ad8c07c/src/main/groovy/groovy/lang/MetaBeanProperty.java
----------------------------------------------------------------------
diff --git a/src/main/groovy/groovy/lang/MetaBeanProperty.java b/src/main/groovy/groovy/lang/MetaBeanProperty.java
new file mode 100644
index 0000000..89328af
--- /dev/null
+++ b/src/main/groovy/groovy/lang/MetaBeanProperty.java
@@ -0,0 +1,156 @@
+/*
+ *  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.reflection.CachedField;
+import org.codehaus.groovy.runtime.MetaClassHelper;
+import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
+
+import java.lang.reflect.Modifier;
+
+/**
+ * Represents a property on a bean which may have a getter and/or a setter
+ */
+public class MetaBeanProperty extends MetaProperty {
+
+    private MetaMethod getter;
+    private MetaMethod setter;
+    private CachedField field;
+
+    /**
+     * Sole constructor setting name, type (class), getter and setter.
+     */
+    public MetaBeanProperty(String name, Class type, MetaMethod getter, MetaMethod setter) {
+        super(name, type);
+        this.getter = getter;
+        this.setter = setter;
+    }
+
+    /**
+     * Get the property of the given object.
+     *
+     * @param object which to be got
+     * @return the property of the given object
+     * @throws RuntimeException if the property could not be evaluated
+     */
+    public Object getProperty(Object object) {
+        MetaMethod getter = getGetter();
+        if (getter == null) {
+            if (field != null) return field.getProperty(object);
+            //TODO: create a WriteOnlyException class?
+            throw new GroovyRuntimeException("Cannot read write-only property: " + name);
+        }
+        return getter.invoke(object, MetaClassHelper.EMPTY_ARRAY);
+    }
+
+    /**
+     * Set the property on the given object to the new value.
+     *
+     * @param object   on which to set the property
+     * @param newValue the new value of the property
+     * @throws RuntimeException if the property could not be set
+     */
+    public void setProperty(Object object, Object newValue) {
+        MetaMethod setter = getSetter();
+        if (setter == null) {
+            if (field != null && !Modifier.isFinal(field.getModifiers())) {
+                field.setProperty(object, newValue);
+                return;
+            }
+            throw new GroovyRuntimeException("Cannot set read-only property: " + name);
+        }
+        newValue = DefaultTypeTransformation.castToType(newValue, getType());
+        setter.invoke(object, new Object[]{newValue});
+    }
+
+    /**
+     * Get the getter method.
+     *
+     * @return the getter method for this property.
+     */
+    public MetaMethod getGetter() {
+        return getter;
+    }
+
+    /**
+     * Get the setter method.
+     *
+     * @return the setter method for this property.
+     */
+    public MetaMethod getSetter() {
+        return setter;
+    }
+
+    /**
+     * This is for MetaClass to patch up the object later when looking for get*() methods.
+     *
+     * @param getter The getter for this property
+     */
+    void setGetter(MetaMethod getter) {
+        this.getter = getter;
+    }
+
+    /**
+     * This is for MetaClass to patch up the object later when looking for set*() methods.
+     *
+     * @param setter The setter for this property 
+     */
+    void setSetter(MetaMethod setter) {
+        this.setter = setter;
+    }
+
+    /**
+     * Gets the visibility modifiers for the property as defined by the getter and setter methods.
+     *
+     * @return the visibility modifier of the getter, the setter, or both depending on which exist
+     */
+    public int getModifiers() {
+        MetaMethod getter = getGetter();
+        MetaMethod setter = getSetter();
+        if (setter != null && getter == null) return setter.getModifiers();
+        if (getter != null && setter == null) return getter.getModifiers();
+        int modifiers = getter.getModifiers() | setter.getModifiers();
+        int visibility = 0;
+        if (Modifier.isPublic(modifiers)) visibility = Modifier.PUBLIC;
+        if (Modifier.isProtected(modifiers)) visibility = Modifier.PROTECTED;
+        if (Modifier.isPrivate(modifiers)) visibility = Modifier.PRIVATE;
+        int states = getter.getModifiers() & setter.getModifiers();
+        states &= ~(Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE);
+        states |= visibility;
+        return states;
+    }
+
+    /**
+     * Sets the field of this property
+     *
+     * @param field
+     */
+    public void setField(CachedField field) {
+        this.field = field;
+    }
+
+    /**
+     * Gets the field of this property
+     *
+     * @return The field of this property
+     */
+    public CachedField getField() {
+        return field;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0ad8c07c/src/main/groovy/groovy/lang/MetaClass.java
----------------------------------------------------------------------
diff --git a/src/main/groovy/groovy/lang/MetaClass.java b/src/main/groovy/groovy/lang/MetaClass.java
new file mode 100644
index 0000000..42c6a83
--- /dev/null
+++ b/src/main/groovy/groovy/lang/MetaClass.java
@@ -0,0 +1,207 @@
+/*
+ *  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.ast.ClassNode;
+
+import java.util.List;
+
+/**
+ * A MetaClass within Groovy defines the behaviour of any given Groovy or Java class. The MetaClass
+ * interface defines two parts. The client API, which is defined via the extend MetaObjectProtocol interface
+ * and the contract with the Groovy runtime system.
+ *
+ * In general the compiler and Groovy runtime engine interact with methods on this class whilst MetaClass
+ * clients interact with the method defined by the MetaObjectProtocol interface
+ *
+ * @see MetaClassImpl
+ * @see groovy.lang.MetaObjectProtocol
+ * 
+ * @author John Wilson
+ * @author Graeme Rocher
+ */
+public interface MetaClass extends MetaObjectProtocol {
+
+    /**
+     * <p>Invokes a method on the given receiver for the specified arguments. The sender is the class that invoked the method on the object.
+     * The MetaClass will attempt to establish the method to invoke based on the name and arguments provided.
+     *
+     * <p>The isCallToSuper and fromInsideClass help the Groovy runtime perform optimisations on the call to go directly
+     * to the super class if necessary
+     *
+     * @param sender The java.lang.Class instance that invoked the method
+     * @param receiver The object which the method was invoked on
+     * @param methodName The name of the method
+     * @param arguments The arguments to the method
+     * @param isCallToSuper Whether the method is a call to a super class method
+     * @param fromInsideClass Whether the call was invoked from the inside or the outside of the class
+     *
+     * @return The return value of the method
+     */
+     Object invokeMethod(Class sender, Object receiver, String methodName, Object[] arguments, boolean isCallToSuper, boolean fromInsideClass);
+
+    /**
+     * <p>Retrieves a property on the given receiver for the specified arguments. The sender is the class that is requesting the property from the object.
+     * The MetaClass will attempt to establish the method to invoke based on the name and arguments provided.
+     *
+     * <p>The isCallToSuper and fromInsideClass help the Groovy runtime perform optimisations on the call to go directly
+     * to the super class if necessary
+     *
+     * @param sender The java.lang.Class instance that requested the property
+     * @param receiver The Object which the property is being retrieved from
+     * @param property The name of the property
+     * @param isCallToSuper Whether the call is to a super class property
+     * @param fromInsideClass ??
+     *
+     * @return The properties value
+     */
+     Object getProperty(Class sender, Object receiver, String property, boolean isCallToSuper, boolean fromInsideClass);
+
+    /**
+     * <p>Sets a property on the given receiver for the specified arguments. The sender is the class that is setting the property from the object.
+     * The MetaClass will attempt to establish the method to invoke based on the name and arguments provided.
+     *
+     * <p>The isCallToSuper and fromInsideClass help the Groovy runtime perform optimisations on the call to go directly
+     * to the super class if necessary
+     *
+     * @param sender The java.lang.Class instance that is mutating the property
+     * @param receiver The Object which the property is being set on
+     * @param property The name of the property
+     * @param value The new value of the property to set
+     * @param isCallToSuper Whether the call is to a super class property
+     * @param fromInsideClass Whether the call was invoked from the inside or the outside of the class
+     */
+     void setProperty(Class sender, Object receiver, String property, Object value, boolean isCallToSuper, boolean fromInsideClass);
+
+    /**
+     *
+     * <p>Attempts to invoke the methodMissing method otherwise throws a MissingMethodException
+     *
+     * @see groovy.lang.MissingMethodException
+     *
+     * @param instance The instance to invoke methodMissing on
+     * @param methodName The name of the method
+     * @param arguments The arguments to the method
+     * @return The results of methodMissing or throws MissingMethodException
+     */
+     Object invokeMissingMethod(Object instance, String methodName, Object[] arguments);
+
+    /**
+     * Invokes the propertyMissing method otherwise throws a MissingPropertyException
+     *
+     * @param instance The instance of the class
+     * @param propertyName The name of the property
+     * @param optionalValue The value of the property which could be null in the case of a getter
+     * @param isGetter Whether the missing property event was the result of a getter or a setter
+     * 
+     * @return The result of the propertyMissing method or throws MissingPropertyException
+     */
+     Object invokeMissingProperty(Object instance, String propertyName, Object optionalValue, boolean isGetter);
+
+    /**
+     * Retrieves the value of an attribute (field). This method is to support the Groovy runtime and not for general client API usage.
+     *
+     * @param sender The class of the object that requested the attribute
+     * @param receiver The instance
+     * @param messageName The name of the attribute
+     * @param useSuper Whether to look-up on the super class or not
+     * @return The attribute value
+     */
+     Object getAttribute(Class sender, Object receiver, String messageName, boolean useSuper);
+
+    /**
+     * Sets the value of an attribute (field). This method is to support the Groovy runtime and not for general client API usage.
+     *
+     * @param sender The class of the object that requested the attribute
+     * @param receiver The instance
+     * @param messageName The name of the attribute
+     * @param messageValue The value of the attribute
+     * @param useSuper Whether to look-up on the super class or not
+     * @param fromInsideClass Whether the call happened from the inside or the outside of a class
+     */
+     void setAttribute(Class sender, Object receiver, String messageName, Object messageValue, boolean useSuper, boolean fromInsideClass);
+    
+    /**
+     * Complete the initialisation process. After this method
+     * is called no methods should be added to the meta class.
+     * Invocation of methods or access to fields/properties is
+     * forbidden unless this method is called. This method 
+     * should contain any initialisation code, taking a longer
+     * time to complete. An example is the creation of the 
+     * Reflector. It is suggested to synchronize this 
+     * method.
+     */
+     void initialize();
+
+    /**
+     * Retrieves a list of MetaProperty instances that the MetaClass has
+     *
+     * @see MetaProperty
+     *
+     * @return A list of MetaProperty instances
+     */
+     List<MetaProperty> getProperties();
+
+    /**
+     * Retrieves a list of MetaMethods held by the class. This list does not include MetaMethods added by groovy.lang.ExpandoMetaClass.
+     *
+     * @return A list of MetaMethods
+     */
+     List<MetaMethod> getMethods();
+     
+     /**
+      * Obtains a reference to the original AST for the MetaClass if it is available at runtime
+      *
+      * @return The original AST or null if it cannot be returned
+      */
+     ClassNode getClassNode();
+
+     /**
+      * Retrieves a list of MetaMethods held by this class. This list includes MetaMethods added by groovy.lang.ExpandoMetaClass.
+      *
+      * @return A list of MetaMethods
+      */
+     List<MetaMethod> getMetaMethods();
+    
+     /**
+      *
+      * Internal method to support Groovy runtime. Not for client usage.
+      *
+      * @param numberOfConstructors The number of constructors
+      * @param arguments The arguments
+      *
+      * @return selected index
+      */
+     int selectConstructorAndTransformArguments(int numberOfConstructors, Object[] arguments);
+
+    /**
+     * Selects a method by name and argument classes. This method
+     * does not search for an exact match, it searches for a compatible
+     * method. For this the method selection mechanism is used as provided
+     * by the implementation of this MetaClass. pickMethod may or may
+     * not be used during the method selection process when invoking a method.
+     * There is no warranty for that.
+     *
+     * @return a matching MetaMethod or null
+     * @throws GroovyRuntimeException if there is more than one matching method
+     * @param methodName the name of the method to pick
+     * @param arguments the method arguments
+     */
+     MetaMethod pickMethod(String methodName, Class[] arguments);
+}