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

[04/57] [abbrv] [partial] groovy git commit: Move Java source set into `src/main/java`

http://git-wip-us.apache.org/repos/asf/groovy/blob/b25d0e55/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethodsSupport.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethodsSupport.java b/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethodsSupport.java
new file mode 100644
index 0000000..3838fdc
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethodsSupport.java
@@ -0,0 +1,383 @@
+/*
+ *  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 org.codehaus.groovy.runtime;
+
+import groovy.lang.EmptyRange;
+import groovy.lang.IntRange;
+import groovy.lang.Range;
+import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.lang.reflect.Array;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.Hashtable;
+import java.util.IdentityHashMap;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.PriorityQueue;
+import java.util.Properties;
+import java.util.Queue;
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.SortedSet;
+import java.util.Stack;
+import java.util.TreeMap;
+import java.util.TreeSet;
+import java.util.Vector;
+import java.util.WeakHashMap;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.ConcurrentSkipListMap;
+import java.util.concurrent.ConcurrentSkipListSet;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.CopyOnWriteArraySet;
+import java.util.concurrent.DelayQueue;
+import java.util.concurrent.LinkedBlockingDeque;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.PriorityBlockingQueue;
+import java.util.concurrent.SynchronousQueue;
+import java.util.logging.Logger;
+
+/**
+ * Support methods for DefaultGroovyMethods and PluginDefaultMethods.
+ */
+public class DefaultGroovyMethodsSupport {
+
+    private static final Logger LOG = Logger.getLogger(DefaultGroovyMethodsSupport.class.getName());
+    private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];
+
+    // helper method for getAt and putAt
+    protected static RangeInfo subListBorders(int size, Range range) {
+        if (range instanceof IntRange) {
+            return ((IntRange)range).subListBorders(size);
+        }
+        int from = normaliseIndex(DefaultTypeTransformation.intUnbox(range.getFrom()), size);
+        int to = normaliseIndex(DefaultTypeTransformation.intUnbox(range.getTo()), size);
+        boolean reverse = range.isReverse();
+        if (from > to) {
+            // support list[1..-1]
+            int tmp = to;
+            to = from;
+            from = tmp;
+            reverse = !reverse;
+        }
+        return new RangeInfo(from, to + 1, reverse);
+    }
+
+    // helper method for getAt and putAt
+    protected static RangeInfo subListBorders(int size, EmptyRange range) {
+        int from = normaliseIndex(DefaultTypeTransformation.intUnbox(range.getFrom()), size);
+        return new RangeInfo(from, from, false);
+    }
+
+    /**
+     * This converts a possibly negative index to a real index into the array.
+     *
+     * @param i    the unnormalized index
+     * @param size the array size
+     * @return the normalised index
+     */
+    protected static int normaliseIndex(int i, int size) {
+        int temp = i;
+        if (i < 0) {
+            i += size;
+        }
+        if (i < 0) {
+            throw new ArrayIndexOutOfBoundsException("Negative array index [" + temp + "] too large for array size " + size);
+        }
+        return i;
+    }
+
+    /**
+     * Close the Closeable. Logging a warning if any problems occur.
+     *
+     * @param closeable the thing to close
+     */
+    public static void closeWithWarning(Closeable closeable) {
+        tryClose(closeable, true); // ignore result
+    }
+
+    /**
+     * Attempts to close the closeable returning rather than throwing
+     * any Exception that may occur.
+     *
+     * @param closeable the thing to close
+     * @param logWarning if true will log a warning if an exception occurs
+     * @return throwable Exception from the close method, else null
+     */
+    static Throwable tryClose(AutoCloseable closeable, boolean logWarning) {
+        Throwable thrown = null;
+        if (closeable != null) {
+            try {
+                closeable.close();
+            } catch (Exception e) {
+                thrown = e;
+                if (logWarning) {
+                    LOG.warning("Caught exception during close(): " + e);
+                }
+            }
+        }
+        return thrown;
+    }
+
+    /**
+     * Close the Closeable. Ignore any problems that might occur.
+     *
+     * @param c the thing to close
+     */
+    public static void closeQuietly(Closeable c) {
+        if (c != null) {
+            try {
+                c.close();
+            } catch (IOException e) {
+                /* ignore */
+            }
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    protected static <T> Collection<T> cloneSimilarCollection(Collection<T> orig, int newCapacity) {
+        Collection<T> answer = (Collection<T>) cloneObject(orig);
+        if (answer != null) return answer;
+
+        // fall back to creation
+        answer = createSimilarCollection(orig, newCapacity);
+        answer.addAll(orig);
+        return answer;
+    }
+
+    private static Object cloneObject(Object orig) {
+        if (orig instanceof Cloneable) {
+            try {
+                return InvokerHelper.invokeMethod(orig, "clone", EMPTY_OBJECT_ARRAY);
+            } catch (Exception ex) {
+                // ignore
+            }
+        }
+        return null;
+    }
+
+    protected static Collection createSimilarOrDefaultCollection(Object object) {
+        if (object instanceof Collection) {
+            return createSimilarCollection((Collection<?>) object);
+        }
+        return new ArrayList();
+    }
+
+    protected static <T> Collection<T> createSimilarCollection(Iterable<T> iterable) {
+        if (iterable instanceof Collection) {
+            return createSimilarCollection((Collection<T>) iterable);
+        } else {
+            return new ArrayList<T>();
+        }
+    }
+
+    protected static <T> Collection<T> createSimilarCollection(Collection<T> collection) {
+        return createSimilarCollection(collection, collection.size());
+    }
+
+    protected static <T> Collection<T> createSimilarCollection(Collection<T> orig, int newCapacity) {
+        if (orig instanceof Set) {
+            return createSimilarSet((Set<T>) orig);
+        }
+        if (orig instanceof List) {
+            return createSimilarList((List<T>) orig, newCapacity);
+        }
+        if (orig instanceof Queue) {
+            return createSimilarQueue((Queue<T>) orig);
+        }
+        return new ArrayList<T>(newCapacity);
+    }
+
+    protected static <T> List<T> createSimilarList(List<T> orig, int newCapacity) {
+        if (orig instanceof LinkedList)
+            return new LinkedList<T>();
+
+        if (orig instanceof Stack)
+            return new Stack<T>();
+
+        if (orig instanceof Vector)
+            return new Vector<T>();
+
+        if (orig instanceof CopyOnWriteArrayList)
+            return new CopyOnWriteArrayList<T>();
+
+        return new ArrayList<T>(newCapacity);
+    }
+
+    @SuppressWarnings("unchecked")
+    protected static <T> T[] createSimilarArray(T[] orig, int newCapacity) {
+        Class<T> componentType = (Class<T>) orig.getClass().getComponentType();
+        return (T[]) Array.newInstance(componentType, newCapacity);
+    }
+
+    @SuppressWarnings("unchecked")
+    protected static <T> Set<T> createSimilarSet(Set<T> orig) {
+        if (orig instanceof SortedSet) {
+            Comparator comparator = ((SortedSet) orig).comparator();
+            if (orig instanceof ConcurrentSkipListSet) {
+                return new ConcurrentSkipListSet<T>(comparator);
+            } else {
+                return new TreeSet<T>(comparator);
+            }
+        } else {
+            if (orig instanceof CopyOnWriteArraySet) {
+                return new CopyOnWriteArraySet<T>();
+            } else {
+                // Do not use HashSet
+                return new LinkedHashSet<T>();
+            }
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    protected static <T> Queue<T> createSimilarQueue(Queue<T> orig) {
+        if (orig instanceof ArrayBlockingQueue) {
+            ArrayBlockingQueue queue = (ArrayBlockingQueue) orig;
+            return new ArrayBlockingQueue<T>(queue.size() + queue.remainingCapacity());
+        } else if (orig instanceof ArrayDeque) {
+            return new ArrayDeque<T>();
+        } else if (orig instanceof ConcurrentLinkedQueue) {
+            return new ConcurrentLinkedQueue<T>();
+        } else if (orig instanceof DelayQueue) {
+            return new DelayQueue();
+        } else if (orig instanceof LinkedBlockingDeque) {
+            return new LinkedBlockingDeque<T>();
+        } else if (orig instanceof LinkedBlockingQueue) {
+            return new LinkedBlockingQueue<T>();
+        } else if (orig instanceof PriorityBlockingQueue) {
+            return new PriorityBlockingQueue<T>();
+        } else if (orig instanceof PriorityQueue) {
+            return new PriorityQueue<T>(11, ((PriorityQueue) orig).comparator());
+        } else if (orig instanceof SynchronousQueue) {
+            return new SynchronousQueue<T>();
+        } else {
+            return new LinkedList<T>();
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    protected static <K, V> Map<K, V> createSimilarMap(Map<K, V> orig) {
+        if (orig instanceof SortedMap) {
+            Comparator comparator = ((SortedMap) orig).comparator();
+            if (orig instanceof ConcurrentSkipListMap) {
+                return new ConcurrentSkipListMap<K, V>(comparator);
+            } else {
+                return new TreeMap<K, V>(comparator);
+            }
+        } else {
+            if (orig instanceof ConcurrentHashMap) {
+                return new ConcurrentHashMap<K, V>();
+            } else if (orig instanceof Hashtable) {
+                if (orig instanceof Properties) {
+                    return (Map<K, V>) new Properties();
+                } else {
+                    return new Hashtable<K, V>();
+                }
+            } else if (orig instanceof IdentityHashMap) {
+                return new IdentityHashMap<K, V>();
+            } else if (orig instanceof WeakHashMap) {
+                return new WeakHashMap<K, V>();
+            } else {
+                // Do not use HashMap
+                return new LinkedHashMap<K, V>();
+            }
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    protected static <K, V> Map<K ,V> cloneSimilarMap(Map<K, V> orig) {
+        Map<K, V> answer = (Map<K, V>) cloneObject(orig);
+        if (answer != null) return answer;
+
+        // fall back to some defaults
+        if (orig instanceof SortedMap) {
+            if (orig instanceof ConcurrentSkipListMap) {
+                return new ConcurrentSkipListMap<K, V>(orig);
+            } else {
+                return new TreeMap<K, V>(orig);
+            }
+        } else {
+            if (orig instanceof ConcurrentHashMap) {
+                return new ConcurrentHashMap<K, V>(orig);
+            } else if (orig instanceof Hashtable) {
+                if (orig instanceof Properties) {
+                    Map<K, V> map = (Map<K, V>) new Properties();
+                    map.putAll(orig);
+                    return map;
+                } else {
+                    return new Hashtable<K, V>(orig);
+                }
+            } else if (orig instanceof IdentityHashMap) {
+                return new IdentityHashMap<K, V>(orig);
+            } else if (orig instanceof WeakHashMap) {
+                return new WeakHashMap<K, V>(orig);
+            } else {
+                // Do not use HashMap
+                return new LinkedHashMap<K, V>(orig);
+            }
+        }
+    }
+
+    /**
+     * Determines if all items of this array are of the same type.
+     *
+     * @param cols an array of collections
+     * @return true if the collections are all of the same type
+     */
+    @SuppressWarnings("unchecked")
+    protected static boolean sameType(Collection[] cols) {
+        List all = new LinkedList();
+        for (Collection col : cols) {
+            all.addAll(col);
+        }
+        if (all.isEmpty())
+            return true;
+
+        Object first = all.get(0);
+
+        //trying to determine the base class of the collections
+        //special case for Numbers
+        Class baseClass;
+        if (first instanceof Number) {
+            baseClass = Number.class;
+        } else if (first == null) {
+            baseClass = NullObject.class;
+        } else {
+            baseClass = first.getClass();
+        }
+
+        for (Collection col : cols) {
+            for (Object o : col) {
+                if (!baseClass.isInstance(o)) {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/b25d0e55/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyStaticMethods.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyStaticMethods.java b/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyStaticMethods.java
new file mode 100644
index 0000000..1c85e91
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyStaticMethods.java
@@ -0,0 +1,314 @@
+/*
+ *  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 org.codehaus.groovy.runtime;
+
+import groovy.lang.Closure;
+import org.codehaus.groovy.reflection.ReflectionUtils;
+import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
+
+import java.io.File;
+import java.io.IOException;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+import java.util.ResourceBundle;
+import java.util.TimeZone;
+import java.util.regex.Matcher;
+
+/**
+ * This class defines all the new static groovy methods which appear on normal
+ * JDK classes inside the Groovy environment. Static methods are used with the
+ * first parameter as the destination class.
+ *
+ * @author Guillaume Laforge
+ * @author Dierk Koenig
+ * @author Joachim Baumann
+ * @author Paul King
+ * @author Kent Inge Fagerland Simonsen
+ */
+public class DefaultGroovyStaticMethods {
+
+    /**
+     * Start a Thread with the given closure as a Runnable instance.
+     *
+     * @param self    placeholder variable used by Groovy categories; ignored for default static methods
+     * @param closure the Runnable closure
+     * @return the started thread
+     * @since 1.0
+     */
+    public static Thread start(Thread self, Closure closure) {
+        return createThread(null, false, closure);
+    }
+
+    /**
+     * Start a Thread with a given name and the given closure
+     * as a Runnable instance.
+     *
+     * @param self    placeholder variable used by Groovy categories; ignored for default static methods
+     * @param name    the name to give the thread
+     * @param closure the Runnable closure
+     * @return the started thread
+     * @since 1.6
+     */
+    public static Thread start(Thread self, String name, Closure closure) {
+        return createThread(name, false, closure);
+    }
+
+    /**
+     * Start a daemon Thread with the given closure as a Runnable instance.
+     *
+     * @param self    placeholder variable used by Groovy categories; ignored for default static methods
+     * @param closure the Runnable closure
+     * @return the started thread
+     * @since 1.0
+     */
+    public static Thread startDaemon(Thread self, Closure closure) {
+        return createThread(null, true, closure);
+    }
+
+    /**
+     * Start a daemon Thread with a given name and the given closure as
+     * a Runnable instance.
+     *
+     * @param self    placeholder variable used by Groovy categories; ignored for default static methods
+     * @param name    the name to give the thread
+     * @param closure the Runnable closure
+     * @return the started thread
+     * @since 1.6
+     */
+    public static Thread startDaemon(Thread self, String name, Closure closure) {
+        return createThread(name, true, closure);
+    }
+
+    private static Thread createThread(String name, boolean daemon, Closure closure) {
+        Thread thread = name != null ? new Thread(closure, name) : new Thread(closure);
+        if (daemon) thread.setDaemon(true);
+        thread.start();
+        return thread;
+    }
+
+    /**
+     * Get the last hidden matcher that the system used to do a match.
+     *
+     * @param self placeholder variable used by Groovy categories; ignored for default static methods
+     * @return the last regex matcher
+     * @since 1.0
+     */
+    public static Matcher getLastMatcher(Matcher self) {
+        return RegexSupport.getLastMatcher();
+    }
+
+    /**
+     * This method is used by both sleep() methods to implement sleeping
+     * for the given time even if interrupted
+     *
+     * @param millis  the number of milliseconds to sleep
+     * @param closure optional closure called when interrupted
+     *                as long as the closure returns false the sleep continues
+     */
+    private static void sleepImpl(long millis, Closure closure) {
+        long start = System.currentTimeMillis();
+        long rest = millis;
+        long current;
+        while (rest > 0) {
+            try {
+                Thread.sleep(rest);
+                rest = 0;
+            } catch (InterruptedException e) {
+                if (closure != null) {
+                    if (DefaultTypeTransformation.castToBoolean(closure.call(e))) {
+                        return;
+                    }
+                }
+                current = System.currentTimeMillis(); // compensate for closure's time
+                rest = millis + start - current;
+            }
+        }
+    }
+
+    /**
+     * Sleep for so many milliseconds, even if interrupted.
+     *
+     * @param self         placeholder variable used by Groovy categories; ignored for default static methods
+     * @param milliseconds the number of milliseconds to sleep
+     * @since 1.0
+     */
+    public static void sleep(Object self, long milliseconds) {
+        sleepImpl(milliseconds, null);
+    }
+
+    /**
+     * Sleep for so many milliseconds, using a given closure for interrupt processing.
+     *
+     * @param self         placeholder variable used by Groovy categories; ignored for default static methods
+     * @param milliseconds the number of milliseconds to sleep
+     * @param onInterrupt  interrupt handler, InterruptedException is passed to the Closure
+     *                     as long as it returns false, the sleep continues
+     * @since 1.0
+     */
+    public static void sleep(Object self, long milliseconds, Closure onInterrupt) {
+        sleepImpl(milliseconds, onInterrupt);
+    }
+
+    /**
+     * Parse a String into a Date instance using the given pattern.
+     * This convenience method acts as a wrapper for {@link java.text.SimpleDateFormat}.
+     * <p>
+     * Note that a new SimpleDateFormat instance is created for every
+     * invocation of this method (for thread safety).
+     *
+     * @param self   placeholder variable used by Groovy categories; ignored for default static methods
+     * @param format pattern used to parse the input string.
+     * @param input  String to be parsed to create the date instance
+     * @return a new Date instance representing the parsed input string
+     * @throws ParseException if there is a parse error
+     * @see java.text.SimpleDateFormat#parse(java.lang.String)
+     * @since 1.5.7
+     */
+    public static Date parse(Date self, String format, String input) throws ParseException {
+        return new SimpleDateFormat(format).parse(input);
+    }
+
+    /**
+     * Parse a String into a Date instance using the given pattern and TimeZone.
+     * This convenience method acts as a wrapper for {@link java.text.SimpleDateFormat}.
+     * <p>
+     * Note that a new SimpleDateFormat instance is created for every
+     * invocation of this method (for thread safety).
+     *
+     * @param self   placeholder variable used by Groovy categories; ignored for default static methods
+     * @param format pattern used to parse the input string.
+     * @param input  String to be parsed to create the date instance
+     * @param zone   TimeZone to use when parsing
+     * @return a new Date instance representing the parsed input string
+     * @throws ParseException if there is a parse error
+     * @see java.text.SimpleDateFormat#parse(java.lang.String)
+     * @since 2.4.1
+     */
+    public static Date parse(Date self, String format, String input, TimeZone zone) throws ParseException {
+        SimpleDateFormat sdf = new SimpleDateFormat(format);
+        sdf.setTimeZone(zone);
+        return sdf.parse(input);
+    }
+
+    /**
+     * Parse a String matching the pattern EEE MMM dd HH:mm:ss zzz yyyy
+     * containing US-locale-constants only (e.g. Sat for Saturdays).
+     * Such a string is generated by the toString method of {@link java.util.Date}
+     * <p>
+     * Note that a new SimpleDateFormat instance is created for every
+     * invocation of this method (for thread safety).
+     *
+     * @param self          placeholder variable used by Groovy categories; ignored for default static methods
+     * @param dateToString  String to be parsed to create the date instance. Must match the pattern EEE MMM dd HH:mm:ss zzz yyyy with US-locale symbols
+     * @return a new Date instance representing the parsed input string
+     * @throws ParseException if there is a parse error
+     */
+    public static Date parseToStringDate(Date self, String dateToString) throws ParseException {
+        return new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy", Locale.US).parse(dateToString);
+    }
+
+    /**
+     * Works exactly like ResourceBundle.getBundle(String).  This is needed
+     * because the java method depends on a particular stack configuration that
+     * is not guaranteed in Groovy when calling the Java method.
+     *
+     * @param self       placeholder variable used by Groovy categories; ignored for default static methods
+     * @param bundleName the name of the bundle.
+     * @return the resource bundle
+     * @see java.util.ResourceBundle#getBundle(java.lang.String)
+     * @since 1.6.0
+     */
+    public static ResourceBundle getBundle(ResourceBundle self, String bundleName) {
+        return getBundle(self, bundleName, Locale.getDefault());
+    }
+
+    /**
+     * Works exactly like ResourceBundle.getBundle(String, Locale).  This is needed
+     * because the java method depends on a particular stack configuration that
+     * is not guaranteed in Groovy when calling the Java method.
+     *
+     * @param self       placeholder variable used by Groovy categories; ignored for default static methods
+     * @param bundleName the name of the bundle.
+     * @param locale     the specific locale
+     * @return the resource bundle
+     * @see java.util.ResourceBundle#getBundle(java.lang.String, java.util.Locale)
+     * @since 1.6.0
+     */
+    public static ResourceBundle getBundle(ResourceBundle self, String bundleName, Locale locale) {
+        Class c = ReflectionUtils.getCallingClass();
+        ClassLoader targetCL = c != null ? c.getClassLoader() : null;
+        if (targetCL == null) targetCL = ClassLoader.getSystemClassLoader();
+        return ResourceBundle.getBundle(bundleName, locale, targetCL);
+    }
+
+    public static File createTempDir(File self) throws IOException {
+        return createTempDir(self, "groovy-generated-", "-tmpdir");
+    }
+
+    public static File createTempDir(File self, final String prefix, final String suffix) throws IOException {
+        final int MAXTRIES = 3;
+        int accessDeniedCounter = 0;
+        File tempFile=null;
+        for (int i=0; i<MAXTRIES; i++) {
+            try {
+                tempFile = File.createTempFile(prefix, suffix);
+                tempFile.delete();
+                tempFile.mkdirs();
+                break;
+            } catch (IOException ioe) {
+                if (ioe.getMessage().startsWith("Access is denied")) {
+                    accessDeniedCounter++;
+                    try { Thread.sleep(100); } catch (InterruptedException e) {}
+                }
+                if (i==MAXTRIES-1) {
+                    if (accessDeniedCounter==MAXTRIES) {
+                        String msg =
+                                "Access is denied.\nWe tried " +
+                                        + accessDeniedCounter+
+                                        " times to create a temporary directory"+
+                                        " and failed each time. If you are on Windows"+
+                                        " you are possibly victim to"+
+                                        " http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6325169. "+
+                                        " this is no bug in Groovy.";
+                        throw new IOException(msg);
+                    } else {
+                        throw ioe;
+                    }
+                }
+                continue;
+            }
+        }
+        return tempFile;
+    }
+
+  /**
+   * Get the current time in seconds
+   *
+   * @param self   placeholder variable used by Groovy categories; ignored for default static methods
+   * @return  the difference, measured in seconds, between
+   *          the current time and midnight, January 1, 1970 UTC.
+   * @see     System#currentTimeMillis()
+   */
+  public static long currentTimeSeconds(System self){
+    return System.currentTimeMillis() / 1000;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/b25d0e55/src/main/java/org/codehaus/groovy/runtime/DefaultMethodKey.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/runtime/DefaultMethodKey.java b/src/main/java/org/codehaus/groovy/runtime/DefaultMethodKey.java
new file mode 100644
index 0000000..96612ff
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/runtime/DefaultMethodKey.java
@@ -0,0 +1,44 @@
+/*
+ *  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 org.codehaus.groovy.runtime;
+
+/**
+ * A default implementation of MethodKey
+ *
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ */
+public class DefaultMethodKey extends MethodKey{
+
+    private final Class[] parameterTypes;
+
+    public DefaultMethodKey(Class sender, String name, Class[] parameterTypes, boolean isCallToSuper) {
+        super(sender, name,isCallToSuper);
+        this.parameterTypes = parameterTypes;
+    }
+
+    public int getParameterCount() {
+        return parameterTypes.length;
+    }
+
+    public Class getParameterType(int index) {
+        Class c = parameterTypes[index];
+        if (c==null) return Object.class;
+        return c;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/groovy/blob/b25d0e55/src/main/java/org/codehaus/groovy/runtime/EncodingGroovyMethods.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/runtime/EncodingGroovyMethods.java b/src/main/java/org/codehaus/groovy/runtime/EncodingGroovyMethods.java
new file mode 100644
index 0000000..62b6eeb
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/runtime/EncodingGroovyMethods.java
@@ -0,0 +1,367 @@
+/*
+ *  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 org.codehaus.groovy.runtime;
+
+import groovy.lang.StringWriterIOException;
+import groovy.lang.Writable;
+import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.io.UnsupportedEncodingException;
+import java.io.Writer;
+
+import static org.codehaus.groovy.runtime.EncodingGroovyMethodsSupport.TRANSLATE_TABLE;
+import static org.codehaus.groovy.runtime.EncodingGroovyMethodsSupport.TRANSLATE_TABLE_URLSAFE;
+
+/**
+ * This class defines all the encoding/decoding groovy methods which enhance
+ * the normal JDK classes when inside the Groovy environment.
+ * Static methods are used with the first parameter the destination class.
+ */
+public class EncodingGroovyMethods {
+
+    private static final char[] T_TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".toCharArray();
+
+    private static final char[] T_TABLE_URLSAFE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_=".toCharArray();
+
+    private static final String CHUNK_SEPARATOR = "\r\n";
+
+    /**
+     * Produce a Writable object which writes the Base64 encoding of the byte array.
+     * Calling toString() on the result returns the encoding as a String. For more
+     * information on Base64 encoding and chunking see <code>RFC 4648</code>.
+     *
+     * @param data Byte array to be encoded
+     * @param chunked whether or not the Base64 encoded data should be MIME chunked
+     * @return object which will write the Base64 encoding of the byte array
+     * @since 1.5.1
+     */
+    public static Writable encodeBase64(Byte[] data, final boolean chunked) {
+        return encodeBase64(DefaultTypeTransformation.convertToByteArray(data), chunked);
+    }
+
+    /**
+     * Produce a Writable object which writes the Base64 encoding of the byte array.
+     * Calling toString() on the result returns the encoding as a String. For more
+     * information on Base64 encoding and chunking see <code>RFC 4648</code>.
+     *
+     * @param data Byte array to be encoded
+     * @return object which will write the Base64 encoding of the byte array
+     * @since 1.0
+     */
+    public static Writable encodeBase64(Byte[] data) {
+        return encodeBase64(DefaultTypeTransformation.convertToByteArray(data), false);
+    }
+
+    /**
+     * Produce a Writable object which writes the Base64 encoding of the byte array.
+     * Calling toString() on the result returns the encoding as a String. For more
+     * information on Base64 encoding and chunking see <code>RFC 4648</code>.
+     *
+     * @param data byte array to be encoded
+     * @param chunked whether or not the Base64 encoded data should be MIME chunked
+     * @return object which will write the Base64 encoding of the byte array
+     * @since 1.5.7
+     */
+    public static Writable encodeBase64(final byte[] data, final boolean chunked) {
+        return encodeBase64(data, chunked, false, true);
+    }
+
+    private static Writable encodeBase64(final byte[] data, final boolean chunked, final boolean urlSafe, final boolean pad) {
+        return new Writable() {
+            public Writer writeTo(final Writer writer) throws IOException {
+                int charCount = 0;
+                final int dLimit = (data.length / 3) * 3;
+                final char[] table = urlSafe ? T_TABLE_URLSAFE : T_TABLE;
+                for (int dIndex = 0; dIndex != dLimit; dIndex += 3) {
+                    int d = ((data[dIndex] & 0XFF) << 16) | ((data[dIndex + 1] & 0XFF) << 8) | (data[dIndex + 2] & 0XFF);
+
+                    writer.write(table[d >> 18]);
+                    writer.write(table[(d >> 12) & 0X3F]);
+                    writer.write(table[(d >> 6) & 0X3F]);
+                    writer.write(table[d & 0X3F]);
+
+                    if (chunked && ++charCount == 19) {
+                        writer.write(CHUNK_SEPARATOR);
+                        charCount = 0;
+                    }
+                }
+
+                if (dLimit != data.length) {
+                    int d = (data[dLimit] & 0XFF) << 16;
+
+                    if (dLimit + 1 != data.length) {
+                        d |= (data[dLimit + 1] & 0XFF) << 8;
+                    }
+
+                    writer.write(table[d >> 18]);
+                    writer.write(table[(d >> 12) & 0X3F]);
+                    if (pad) {
+                        writer.write((dLimit + 1 < data.length) ? table[(d >> 6) & 0X3F] : '=');
+                        writer.write('=');
+                    } else {
+                        if (dLimit + 1 < data.length) {
+                            writer.write(table[(d >> 6) & 0X3F]);
+                        }
+                    }
+                    if (chunked && charCount != 0) {
+                        writer.write(CHUNK_SEPARATOR);
+                    }
+                }
+
+                return writer;
+            }
+
+            public String toString() {
+                StringWriter buffer = new StringWriter();
+
+                try {
+                    writeTo(buffer);
+                } catch (IOException e) {
+                    throw new StringWriterIOException(e);
+                }
+
+                return buffer.toString();
+            }
+        };
+    }
+
+    /**
+     * Produce a Writable object which writes the Base64 encoding of the byte array.
+     * Calling toString() on the result returns the encoding as a String. For more
+     * information on Base64 encoding and chunking see <code>RFC 4648</code>.
+     *
+     * @param data byte array to be encoded
+     * @return object which will write the Base64 encoding of the byte array
+     * @since 1.0
+     */
+    public static Writable encodeBase64(final byte[] data) {
+        return encodeBase64(data, false);
+    }
+
+    /**
+     * Produce a Writable object which writes the Base64 URL and Filename Safe encoding of the byte array.
+     * Calling toString() on the result returns the encoding as a String. For more
+     * information on Base64 URL and Filename Safe encoding see <code>RFC 4648 - Section 5
+     * Base 64 Encoding with URL and Filename Safe Alphabet</code>.
+     * <p>
+     * The method omits padding and is equivalent to calling
+     * {@link org.codehaus.groovy.runtime.EncodingGroovyMethods#encodeBase64Url(Byte[], boolean)} with a
+     * value of {@code false}.
+     *
+     * @param data Byte array to be encoded
+     * @return object which will write the Base64 URL and Filename Safe encoding of the byte array
+     * @see org.codehaus.groovy.runtime.EncodingGroovyMethods#encodeBase64Url(Byte[], boolean)
+     * @since 2.5.0
+     */
+    public static Writable encodeBase64Url(Byte[] data) {
+        return encodeBase64Url(data, false);
+    }
+
+    /**
+     * Produce a Writable object which writes the Base64 URL and Filename Safe encoding of the byte array.
+     * Calling toString() on the result returns the encoding as a String. For more
+     * information on Base64 URL and Filename Safe encoding see <code>RFC 4648 - Section 5
+     * Base 64 Encoding with URL and Filename Safe Alphabet</code>.
+     *
+     * @param data Byte array to be encoded
+     * @param pad whether or not the encoded data should be padded
+     * @return object which will write the Base64 URL and Filename Safe encoding of the byte array
+     * @since 2.5.0
+     */
+    public static Writable encodeBase64Url(Byte[] data, boolean pad) {
+        return encodeBase64Url(DefaultTypeTransformation.convertToByteArray(data), pad);
+    }
+
+    /**
+     * Produce a Writable object which writes the Base64 URL and Filename Safe encoding of the byte array.
+     * Calling toString() on the result returns the encoding as a String. For more
+     * information on Base64 URL and Filename Safe encoding see <code>RFC 4648 - Section 5
+     * Base 64 Encoding with URL and Filename Safe Alphabet</code>.
+     * <p>
+     * The method omits padding and is equivalent to calling
+     * {@link org.codehaus.groovy.runtime.EncodingGroovyMethods#encodeBase64Url(byte[], boolean)} with a
+     * value of {@code false}.
+     *
+     * @param data Byte array to be encoded
+     * @return object which will write the Base64 URL and Filename Safe encoding of the byte array
+     * @see org.codehaus.groovy.runtime.EncodingGroovyMethods#encodeBase64Url(byte[], boolean)
+     * @since 2.5.0
+     */
+    public static Writable encodeBase64Url(final byte[] data) {
+        return encodeBase64Url(data, false);
+    }
+
+    /**
+     * Produce a Writable object which writes the Base64 URL and Filename Safe encoding of the byte array.
+     * Calling toString() on the result returns the encoding as a String. For more
+     * information on Base64 URL and Filename Safe encoding see <code>RFC 4648 - Section 5
+     * Base 64 Encoding with URL and Filename Safe Alphabet</code>.
+     *
+     * @param data Byte array to be encoded
+     * @param pad whether or not the encoded data should be padded
+     * @return object which will write the Base64 URL and Filename Safe encoding of the byte array
+     * @since 2.5.0
+     */
+    public static Writable encodeBase64Url(final byte[] data, final boolean pad) {
+        return encodeBase64(data, false, true, pad);
+    }
+
+    /**
+     * Decode the String from Base64 into a byte array.
+     *
+     * @param value the string to be decoded
+     * @return the decoded bytes as an array
+     * @since 1.0
+     */
+    public static byte[] decodeBase64(String value) {
+        return decodeBase64(value, false);
+    }
+
+    /**
+     * Decodes a Base64 URL and Filename Safe encoded String into a byte array.
+     *
+     * @param value the string to be decoded
+     * @return the decoded bytes as an array
+     * @since 2.5.0
+     */
+    public static byte[] decodeBase64Url(String value) {
+        return decodeBase64(value, true);
+    }
+
+    private static byte[] decodeBase64(String value, boolean urlSafe) {
+        int byteShift = 4;
+        int tmp = 0;
+        boolean done = false;
+        final StringBuilder buffer = new StringBuilder();
+        final byte[] table = urlSafe ? TRANSLATE_TABLE_URLSAFE : TRANSLATE_TABLE;
+        for (int i = 0; i != value.length(); i++) {
+            final char c = value.charAt(i);
+            final int sixBit = (c < 123) ? table[c] : 66;
+
+            if (sixBit < 64) {
+                if (done)
+                    throw new RuntimeException("= character not at end of base64 value"); // TODO: change this exception type
+
+                tmp = (tmp << 6) | sixBit;
+
+                if (byteShift-- != 4) {
+                    buffer.append((char) ((tmp >> (byteShift * 2)) & 0XFF));
+                }
+
+            } else if (sixBit == 64) {
+
+                byteShift--;
+                done = true;
+
+            } else if (sixBit == 66) {
+                // RFC 2045 says that I'm allowed to take the presence of
+                // these characters as evidence of data corruption
+                // So I will
+                throw new RuntimeException("bad character in base64 value"); // TODO: change this exception type
+            }
+
+            if (byteShift == 0) byteShift = 4;
+        }
+
+        try {
+            return buffer.toString().getBytes("ISO-8859-1");
+        } catch (UnsupportedEncodingException e) {
+            throw new RuntimeException("Base 64 decode produced byte values > 255"); // TODO: change this exception type
+        }
+    }
+
+    /**
+     * Produces a Writable that writes the hex encoding of the Byte[]. Calling
+     * toString() on this Writable returns the hex encoding as a String. The hex
+     * encoding includes two characters for each byte and all letters are lower case.
+     *
+     * @param data byte array to be encoded
+     * @return object which will write the hex encoding of the byte array
+     * @see Integer#toHexString(int)
+     */
+    public static Writable encodeHex(final Byte[] data) {
+        return encodeHex(DefaultTypeTransformation.convertToByteArray(data));
+    }
+
+    /**
+     * Produces a Writable that writes the hex encoding of the byte[]. Calling
+     * toString() on this Writable returns the hex encoding as a String. The hex
+     * encoding includes two characters for each byte and all letters are lower case.
+     *
+     * @param data byte array to be encoded
+     * @return object which will write the hex encoding of the byte array
+     * @see Integer#toHexString(int)
+     */
+    public static Writable encodeHex(final byte[] data) {
+        return new Writable() {
+            public Writer writeTo(Writer out) throws IOException {
+                for (int i = 0; i < data.length; i++) {
+                    // convert byte into unsigned hex string
+                    String hexString = Integer.toHexString(data[i] & 0xFF);
+
+                    // add leading zero if the length of the string is one
+                    if (hexString.length() < 2) {
+                        out.write("0");
+                    }
+
+                    // write hex string to writer
+                    out.write(hexString);
+                }
+                return out;
+            }
+
+            public String toString() {
+                StringWriter buffer = new StringWriter();
+
+                try {
+                    writeTo(buffer);
+                } catch (IOException e) {
+                    throw new StringWriterIOException(e);
+                }
+
+                return buffer.toString();
+            }
+        };
+    }
+
+    /**
+     * Decodes a hex string to a byte array. The hex string can contain either upper
+     * case or lower case letters.
+     *
+     * @param value string to be decoded
+     * @return decoded byte array
+     * @throws NumberFormatException If the string contains an odd number of characters
+     *                               or if the characters are not valid hexadecimal values.
+     */
+    public static byte[] decodeHex(final String value) {
+        // if string length is odd then throw exception
+        if (value.length() % 2 != 0) {
+            throw new NumberFormatException("odd number of characters in hex string");
+        }
+
+        byte[] bytes = new byte[value.length() / 2];
+        for (int i = 0; i < value.length(); i += 2) {
+            bytes[i / 2] = (byte) Integer.parseInt(value.substring(i, i + 2), 16);
+        }
+
+        return bytes;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/groovy/blob/b25d0e55/src/main/java/org/codehaus/groovy/runtime/EncodingGroovyMethodsSupport.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/runtime/EncodingGroovyMethodsSupport.java b/src/main/java/org/codehaus/groovy/runtime/EncodingGroovyMethodsSupport.java
new file mode 100644
index 0000000..24929a8
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/runtime/EncodingGroovyMethodsSupport.java
@@ -0,0 +1,90 @@
+/*
+ *  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 org.codehaus.groovy.runtime;
+
+/**
+ * Keep this constant in a separate file as it is troublesome for Antlr to parse for doc purposes.
+ */
+public class EncodingGroovyMethodsSupport {
+    static final byte[] TRANSLATE_TABLE = (
+            "\u0042\u0042\u0042\u0042\u0042\u0042\u0042\u0042"
+                    //           \t    \n                \r
+                    + "\u0042\u0041\u0041\u0042\u0042\u0041\u0042\u0042"
+                    //
+                    + "\u0042\u0042\u0042\u0042\u0042\u0042\u0042\u0042"
+                    //
+                    + "\u0042\u0042\u0042\u0042\u0042\u0042\u0042\u0042"
+                    //     sp     !     "     #     $     %     &     '
+                    + "\u0041\u0042\u0042\u0042\u0042\u0042\u0042\u0042"
+                    //      (     )     *     +     ,     -     .     /
+                    + "\u0042\u0042\u0042\u003E\u0042\u0042\u0042\u003F"
+                    //      0     1     2     3     4     5     6     7
+                    + "\u0034\u0035\u0036\u0037\u0038\u0039\u003A\u003B"
+                    //      8     9     :     ;     <     =     >     ?
+                    + "\u003C\u003D\u0042\u0042\u0042\u0040\u0042\u0042"
+                    //      @     A     B     C     D     E     F     G
+                    + "\u0042\u0000\u0001\u0002\u0003\u0004\u0005\u0006"
+                    //      H     I J K     L     M N     O
+                    + "\u0007\u0008\t\n\u000B\u000C\r\u000E"
+                    //      P     Q     R     S     T     U     V     W
+                    + "\u000F\u0010\u0011\u0012\u0013\u0014\u0015\u0016"
+                    //      X     Y     Z     [     \     ]     ^     _
+                    + "\u0017\u0018\u0019\u0042\u0042\u0042\u0042\u0042"
+                    //      '     a     b     c     d     e     f     g
+                    + "\u0042\u001A\u001B\u001C\u001D\u001E\u001F\u0020"
+                    //      h i     j     k     l     m     n     o
+                    + "\u0021\"\u0023\u0024\u0025\u0026\u0027\u0028"
+                    //      p     q     r     s     t     u     v     w
+                    + "\u0029\u002A\u002B\u002C\u002D\u002E\u002F\u0030"
+                    //      x     y     z
+                    + "\u0031\u0032\u0033").getBytes();
+
+    static final byte[] TRANSLATE_TABLE_URLSAFE = (
+            "\u0042\u0042\u0042\u0042\u0042\u0042\u0042\u0042"
+                    //           \t    \n                \r
+                    + "\u0042\u0041\u0041\u0042\u0042\u0041\u0042\u0042"
+                    //
+                    + "\u0042\u0042\u0042\u0042\u0042\u0042\u0042\u0042"
+                    //
+                    + "\u0042\u0042\u0042\u0042\u0042\u0042\u0042\u0042"
+                    //     sp     !     "     #     $     %     &     '
+                    + "\u0041\u0042\u0042\u0042\u0042\u0042\u0042\u0042"
+                    //      (     )     *     +     ,     -     .     /
+                    + "\u0042\u0042\u0042\u0042\u0042\u003E\u0042\u0042"
+                    //      0     1     2     3     4     5     6     7
+                    + "\u0034\u0035\u0036\u0037\u0038\u0039\u003A\u003B"
+                    //      8     9     :     ;     <     =     >     ?
+                    + "\u003C\u003D\u0042\u0042\u0042\u0040\u0042\u0042"
+                    //      @     A     B     C     D     E     F     G
+                    + "\u0042\u0000\u0001\u0002\u0003\u0004\u0005\u0006"
+                    //      H     I J K     L     M N     O
+                    + "\u0007\u0008\t\n\u000B\u000C\r\u000E"
+                    //      P     Q     R     S     T     U     V     W
+                    + "\u000F\u0010\u0011\u0012\u0013\u0014\u0015\u0016"
+                    //      X     Y     Z     [     \     ]     ^     _
+                    + "\u0017\u0018\u0019\u0042\u0042\u0042\u0042\u003F"
+                    //      '     a     b     c     d     e     f     g
+                    + "\u0042\u001A\u001B\u001C\u001D\u001E\u001F\u0020"
+                    //      h i     j     k     l     m     n     o
+                    + "\u0021\"\u0023\u0024\u0025\u0026\u0027\u0028"
+                    //      p     q     r     s     t     u     v     w
+                    + "\u0029\u002A\u002B\u002C\u002D\u002E\u002F\u0030"
+                    //      x     y     z
+                    + "\u0031\u0032\u0033").getBytes();
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/b25d0e55/src/main/java/org/codehaus/groovy/runtime/FlushingStreamWriter.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/runtime/FlushingStreamWriter.java b/src/main/java/org/codehaus/groovy/runtime/FlushingStreamWriter.java
new file mode 100644
index 0000000..6fb77b7
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/runtime/FlushingStreamWriter.java
@@ -0,0 +1,50 @@
+/*
+ *  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 org.codehaus.groovy.runtime;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+
+/**
+ * Stream writer which flushes after each write operation.
+ *
+ * @author Guillaume Laforge
+ */
+public class FlushingStreamWriter extends OutputStreamWriter {
+
+    public FlushingStreamWriter(OutputStream out) {
+        super(out);
+    }
+
+    public void write(char[] cbuf, int off, int len) throws IOException {
+        super.write(cbuf, off, len);
+        flush();
+    }
+
+    public void write(int c) throws IOException {
+        super.write(c);
+        flush();
+    }
+
+    public void write(String str, int off, int len) throws IOException {
+        super.write(str, off, len);
+        flush();
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/b25d0e55/src/main/java/org/codehaus/groovy/runtime/GStringImpl.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/runtime/GStringImpl.java b/src/main/java/org/codehaus/groovy/runtime/GStringImpl.java
new file mode 100644
index 0000000..d4cd857
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/runtime/GStringImpl.java
@@ -0,0 +1,64 @@
+/*
+ * 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 org.codehaus.groovy.runtime;
+
+import groovy.lang.GString;
+
+/**
+ * Default implementation of a GString used by the compiler. A GString
+ * consist of a list of values and strings which can be combined to
+ * create a new String.
+ *
+ * @author Jochen Theodorou
+ * @see groovy.lang.GString
+ */
+public class GStringImpl extends GString {
+    private final String[] strings;
+
+    /**
+     * Create a new GString with values and strings.
+     * <p>
+     * Each value is prefixed by a string, after the last value
+     * an additional String might be used. This means
+     * <code>strings.length == values.length  ||  strings.length == values.length + 1</code>.
+     * <p>
+     * <b>NOTE:</b> The lengths are <b>not</b> checked. Using different lengths might result
+     * in unpredictable behaviour.
+     *
+     * @param values  the value parts
+     * @param strings the string parts
+     */
+    public GStringImpl(Object[] values, String[] strings) {
+        super(values);
+        this.strings = strings;
+    }
+
+    /**
+     * Get the strings of this GString.
+     * <p>
+     * This methods returns the same array as used in the constructor. Changing
+     * the values will result in changes of the GString. It is not recommended
+     * to do so.
+     */
+    public String[] getStrings() {
+        return strings;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/b25d0e55/src/main/java/org/codehaus/groovy/runtime/GeneratedClosure.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/runtime/GeneratedClosure.java b/src/main/java/org/codehaus/groovy/runtime/GeneratedClosure.java
new file mode 100644
index 0000000..50da843
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/runtime/GeneratedClosure.java
@@ -0,0 +1,29 @@
+/*
+ *  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 org.codehaus.groovy.runtime;
+
+/**
+ * Marker interface to identify closures generated by the groovy compiler.
+ * For internal use only!
+ * 
+ * @author Jochen Theodorou
+ * @since 1.5
+ * @see org.codehaus.groovy.runtime.metaclass.ClosureMetaClass
+ */
+public interface GeneratedClosure {}

http://git-wip-us.apache.org/repos/asf/groovy/blob/b25d0e55/src/main/java/org/codehaus/groovy/runtime/GroovyCategorySupport.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/runtime/GroovyCategorySupport.java b/src/main/java/org/codehaus/groovy/runtime/GroovyCategorySupport.java
new file mode 100644
index 0000000..19f53d2
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/runtime/GroovyCategorySupport.java
@@ -0,0 +1,365 @@
+/*
+ *  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 org.codehaus.groovy.runtime;
+
+import groovy.lang.Closure;
+import org.codehaus.groovy.reflection.CachedClass;
+import org.codehaus.groovy.reflection.CachedMethod;
+import org.codehaus.groovy.reflection.ReflectionCache;
+import org.codehaus.groovy.runtime.metaclass.DefaultMetaClassInfo;
+import org.codehaus.groovy.runtime.metaclass.NewInstanceMetaMethod;
+import org.codehaus.groovy.vmplugin.VMPluginFactory;
+
+import java.lang.ref.SoftReference;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * @author sam
+ * @author Paul King
+ * @author Alex Tkachman
+ */
+public class GroovyCategorySupport {
+
+    private static int categoriesInUse = 0;
+
+    public static class CategoryMethodList extends ArrayList<CategoryMethod> {
+        public final int level;
+        final CategoryMethodList previous;
+        final AtomicInteger usage;
+
+        public CategoryMethodList(String name, int level, CategoryMethodList previous) {
+            this.level = level;
+            this.previous = previous;
+            if (previous != null) {
+                addAll(previous);
+                usage = previous.usage;
+            }
+            else {
+                usage = getCategoryNameUsage (name);
+            }
+        }
+
+        public boolean add(CategoryMethod o) {
+            usage.incrementAndGet();
+            return super.add(o);
+        }
+    }
+
+    public static class ThreadCategoryInfo extends HashMap<String, CategoryMethodList>{
+
+        private static final Object LOCK = new Object();
+
+        int level;
+
+        private Map<String, String> propertyGetterMap;
+        private Map<String, String> propertySetterMap;
+
+        private void newScope () {
+            synchronized (LOCK) {
+                categoriesInUse++;
+                DefaultMetaClassInfo.setCategoryUsed(true);
+            }
+            VMPluginFactory.getPlugin().invalidateCallSites();
+            level++;
+        }
+
+        private void endScope () {
+            for (Iterator<Map.Entry<String, CategoryMethodList>> it = entrySet().iterator(); it.hasNext(); ) {
+                final Map.Entry<String, CategoryMethodList> e = it.next();
+                final CategoryMethodList list = e.getValue();
+                if (list.level == level) {
+                    final CategoryMethodList prev = list.previous;
+                    if (prev == null) {
+                      it.remove();
+                      list.usage.addAndGet(-list.size());
+                    }
+                    else {
+                      e.setValue(prev);
+                      list.usage.addAndGet(prev.size()-list.size());
+                    }
+                }
+            }
+            level--;
+            VMPluginFactory.getPlugin().invalidateCallSites();
+            synchronized (LOCK) {
+                if (--categoriesInUse == 0) {
+                    DefaultMetaClassInfo.setCategoryUsed(false);
+                }
+            }
+            if (level == 0) {
+                THREAD_INFO.remove();
+            }
+        }
+
+        private <T> T use(Class categoryClass, Closure<T> closure) {
+            newScope();
+            try {
+                use(categoryClass);
+                return closure.call();
+            } finally {
+                endScope();
+            }
+        }
+
+        public <T> T use(List<Class> categoryClasses, Closure<T> closure) {
+            newScope();
+            try {
+                for (Class categoryClass : categoryClasses) {
+                    use(categoryClass);
+                }
+                return closure.call();
+            } finally {
+                endScope();
+            }
+        }
+
+        private void applyUse(CachedClass cachedClass) {
+            CachedMethod[] methods = cachedClass.getMethods();
+            for (CachedMethod cachedMethod : methods) {
+                if (cachedMethod.isStatic() && cachedMethod.isPublic()) {
+                    CachedClass[] paramTypes = cachedMethod.getParameterTypes();
+                    if (paramTypes.length > 0) {
+                        CachedClass metaClass = paramTypes[0];
+                        CategoryMethod mmethod = new CategoryMethod(cachedMethod, metaClass.getTheClass());
+                        final String name = cachedMethod.getName();
+                        CategoryMethodList list = get(name);
+                        if (list == null || list.level != level) {
+                            list = new CategoryMethodList(name, level, list);
+                            put(name, list);
+                        }
+                        list.add(mmethod);
+                        Collections.sort(list);
+                        cachePropertyAccessor(mmethod);
+                    }
+                }
+            }
+        }
+
+        private void cachePropertyAccessor(CategoryMethod method) {
+             String name = method.getName();
+             int parameterLength = method.getParameterTypes().length;
+
+             if (name.startsWith("get") && name.length() > 3 && parameterLength == 0) {
+                 propertyGetterMap = putPropertyAccessor(3, name, propertyGetterMap);
+             }
+             else if (name.startsWith("set") && name.length() > 3 && parameterLength == 1) {
+                 propertySetterMap = putPropertyAccessor(3, name, propertySetterMap);
+             }
+        }
+
+        // Precondition: accessorName.length() > prefixLength
+        private Map<String, String> putPropertyAccessor(int prefixLength, String accessorName, Map<String, String> map) {
+            if (map == null) {
+              map = new HashMap<String, String>();
+            }
+            String property = accessorName.substring(prefixLength, prefixLength+1).toLowerCase() + accessorName.substring(prefixLength+1);
+            map.put(property, accessorName);
+            return map;
+        }
+
+        private void use(Class categoryClass) {
+            CachedClass cachedClass = ReflectionCache.getCachedClass(categoryClass);
+            LinkedList<CachedClass> classStack = new LinkedList<CachedClass>();
+            for (CachedClass superClass = cachedClass; superClass.getTheClass()!=Object.class; superClass = superClass.getCachedSuperClass()) {
+                classStack.add(superClass);
+            }
+
+            while (!classStack.isEmpty()) {
+                CachedClass klazz = classStack.removeLast();
+                applyUse(klazz);
+            }
+        }
+
+        public CategoryMethodList getCategoryMethods(String name) {
+            return level == 0 ? null : get(name);
+        }
+
+
+        String getPropertyCategoryGetterName(String propertyName){
+            return propertyGetterMap != null ? propertyGetterMap.get(propertyName) : null;
+        }
+
+        String getPropertyCategorySetterName(String propertyName){
+            return propertySetterMap != null ? propertySetterMap.get(propertyName) : null;
+        }
+    }
+
+    private static final MyThreadLocal THREAD_INFO = new MyThreadLocal();
+
+    public static class CategoryMethod extends NewInstanceMetaMethod implements Comparable {
+        private final Class metaClass;
+
+        public CategoryMethod(CachedMethod metaMethod, Class metaClass) {
+            super(metaMethod);
+            this.metaClass = metaClass;
+        }
+
+        public boolean isCacheable() { return false; }
+
+        /**
+         * Sort by most specific to least specific.
+         *
+         * @param o the object to compare against
+         */
+        public int compareTo(Object o) {
+            CategoryMethod thatMethod = (CategoryMethod) o;
+            Class thisClass = metaClass;
+            Class thatClass = thatMethod.metaClass;
+            if (thisClass == thatClass) return 0;
+            if (isChildOfParent(thisClass, thatClass)) return -1;
+            if (isChildOfParent(thatClass, thisClass)) return 1;
+            return 0;
+        }
+
+        private boolean isChildOfParent(Class candidateChild, Class candidateParent) {
+            Class loop = candidateChild;
+            while(loop != null && loop != Object.class) {
+                loop = loop.getSuperclass();
+                if (loop == candidateParent) {
+                    return true;
+                }
+            }
+            return false;
+        }
+    }
+
+    public static AtomicInteger getCategoryNameUsage (String name) {
+        return THREAD_INFO.getUsage (name);
+    }
+
+    /**
+     * Create a scope based on given categoryClass and invoke closure within that scope.
+     *
+     * @param categoryClass the class containing category methods
+     * @param closure the closure during which to make the category class methods available
+     * @return the value returned from the closure
+     */
+    public static <T> T use(Class categoryClass, Closure<T> closure) {
+        return THREAD_INFO.getInfo().use(categoryClass, closure);
+    }
+
+    /**
+     * Create a scope based on given categoryClasses and invoke closure within that scope.
+     *
+     * @param categoryClasses the list of classes containing category methods
+     * @param closure the closure during which to make the category class methods available
+     * @return the value returned from the closure
+     */
+    public static <T> T use(List<Class> categoryClasses, Closure<T> closure) {
+        return THREAD_INFO.getInfo().use(categoryClasses, closure);
+    }
+
+    public static boolean hasCategoryInCurrentThread() {
+        /*
+         * Synchronization is avoided here for performance reasons since
+         * this method is called frequently from callsite locations. For
+         * a typical case when no Categories are in use the initialized
+         * value of 0 will be correctly read. For cases where multiple
+         * Threads are using Categories it is possible that a stale
+         * non-zero value may be read but in that case the ThreadLocal
+         * check will produce the correct result. When the current Thread
+         * is using Categories, it would have incremented the counter
+         * so whatever version of the value it observes here should be
+         * non-zero and good enough for the purposes of this quick exit
+         * check.
+         */
+        if (categoriesInUse == 0) {
+            return false;
+        }
+        ThreadCategoryInfo infoNullable = THREAD_INFO.getInfoNullable();
+        return infoNullable != null && infoNullable.level != 0;
+    }
+
+    /**
+     * @deprecated use {@link #hasCategoryInCurrentThread()}
+     */
+    @Deprecated
+    public static boolean hasCategoryInAnyThread() {
+        synchronized (ThreadCategoryInfo.LOCK) {
+            return categoriesInUse != 0;
+        }
+    }
+
+    /**
+     * This method is used to pull all the new methods out of the local thread context with a particular name.
+     *
+     * @param name the method name of interest
+     * @return the list of methods
+     */
+    public static CategoryMethodList getCategoryMethods(String name) {
+        final ThreadCategoryInfo categoryInfo = THREAD_INFO.getInfoNullable();
+        return categoryInfo == null ? null : categoryInfo.getCategoryMethods(name);
+    }
+
+    public static String getPropertyCategoryGetterName(String propertyName) {
+         final ThreadCategoryInfo categoryInfo = THREAD_INFO.getInfoNullable();
+         return categoryInfo == null ? null : categoryInfo.getPropertyCategoryGetterName(propertyName);
+    }
+
+    public static String getPropertyCategorySetterName(String propertyName) {
+         final ThreadCategoryInfo categoryInfo = THREAD_INFO.getInfoNullable();
+         return categoryInfo == null ? null : categoryInfo.getPropertyCategorySetterName(propertyName);
+   }
+
+    private static class MyThreadLocal extends ThreadLocal<SoftReference> {
+
+        final ConcurrentHashMap<String,AtomicInteger> usage = new ConcurrentHashMap<String,AtomicInteger> ();
+
+        public ThreadCategoryInfo getInfo() {
+            final SoftReference reference = get();
+            ThreadCategoryInfo tcinfo;
+            if (reference != null) {
+                tcinfo = (ThreadCategoryInfo) reference.get();
+                if( tcinfo == null ) {
+                    tcinfo = new ThreadCategoryInfo();
+                    set(new SoftReference(tcinfo));
+                }
+            }
+            else {
+                tcinfo = new ThreadCategoryInfo();
+                set(new SoftReference(tcinfo));
+            }
+            return tcinfo;
+        }
+
+        public ThreadCategoryInfo getInfoNullable() {
+            final SoftReference reference = get();
+            return reference == null ? null : (ThreadCategoryInfo) reference.get();
+        }
+
+        public AtomicInteger getUsage (String name) {
+            AtomicInteger u = usage.get(name);
+            if (u != null) {
+                return u;
+            }
+
+            final AtomicInteger ai = new AtomicInteger();
+            final AtomicInteger prev = usage.putIfAbsent(name, ai);
+            return prev == null ? ai : prev;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/b25d0e55/src/main/java/org/codehaus/groovy/runtime/HandleMetaClass.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/runtime/HandleMetaClass.java b/src/main/java/org/codehaus/groovy/runtime/HandleMetaClass.java
new file mode 100644
index 0000000..a838c28
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/runtime/HandleMetaClass.java
@@ -0,0 +1,122 @@
+/*
+ *  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 org.codehaus.groovy.runtime;
+
+import groovy.lang.DelegatingMetaClass;
+import groovy.lang.ExpandoMetaClass;
+import groovy.lang.GroovyObject;
+import groovy.lang.MetaBeanProperty;
+import groovy.lang.MetaClass;
+import groovy.lang.MetaMethod;
+
+import java.lang.reflect.Method;
+
+public class HandleMetaClass extends DelegatingMetaClass {
+    private Object object;
+    private static final Object NONE = new Object();
+
+    public HandleMetaClass(MetaClass mc) {
+        this(mc, null);
+    }
+
+    public HandleMetaClass(MetaClass mc, Object obj) {
+        super(mc);
+        if (obj != null) {
+            if (InvokerHelper.getMetaClass(obj.getClass()) == mc || !(mc instanceof ExpandoMetaClass))
+              object = obj; // object has default meta class, so we need to replace it on demand
+            else
+              object = NONE; // object already has per instance meta class
+        }
+    }
+
+    public void initialize() {
+        replaceDelegate();
+        delegate.initialize();
+    }
+
+    public GroovyObject replaceDelegate() {
+        if (object == null) {
+            if (!(delegate instanceof ExpandoMetaClass)) {
+              delegate = new ExpandoMetaClass(delegate.getTheClass(), true, true);
+              delegate.initialize();
+            }
+            DefaultGroovyMethods.setMetaClass(delegate.getTheClass(), delegate);
+        }
+        else {
+          if (object != NONE) {
+              final MetaClass metaClass = delegate;
+              delegate = new ExpandoMetaClass(delegate.getTheClass(), false, true);
+              if (metaClass instanceof ExpandoMetaClass) {
+                  ExpandoMetaClass emc = (ExpandoMetaClass) metaClass;
+                  for (MetaMethod method : emc.getExpandoMethods())
+                    ((ExpandoMetaClass)delegate).registerInstanceMethod(method);
+              }
+              delegate.initialize();
+              MetaClassHelper.doSetMetaClass(object, delegate);
+              object = NONE;
+          }
+        }
+        return (GroovyObject)delegate;
+    }
+
+    public Object invokeMethod(String name, Object args) {
+        return replaceDelegate().invokeMethod(name, args);
+    }
+
+    // this method mimics EMC behavior
+    public Object getProperty(String property) {
+        if(ExpandoMetaClass.isValidExpandoProperty(property)) {
+            if(property.equals(ExpandoMetaClass.STATIC_QUALIFIER) ||
+               property.equals(ExpandoMetaClass.CONSTRUCTOR) ||
+               Holder.META_CLASS.hasProperty(this, property) == null) {
+                  return replaceDelegate().getProperty(property);
+            }
+        }
+        return Holder.META_CLASS.getProperty(this, property);
+    }
+
+    public void setProperty(String property, Object newValue) {
+        replaceDelegate().setProperty(property, newValue);
+    }
+
+    public void addNewInstanceMethod(Method method) {
+        throw new UnsupportedOperationException();
+    }
+
+    public void addNewStaticMethod(Method method) {
+        throw new UnsupportedOperationException();
+    }
+
+    public void addMetaMethod(MetaMethod metaMethod) {
+        throw new UnsupportedOperationException();
+    }
+
+    public void addMetaBeanProperty(MetaBeanProperty metaBeanProperty) {
+        throw new UnsupportedOperationException();
+    }
+
+    public boolean equals(Object obj) {
+        return super.equals(obj) || getAdaptee().equals(obj) || (obj instanceof HandleMetaClass && equals(((HandleMetaClass)obj).getAdaptee()));
+    }
+
+    // Lazily initialize the single instance of the HandleMetaClass metaClass
+    private static class Holder {
+        static final MetaClass META_CLASS = InvokerHelper.getMetaClass(HandleMetaClass.class);
+    }
+}