http://git-wip-us.apache.org/repos/asf/groovy/blob/10110145/src/main/groovy/util/GroovyCollections.java ---------------------------------------------------------------------- diff --git a/src/main/groovy/util/GroovyCollections.java b/src/main/groovy/util/GroovyCollections.java deleted file mode 100644 index dff062d..0000000 --- a/src/main/groovy/util/GroovyCollections.java +++ /dev/null @@ -1,293 +0,0 @@ -/* - * 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.util; - -import org.codehaus.groovy.runtime.DefaultGroovyMethods; -import org.codehaus.groovy.runtime.ScriptBytecodeAdapter; -import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -/** - * A Collections utility class - * - * @author Paul King - * @author Jim White - */ -public class GroovyCollections { - /** - * Finds all combinations of items from the given collections. - * - * @param collections the given collections - * @return a List of the combinations found - * @see #combinations(Collection) - */ - public static List combinations(Object[] collections) { - return combinations((Iterable)Arrays.asList(collections)); - } - - /** - * Finds all non-null subsequences of a list. - * E.g. <code>subsequences([1, 2, 3])</code> would be: - * [[1, 2, 3], [1, 3], [2, 3], [1, 2], [1], [2], [3]] - * - * @param items the List of items - * @return the subsequences from items - */ - public static <T> Set<List<T>> subsequences(List<T> items) { - // items.inject([]){ ss, h -> ss.collect { it + [h] } + ss + [[h]] } - Set<List<T>> ans = new HashSet<List<T>>(); - for (T h : items) { - Set<List<T>> next = new HashSet<List<T>>(); - for (List<T> it : ans) { - List<T> sublist = new ArrayList<T>(it); - sublist.add(h); - next.add(sublist); - } - next.addAll(ans); - List<T> hlist = new ArrayList<T>(); - hlist.add(h); - next.add(hlist); - ans = next; - } - return ans; - } - - /** - * @param collections the given collections - * @deprecated use combinations(Iterable) - */ - @Deprecated - public static List combinations(Collection collections) { - return combinations((Iterable)collections); - } - - /** - * Finds all combinations of items from the given Iterable aggregate of collections. - * So, <code>combinations([[true, false], [true, false]])</code> - * is <code>[[true, true], [false, true], [true, false], [false, false]]</code> - * and <code>combinations([['a', 'b'],[1, 2, 3]])</code> - * is <code>[['a', 1], ['b', 1], ['a', 2], ['b', 2], ['a', 3], ['b', 3]]</code>. - * If a non-collection item is given, it is treated as a singleton collection, - * i.e. <code>combinations([[1, 2], 'x'])</code> is <code>[[1, 'x'], [2, 'x']]</code>. - * - * @param collections the Iterable of given collections - * @return a List of the combinations found - * @since 2.2.0 - */ - public static List combinations(Iterable collections) { - List collectedCombos = new ArrayList(); - for (Object collection : collections) { - Iterable items = DefaultTypeTransformation.asCollection(collection); - if (collectedCombos.isEmpty()) { - for (Object item : items) { - List l = new ArrayList(); - l.add(item); - collectedCombos.add(l); - } - } else { - List savedCombos = new ArrayList(collectedCombos); - List newCombos = new ArrayList(); - for (Object value : items) { - for (Object savedCombo : savedCombos) { - List oldList = new ArrayList((List) savedCombo); - oldList.add(value); - newCombos.add(oldList); - } - } - collectedCombos = newCombos; - } - } - return collectedCombos; - } - - public static <T> List<List<T>> inits(Iterable<T> collections) { - List<T> copy = DefaultGroovyMethods.toList(collections); - List<List<T>> result = new ArrayList<List<T>>(); - for (int i = copy.size(); i >= 0; i--) { - List<T> next = copy.subList(0, i); - result.add(next); - } - return result; - } - - public static <T> List<List<T>> tails(Iterable<T> collections) { - List<T> copy = DefaultGroovyMethods.toList(collections); - List<List<T>> result = new ArrayList<List<T>>(); - for (int i = 0; i <= copy.size(); i++) { - List<T> next = copy.subList(i, copy.size()); - result.add(next); - } - return result; - } - - /** - * Transposes an array of lists. - * - * @param lists the given lists - * @return a List of the transposed lists - * @see #transpose(List) - */ - public static List transpose(Object[] lists) { - return transpose(Arrays.asList(lists)); - } - - /** - * Transposes the given lists. - * So, <code>transpose([['a', 'b'], [1, 2]])</code> - * is <code>[['a', 1], ['b', 2]]</code> and - * <code>transpose([['a', 'b', 'c']])</code> - * is <code>[['a'], ['b'], ['c']]</code>. - * - * @param lists the given lists - * @return a List of the transposed lists - */ - public static List transpose(List lists) { - List result = new ArrayList(); - if (lists.isEmpty()) return result; - int minSize = Integer.MAX_VALUE; - for (Object listLike : lists) { - List list = (List) DefaultTypeTransformation.castToType(listLike, List.class); - if (list.size() < minSize) minSize = list.size(); - } - if (minSize == 0) return result; - for (int i = 0; i < minSize; i++) { - result.add(new ArrayList()); - } - for (Object listLike : lists) { - List list = (List) DefaultTypeTransformation.castToType(listLike, List.class); - for (int i = 0; i < minSize; i++) { - List resultList = (List) result.get(i); - resultList.add(list.get(i)); - } - } - return result; - } - - /** - * Selects the minimum value found in an array of items, so - * min([2, 4, 6] as Object[]) == 2. - * - * @param items an array of items - * @return the minimum value - */ - public static <T> T min(T[] items) { - return min((Iterable<T>)Arrays.asList(items)); - } - - /** - * @deprecated use min(Iterable) - */ - @Deprecated - public static <T> T min(Collection<T> items) { - return min((Iterable<T>)items); - } - - /** - * Selects the minimum value found in an Iterable of items. - * - * @param items an Iterable - * @return the minimum value - * @since 2.2.0 - */ - public static <T> T min(Iterable<T> items) { - T answer = null; - for (T value : items) { - if (value != null) { - if (answer == null || ScriptBytecodeAdapter.compareLessThan(value, answer)) { - answer = value; - } - } - } - return answer; - } - - /** - * Selects the maximum value found in an array of items, so - * min([2, 4, 6] as Object[]) == 6. - * - * @param items an array of items - * @return the maximum value - */ - public static <T> T max(T[] items) { - return max((Iterable<T>)Arrays.asList(items)); - } - - /** - * @deprecated use max(Iterable) - */ - @Deprecated - public static <T> T max(Collection<T> items) { - return max((Iterable<T>)items); - } - - /** - * Selects the maximum value found in an Iterable. - * - * @param items a Collection - * @return the maximum value - * @since 2.2.0 - */ - public static <T> T max(Iterable<T> items) { - T answer = null; - for (T value : items) { - if (value != null) { - if (answer == null || ScriptBytecodeAdapter.compareGreaterThan(value, answer)) { - answer = value; - } - } - } - return answer; - } - - /** - * Sums all the items from an array of items. - * - * @param items an array of items - * @return the sum of the items - */ - public static Object sum(Object[] items) { - return sum((Iterable)Arrays.asList(items)); - } - - /** - * @deprecated use sum(Iterable) - */ - @Deprecated - public static Object sum(Collection items) { - return sum((Iterable)items); - } - - /** - * Sums all the given items. - * - * @param items an Iterable of items - * @return the sum of the item - * @since 2.2.0 - */ - public static Object sum(Iterable items) { - return DefaultGroovyMethods.sum(items); - } - -}
http://git-wip-us.apache.org/repos/asf/groovy/blob/10110145/src/main/groovy/util/GroovyScriptEngine.java ---------------------------------------------------------------------- diff --git a/src/main/groovy/util/GroovyScriptEngine.java b/src/main/groovy/util/GroovyScriptEngine.java deleted file mode 100644 index 92e2486..0000000 --- a/src/main/groovy/util/GroovyScriptEngine.java +++ /dev/null @@ -1,694 +0,0 @@ -/* - * 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.util; - -import groovy.lang.Binding; -import groovy.lang.GroovyClassLoader; -import groovy.lang.GroovyCodeSource; -import groovy.lang.GroovyResourceLoader; -import groovy.lang.Script; -import org.codehaus.groovy.GroovyBugError; -import org.codehaus.groovy.ast.ClassNode; -import org.codehaus.groovy.ast.InnerClassNode; -import org.codehaus.groovy.classgen.GeneratorContext; -import org.codehaus.groovy.control.ClassNodeResolver; -import org.codehaus.groovy.control.CompilationFailedException; -import org.codehaus.groovy.control.CompilationUnit; -import org.codehaus.groovy.control.CompilerConfiguration; -import org.codehaus.groovy.control.Phases; -import org.codehaus.groovy.control.SourceUnit; -import org.codehaus.groovy.control.customizers.CompilationCustomizer; -import org.codehaus.groovy.runtime.IOGroovyMethods; -import org.codehaus.groovy.runtime.InvokerHelper; -import org.codehaus.groovy.tools.gse.DependencyTracker; -import org.codehaus.groovy.tools.gse.StringSetMap; - -import java.io.BufferedReader; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.lang.ref.WeakReference; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLConnection; -import java.security.AccessController; -import java.security.CodeSource; -import java.security.PrivilegedAction; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; - -/** - * Specific script engine able to reload modified scripts as well as dealing properly - * with dependent scripts. - * - * @author sam - * @author Marc Palmer - * @author Guillaume Laforge - * @author Jochen Theodorou - * @author Mattias Reichel - */ -public class GroovyScriptEngine implements ResourceConnector { - private static final ClassLoader CL_STUB = AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() { - public ClassLoader run() { - return new ClassLoader() {}; - } - }); - - private static final URL[] EMPTY_URL_ARRAY = new URL[0]; - - private static class LocalData { - CompilationUnit cu; - final StringSetMap dependencyCache = new StringSetMap(); - final Map<String, String> precompiledEntries = new HashMap<String, String>(); - } - - private static WeakReference<ThreadLocal<LocalData>> localData = new WeakReference<ThreadLocal<LocalData>>(null); - - private static synchronized ThreadLocal<LocalData> getLocalData() { - ThreadLocal<LocalData> local = localData.get(); - if (local != null) return local; - local = new ThreadLocal<LocalData>(); - localData = new WeakReference<ThreadLocal<LocalData>>(local); - return local; - } - - private final URL[] roots; - private final ResourceConnector rc; - private final ClassLoader parentLoader; - private GroovyClassLoader groovyLoader; - private final Map<String, ScriptCacheEntry> scriptCache = new ConcurrentHashMap<String, ScriptCacheEntry>(); - private CompilerConfiguration config; - - { - config = new CompilerConfiguration(CompilerConfiguration.DEFAULT); - config.setSourceEncoding(CompilerConfiguration.DEFAULT_SOURCE_ENCODING); - } - - - //TODO: more finals? - - private static class ScriptCacheEntry { - private final Class scriptClass; - private final long lastModified, lastCheck; - private final Set<String> dependencies; - private final boolean sourceNewer; - - public ScriptCacheEntry(Class clazz, long modified, long lastCheck, Set<String> depend, boolean sourceNewer) { - this.scriptClass = clazz; - this.lastModified = modified; - this.lastCheck = lastCheck; - this.dependencies = depend; - this.sourceNewer = sourceNewer; - } - - public ScriptCacheEntry(ScriptCacheEntry old, long lastCheck, boolean sourceNewer) { - this(old.scriptClass, old.lastModified, lastCheck, old.dependencies, sourceNewer); - } - } - - private class ScriptClassLoader extends GroovyClassLoader { - - - public ScriptClassLoader(GroovyClassLoader loader) { - super(loader); - } - - public ScriptClassLoader(ClassLoader loader, CompilerConfiguration config) { - super(loader, config, false); - setResLoader(); - } - - private void setResLoader() { - final GroovyResourceLoader rl = getResourceLoader(); - setResourceLoader(new GroovyResourceLoader() { - public URL loadGroovySource(String className) throws MalformedURLException { - String filename; - for (String extension : getConfig().getScriptExtensions()) { - filename = className.replace('.', File.separatorChar) + "." + extension; - try { - URLConnection dependentScriptConn = rc.getResourceConnection(filename); - return dependentScriptConn.getURL(); - } catch (ResourceException e) { - //TODO: maybe do something here? - } - } - return rl.loadGroovySource(className); - } - }); - } - - @Override - protected CompilationUnit createCompilationUnit(CompilerConfiguration configuration, CodeSource source) { - CompilationUnit cu = super.createCompilationUnit(configuration, source); - LocalData local = getLocalData().get(); - local.cu = cu; - final StringSetMap cache = local.dependencyCache; - final Map<String, String> precompiledEntries = local.precompiledEntries; - - // "." is used to transfer compilation dependencies, which will be - // recollected later during compilation - for (String depSourcePath : cache.get(".")) { - try { - cache.get(depSourcePath); - cu.addSource(getResourceConnection(depSourcePath).getURL()); - } catch (ResourceException e) { - /* ignore */ - } - } - - // remove all old entries including the "." entry - cache.clear(); - - cu.addPhaseOperation(new CompilationUnit.PrimaryClassNodeOperation() { - @Override - public void call(final SourceUnit source, GeneratorContext context, ClassNode classNode) - throws CompilationFailedException { - // GROOVY-4013: If it is an inner class, tracking its dependencies doesn't really - // serve any purpose and also interferes with the caching done to track dependencies - if (classNode instanceof InnerClassNode) return; - DependencyTracker dt = new DependencyTracker(source, cache, precompiledEntries); - dt.visitClass(classNode); - } - }, Phases.CLASS_GENERATION); - - cu.setClassNodeResolver(new ClassNodeResolver() { - @Override - public LookupResult findClassNode(String origName, CompilationUnit compilationUnit) { - CompilerConfiguration cc = compilationUnit.getConfiguration(); - String name = origName.replace('.', '/'); - for (String ext : cc.getScriptExtensions()) { - try { - String finalName = name + "." + ext; - URLConnection conn = rc.getResourceConnection(finalName); - URL url = conn.getURL(); - String path = url.toExternalForm(); - ScriptCacheEntry entry = scriptCache.get(path); - Class clazz = null; - if (entry != null) clazz = entry.scriptClass; - if (GroovyScriptEngine.this.isSourceNewer(entry)) { - try { - SourceUnit su = compilationUnit.addSource(url); - return new LookupResult(su, null); - } finally { - forceClose(conn); - } - } else { - precompiledEntries.put(origName, path); - } - if (clazz != null) { - ClassNode cn = new ClassNode(clazz); - return new LookupResult(null, cn); - } - } catch (ResourceException re) { - // skip - } - } - return super.findClassNode(origName, compilationUnit); - } - }); - - return cu; - } - - @Override - public Class parseClass(GroovyCodeSource codeSource, boolean shouldCacheSource) throws CompilationFailedException { - synchronized (sourceCache) { - return doParseClass(codeSource); - } - } - - private Class<?> doParseClass(GroovyCodeSource codeSource) { - // local is kept as hard reference to avoid garbage collection - ThreadLocal<LocalData> localTh = getLocalData(); - LocalData localData = new LocalData(); - localTh.set(localData); - StringSetMap cache = localData.dependencyCache; - Class<?> answer = null; - try { - updateLocalDependencyCache(codeSource, localData); - answer = super.parseClass(codeSource, false); - updateScriptCache(localData); - } finally { - cache.clear(); - localTh.remove(); - } - return answer; - } - - private void updateLocalDependencyCache(GroovyCodeSource codeSource, LocalData localData) { - // we put the old dependencies into local cache so createCompilationUnit - // can pick it up. We put that entry under the name "." - ScriptCacheEntry origEntry = scriptCache.get(codeSource.getName()); - Set<String> origDep = null; - if (origEntry != null) origDep = origEntry.dependencies; - if (origDep != null) { - Set<String> newDep = new HashSet<String>(origDep.size()); - for (String depName : origDep) { - ScriptCacheEntry dep = scriptCache.get(depName); - try { - if (origEntry == dep || GroovyScriptEngine.this.isSourceNewer(dep)) { - newDep.add(depName); - } - } catch (ResourceException re) { - - } - } - StringSetMap cache = localData.dependencyCache; - cache.put(".", newDep); - } - } - - private void updateScriptCache(LocalData localData) { - StringSetMap cache = localData.dependencyCache; - cache.makeTransitiveHull(); - long time = getCurrentTime(); - Set<String> entryNames = new HashSet<String>(); - for (Map.Entry<String, Set<String>> entry : cache.entrySet()) { - String className = entry.getKey(); - Class clazz = getClassCacheEntry(className); - if (clazz == null) continue; - - String entryName = getPath(clazz, localData.precompiledEntries); - if (entryNames.contains(entryName)) continue; - entryNames.add(entryName); - Set<String> value = convertToPaths(entry.getValue(), localData.precompiledEntries); - long lastModified; - try { - lastModified = getLastModified(entryName); - } catch (ResourceException e) { - lastModified = time; - } - ScriptCacheEntry cacheEntry = new ScriptCacheEntry(clazz, lastModified, time, value, false); - scriptCache.put(entryName, cacheEntry); - } - } - - private String getPath(Class clazz, Map<String, String> precompiledEntries) { - CompilationUnit cu = getLocalData().get().cu; - String name = clazz.getName(); - ClassNode classNode = cu.getClassNode(name); - if (classNode == null) { - // this is a precompiled class! - String path = precompiledEntries.get(name); - if (path == null) throw new GroovyBugError("Precompiled class " + name + " should be available in precompiled entries map, but was not."); - return path; - } else { - return classNode.getModule().getContext().getName(); - } - } - - private Set<String> convertToPaths(Set<String> orig, Map<String, String> precompiledEntries) { - Set<String> ret = new HashSet<String>(); - for (String className : orig) { - Class clazz = getClassCacheEntry(className); - if (clazz == null) continue; - ret.add(getPath(clazz, precompiledEntries)); - } - return ret; - } - } - - /** - * Simple testing harness for the GSE. Enter script roots as arguments and - * then input script names to run them. - * - * @param urls an array of URLs - * @throws Exception if something goes wrong - */ - public static void main(String[] urls) throws Exception { - GroovyScriptEngine gse = new GroovyScriptEngine(urls); - BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); - String line; - while (true) { - System.out.print("groovy> "); - if ((line = br.readLine()) == null || line.equals("quit")) { - break; - } - try { - System.out.println(gse.run(line, new Binding())); - } catch (Exception e) { - e.printStackTrace(); - } - } - } - - /** - * Initialize a new GroovyClassLoader with a default or - * constructor-supplied parentClassLoader. - * - * @return the parent classloader used to load scripts - */ - private GroovyClassLoader initGroovyLoader() { - GroovyClassLoader groovyClassLoader = - AccessController.doPrivileged(new PrivilegedAction<ScriptClassLoader>() { - public ScriptClassLoader run() { - if (parentLoader instanceof GroovyClassLoader) { - return new ScriptClassLoader((GroovyClassLoader) parentLoader); - } else { - return new ScriptClassLoader(parentLoader, config); - } - } - }); - for (URL root : roots) groovyClassLoader.addURL(root); - return groovyClassLoader; - } - - /** - * Get a resource connection as a <code>URLConnection</code> to retrieve a script - * from the <code>ResourceConnector</code>. - * - * @param resourceName name of the resource to be retrieved - * @return a URLConnection to the resource - * @throws ResourceException - */ - public URLConnection getResourceConnection(String resourceName) throws ResourceException { - // Get the URLConnection - URLConnection groovyScriptConn = null; - - ResourceException se = null; - for (URL root : roots) { - URL scriptURL = null; - try { - scriptURL = new URL(root, resourceName); - groovyScriptConn = openConnection(scriptURL); - - break; // Now this is a bit unusual - } catch (MalformedURLException e) { - String message = "Malformed URL: " + root + ", " + resourceName; - if (se == null) { - se = new ResourceException(message); - } else { - se = new ResourceException(message, se); - } - } catch (IOException e1) { - String message = "Cannot open URL: " + root + resourceName; - groovyScriptConn = null; - if (se == null) { - se = new ResourceException(message); - } else { - se = new ResourceException(message, se); - } - } - } - - if (se == null) se = new ResourceException("No resource for " + resourceName + " was found"); - - // If we didn't find anything, report on all the exceptions that occurred. - if (groovyScriptConn == null) throw se; - return groovyScriptConn; - } - - private static URLConnection openConnection(URL scriptURL) throws IOException { - URLConnection urlConnection = scriptURL.openConnection(); - verifyInputStream(urlConnection); - - return scriptURL.openConnection(); - } - - /** - * This method closes a {@link URLConnection} by getting its {@link InputStream} and calling the - * {@link InputStream#close()} method on it. The {@link URLConnection} doesn't have a close() method - * and relies on garbage collection to close the underlying connection to the file. - * Relying on garbage collection could lead to the application exhausting the number of files the - * user is allowed to have open at any one point in time and cause the application to crash - * ({@link java.io.FileNotFoundException} (Too many open files)). - * Hence the need for this method to explicitly close the underlying connection to the file. - * - * @param urlConnection the {@link URLConnection} to be "closed" to close the underlying file descriptors. - */ - private static void forceClose(URLConnection urlConnection) { - if (urlConnection != null) { - // We need to get the input stream and close it to force the open - // file descriptor to be released. Otherwise, we will reach the limit - // for number of files open at one time. - - try { - verifyInputStream(urlConnection); - } catch (Exception e) { - // Do nothing: We were not going to use it anyway. - } - } - } - - private static void verifyInputStream(URLConnection urlConnection) throws IOException { - InputStream in = null; - try { - in = urlConnection.getInputStream(); - } finally { - if (in != null) { - try { - in.close(); - } catch (IOException ignore) { - } - } - } - } - - /** - * The groovy script engine will run groovy scripts and reload them and - * their dependencies when they are modified. This is useful for embedding - * groovy in other containers like games and application servers. - * - * @param roots This an array of URLs where Groovy scripts will be stored. They should - * be laid out using their package structure like Java classes - */ - private GroovyScriptEngine(URL[] roots, ClassLoader parent, ResourceConnector rc) { - if (roots == null) roots = EMPTY_URL_ARRAY; - this.roots = roots; - if (rc == null) rc = this; - this.rc = rc; - if (parent == CL_STUB) parent = this.getClass().getClassLoader(); - this.parentLoader = parent; - this.groovyLoader = initGroovyLoader(); - } - - public GroovyScriptEngine(URL[] roots) { - this(roots, CL_STUB, null); - } - - public GroovyScriptEngine(URL[] roots, ClassLoader parentClassLoader) { - this(roots, parentClassLoader, null); - } - - public GroovyScriptEngine(String[] urls) throws IOException { - this(createRoots(urls), CL_STUB, null); - } - - private static URL[] createRoots(String[] urls) throws MalformedURLException { - if (urls == null) return null; - URL[] roots = new URL[urls.length]; - for (int i = 0; i < roots.length; i++) { - if (urls[i].contains("://")) { - roots[i] = new URL(urls[i]); - } else { - roots[i] = new File(urls[i]).toURI().toURL(); - } - } - return roots; - } - - public GroovyScriptEngine(String[] urls, ClassLoader parentClassLoader) throws IOException { - this(createRoots(urls), parentClassLoader, null); - } - - public GroovyScriptEngine(String url) throws IOException { - this(new String[]{url}); - } - - public GroovyScriptEngine(String url, ClassLoader parentClassLoader) throws IOException { - this(new String[]{url}, parentClassLoader); - } - - public GroovyScriptEngine(ResourceConnector rc) { - this(null, CL_STUB, rc); - } - - public GroovyScriptEngine(ResourceConnector rc, ClassLoader parentClassLoader) { - this(null, parentClassLoader, rc); - } - - /** - * Get the <code>ClassLoader</code> that will serve as the parent ClassLoader of the - * {@link GroovyClassLoader} in which scripts will be executed. By default, this is the - * ClassLoader that loaded the <code>GroovyScriptEngine</code> class. - * - * @return the parent classloader used to load scripts - */ - public ClassLoader getParentClassLoader() { - return parentLoader; - } - - /** - * Get the class of the scriptName in question, so that you can instantiate - * Groovy objects with caching and reloading. - * - * @param scriptName resource name pointing to the script - * @return the loaded scriptName as a compiled class - * @throws ResourceException if there is a problem accessing the script - * @throws ScriptException if there is a problem parsing the script - */ - public Class loadScriptByName(String scriptName) throws ResourceException, ScriptException { - URLConnection conn = rc.getResourceConnection(scriptName); - String path = conn.getURL().toExternalForm(); - ScriptCacheEntry entry = scriptCache.get(path); - Class clazz = null; - if (entry != null) clazz = entry.scriptClass; - try { - if (isSourceNewer(entry)) { - try { - String encoding = conn.getContentEncoding() != null ? conn.getContentEncoding() : config.getSourceEncoding(); - String content = IOGroovyMethods.getText(conn.getInputStream(), encoding); - clazz = groovyLoader.parseClass(content, path); - } catch (IOException e) { - throw new ResourceException(e); - } - } - } finally { - forceClose(conn); - } - return clazz; - } - - /** - * Run a script identified by name with a single argument. - * - * @param scriptName name of the script to run - * @param argument a single argument passed as a variable named <code>arg</code> in the binding - * @return a <code>toString()</code> representation of the result of the execution of the script - * @throws ResourceException if there is a problem accessing the script - * @throws ScriptException if there is a problem parsing the script - */ - public String run(String scriptName, String argument) throws ResourceException, ScriptException { - Binding binding = new Binding(); - binding.setVariable("arg", argument); - Object result = run(scriptName, binding); - return result == null ? "" : result.toString(); - } - - /** - * Run a script identified by name with a given binding. - * - * @param scriptName name of the script to run - * @param binding the binding to pass to the script - * @return an object - * @throws ResourceException if there is a problem accessing the script - * @throws ScriptException if there is a problem parsing the script - */ - public Object run(String scriptName, Binding binding) throws ResourceException, ScriptException { - return createScript(scriptName, binding).run(); - } - - /** - * Creates a Script with a given scriptName and binding. - * - * @param scriptName name of the script to run - * @param binding the binding to pass to the script - * @return the script object - * @throws ResourceException if there is a problem accessing the script - * @throws ScriptException if there is a problem parsing the script - */ - public Script createScript(String scriptName, Binding binding) throws ResourceException, ScriptException { - return InvokerHelper.createScript(loadScriptByName(scriptName), binding); - } - - private long getLastModified(String scriptName) throws ResourceException { - URLConnection conn = rc.getResourceConnection(scriptName); - long lastMod = 0; - try { - lastMod = conn.getLastModified(); - } finally { - // getResourceConnection() opening the inputstream, let's ensure all streams are closed - forceClose(conn); - } - return lastMod; - } - - protected boolean isSourceNewer(ScriptCacheEntry entry) throws ResourceException { - if (entry == null) return true; - - long mainEntryLastCheck = entry.lastCheck; - long now = 0; - - boolean returnValue = false; - for (String scriptName : entry.dependencies) { - ScriptCacheEntry depEntry = scriptCache.get(scriptName); - if (depEntry.sourceNewer) return true; - - // check if maybe dependency was recompiled, but this one here not - if (mainEntryLastCheck < depEntry.lastModified) { - returnValue = true; - continue; - } - - if (now == 0) now = getCurrentTime(); - long nextSourceCheck = depEntry.lastCheck + config.getMinimumRecompilationInterval(); - if (nextSourceCheck > now) continue; - - long lastMod = getLastModified(scriptName); - if (depEntry.lastModified < lastMod) { - depEntry = new ScriptCacheEntry(depEntry, lastMod, true); - scriptCache.put(scriptName, depEntry); - returnValue = true; - } else { - depEntry = new ScriptCacheEntry(depEntry, now, false); - scriptCache.put(scriptName, depEntry); - } - } - - return returnValue; - } - - /** - * Returns the GroovyClassLoader associated with this script engine instance. - * Useful if you need to pass the class loader to another library. - * - * @return the GroovyClassLoader - */ - public GroovyClassLoader getGroovyClassLoader() { - return groovyLoader; - } - - /** - * @return a non null compiler configuration - */ - public CompilerConfiguration getConfig() { - return config; - } - - /** - * sets a compiler configuration - * - * @param config - the compiler configuration - * @throws NullPointerException if config is null - */ - public void setConfig(CompilerConfiguration config) { - if (config == null) throw new NullPointerException("configuration cannot be null"); - this.config = config; - this.groovyLoader = initGroovyLoader(); - } - - protected long getCurrentTime() { - return System.currentTimeMillis(); - } -} http://git-wip-us.apache.org/repos/asf/groovy/blob/10110145/src/main/groovy/util/IFileNameFinder.java ---------------------------------------------------------------------- diff --git a/src/main/groovy/util/IFileNameFinder.java b/src/main/groovy/util/IFileNameFinder.java deleted file mode 100644 index 35e9012..0000000 --- a/src/main/groovy/util/IFileNameFinder.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * 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.util; - -import java.util.List; - -public interface IFileNameFinder { - List<String> getFileNames(String basedir, String pattern); - List<String> getFileNames(String basedir, String pattern, String excludesPattern); -} http://git-wip-us.apache.org/repos/asf/groovy/blob/10110145/src/main/groovy/util/IndentPrinter.java ---------------------------------------------------------------------- diff --git a/src/main/groovy/util/IndentPrinter.java b/src/main/groovy/util/IndentPrinter.java deleted file mode 100644 index df3d8c2..0000000 --- a/src/main/groovy/util/IndentPrinter.java +++ /dev/null @@ -1,234 +0,0 @@ -/* - * 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.util; - -import groovy.lang.GroovyRuntimeException; - -import java.io.IOException; -import java.io.PrintWriter; -import java.io.Writer; - -/** - * A helper class for printing indented text. This can be used stand-alone or, more commonly, from Builders. - * <p> - * By default, a PrintWriter to System.out is used as the Writer, but it is possible - * to change the Writer by passing a new one as a constructor argument. - * <p> - * Indention by default is 2 characters but can be changed by passing a - * different value as a constructor argument. - * <p> - * The following is an example usage. Note that within a "with" block you need to - * specify a parameter name so that this.println is not called instead of IndentPrinter.println: - * <pre> - * new IndentPrinter(new PrintWriter(out)).with { p -> - * p.printIndent() - * p.println('parent1') - * p.incrementIndent() - * p.printIndent() - * p.println('child 1') - * p.printIndent() - * p.println('child 2') - * p.decrementIndent() - * p.printIndent() - * p.println('parent2') - * p.flush() - * } - * </pre> - * The above example prints this to standard output: - * <pre> - * parent1 - * child 1 - * child 2 - * parent2 - * </pre> - * - * @author <a href="mailto:[email protected]">James Strachan</a> - */ -public class IndentPrinter { - - private int indentLevel; - private final String indent; - private final Writer out; - private final boolean addNewlines; - private boolean autoIndent; - - /** - * Creates an IndentPrinter backed by a PrintWriter pointing to System.out, with an indent of two spaces. - * - * @see #IndentPrinter(Writer, String) - */ - public IndentPrinter() { - this(new PrintWriter(System.out), " "); - } - - /** - * Creates an IndentPrinter backed by the supplied Writer, with an indent of two spaces. - * - * @param out Writer to output to - * @see #IndentPrinter(Writer, String) - */ - public IndentPrinter(Writer out) { - this(out, " "); - } - - /** - * Creates an IndentPrinter backed by the supplied Writer, - * with a user-supplied String to be used for indenting. - * - * @param out Writer to output to - * @param indent character(s) used to indent each line - */ - public IndentPrinter(Writer out, String indent) { - this(out, indent, true); - } - - /** - * Creates an IndentPrinter backed by the supplied Writer, - * with a user-supplied String to be used for indenting - * and the ability to override newline handling. - * - * @param out Writer to output to - * @param indent character(s) used to indent each line - * @param addNewlines set to false to gobble all new lines (default true) - */ - public IndentPrinter(Writer out, String indent, boolean addNewlines) { - this(out, indent, addNewlines, false); - } - - /** - * Create an IndentPrinter to the given PrintWriter - * @param out Writer to output to - * @param indent character(s) used to indent each line - * @param addNewlines set to false to gobble all new lines (default true) - * @param autoIndent set to true to make println() prepend the indent automatically (default false) - */ - public IndentPrinter(Writer out, String indent, boolean addNewlines, boolean autoIndent) { - this.addNewlines = addNewlines; - if (out == null) { - throw new IllegalArgumentException("Must specify a Writer"); - } - this.out = out; - this.indent = indent; - this.autoIndent = autoIndent; - } - - /** - * Prints a string followed by an end of line character. - * - * @param text String to be written - */ - public void println(String text) { - try { - if(autoIndent) printIndent(); - out.write(text); - println(); - } catch(IOException ioe) { - throw new GroovyRuntimeException(ioe); - } - } - - /** - * Prints a string. - * - * @param text String to be written - */ - public void print(String text) { - try { - out.write(text); - } catch(IOException ioe) { - throw new GroovyRuntimeException(ioe); - } - } - - /** - * Prints a character. - * - * @param c char to be written - */ - public void print(char c) { - try { - out.write(c); - } catch(IOException ioe) { - throw new GroovyRuntimeException(ioe); - } - } - - /** - * Prints the current indent level. - */ - public void printIndent() { - for (int i = 0; i < indentLevel; i++) { - try { - out.write(indent); - } catch(IOException ioe) { - throw new GroovyRuntimeException(ioe); - } - } - } - - /** - * Prints an end-of-line character (if enabled via addNewLines property). - * Defaults to outputting a single '\n' character but by using a custom - * Writer, e.g. PlatformLineWriter, you can get platform-specific - * end-of-line characters. - * - * @see #IndentPrinter(Writer, String, boolean) - */ - public void println() { - if (addNewlines) { - try { - out.write("\n"); - } catch(IOException ioe) { - throw new GroovyRuntimeException(ioe); - } - } - } - - public void incrementIndent() { - ++indentLevel; - } - - public void decrementIndent() { - --indentLevel; - } - - public int getIndentLevel() { - return indentLevel; - } - - public void setIndentLevel(int indentLevel) { - this.indentLevel = indentLevel; - } - - public boolean getAutoIndent(){ - return this.autoIndent; - } - - public void setAutoIndent(boolean autoIndent){ - this.autoIndent = autoIndent; - } - - public void flush() { - try { - out.flush(); - } catch(IOException ioe) { - throw new GroovyRuntimeException(ioe); - } - } -} http://git-wip-us.apache.org/repos/asf/groovy/blob/10110145/src/main/groovy/util/MapEntry.java ---------------------------------------------------------------------- diff --git a/src/main/groovy/util/MapEntry.java b/src/main/groovy/util/MapEntry.java deleted file mode 100644 index 9190fcd..0000000 --- a/src/main/groovy/util/MapEntry.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * 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.util; - -import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation; - -import java.util.Map; - -/** - * A Map.Entry implementation. - * - * @author <a href="mailto:[email protected]">James Strachan</a> - */ -public class MapEntry implements Map.Entry { - - private Object key; - private Object value; - - public MapEntry(Object key, Object value) { - this.key = key; - this.value = value; - } - - public boolean equals(Object that) { - if (that instanceof MapEntry) { - return equals((MapEntry) that); - } - return false; - } - - public boolean equals(MapEntry that) { - return DefaultTypeTransformation.compareEqual(this.key, that.key) && DefaultTypeTransformation.compareEqual(this.value, that.value); - } - - public int hashCode() { - return hash(key) ^ hash(value); - } - - public String toString() { - return "" + key + ":" + value; - } - - public Object getKey() { - return key; - } - - public void setKey(Object key) { - this.key = key; - } - - public Object getValue() { - return value; - } - - public Object setValue(Object value) { - this.value = value; - return value; - } - - /** - * Helper method to handle object hashes for possibly null values - */ - protected int hash(Object object) { - return (object == null) ? 0xbabe : object.hashCode(); - } - -} http://git-wip-us.apache.org/repos/asf/groovy/blob/10110145/src/main/groovy/util/Node.java ---------------------------------------------------------------------- diff --git a/src/main/groovy/util/Node.java b/src/main/groovy/util/Node.java deleted file mode 100644 index e40b14a..0000000 --- a/src/main/groovy/util/Node.java +++ /dev/null @@ -1,787 +0,0 @@ -/* - * 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.util; - -import groovy.lang.Closure; -import groovy.lang.DelegatingMetaClass; -import groovy.lang.GroovySystem; -import groovy.lang.MetaClass; -import groovy.lang.Tuple2; -import groovy.xml.QName; -import org.codehaus.groovy.runtime.DefaultGroovyMethods; -import org.codehaus.groovy.runtime.InvokerHelper; -import org.codehaus.groovy.util.ListHashMap; - -import java.io.PrintWriter; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Stack; - -/** - * Represents an arbitrary tree node which can be used for structured metadata or any arbitrary XML-like tree. - * A node can have a name, a value and an optional Map of attributes. - * Typically the name is a String and a value is either a String or a List of other Nodes, - * though the types are extensible to provide a flexible structure, e.g. you could use a - * QName as the name which includes a namespace URI and a local name. Or a JMX ObjectName etc. - * So this class can represent metadata like <code>{foo a=1 b="abc"}</code> or nested - * metadata like <code>{foo a=1 b="123" { bar x=12 text="hello" }}</code> - * - * @author <a href="mailto:[email protected]">James Strachan</a> - * @author Paul King - */ -public class Node implements Serializable, Cloneable { - - static { - // wrap the standard MetaClass with the delegate - setMetaClass(GroovySystem.getMetaClassRegistry().getMetaClass(Node.class), Node.class); - } - - private static final long serialVersionUID = 4121134753270542643L; - - private Node parent; - - private final Object name; - - private final Map attributes; - - private Object value; - - /** - * Creates a new Node with the same name, no parent, shallow cloned attributes - * and if the value is a NodeList, a (deep) clone of those nodes. - * - * @return the clone - */ - @Override - public Object clone() { - Object newValue = value; - if (value != null && value instanceof NodeList) { - NodeList nodes = (NodeList) value; - newValue = nodes.clone(); - } - return new Node(null, name, new HashMap(attributes), newValue); - } - - /** - * Creates a new Node named <code>name</code> and if a parent is supplied, adds - * the newly created node as a child of the parent. - * - * @param parent the parent node or null if no parent - * @param name the name of the node - */ - public Node(Node parent, Object name) { - this(parent, name, new NodeList()); - } - - /** - * Creates a new Node named <code>name</code> with value <code>value</code> and - * if a parent is supplied, adds the newly created node as a child of the parent. - * - * @param parent the parent node or null if no parent - * @param name the name of the node - * @param value the Node value, e.g. some text but in general any Object - */ - public Node(Node parent, Object name, Object value) { - this(parent, name, new HashMap(), value); - } - - /** - * Creates a new Node named <code>name</code> with - * attributes specified in the <code>attributes</code> Map. If a parent is supplied, - * the newly created node is added as a child of the parent. - * - * @param parent the parent node or null if no parent - * @param name the name of the node - * @param attributes a Map of name-value pairs - */ - public Node(Node parent, Object name, Map attributes) { - this(parent, name, attributes, new NodeList()); - } - - /** - * Creates a new Node named <code>name</code> with value <code>value</code> and - * with attributes specified in the <code>attributes</code> Map. If a parent is supplied, - * the newly created node is added as a child of the parent. - * - * @param parent the parent node or null if no parent - * @param name the name of the node - * @param attributes a Map of name-value pairs - * @param value the Node value, e.g. some text but in general any Object - */ - public Node(Node parent, Object name, Map attributes, Object value) { - this.parent = parent; - this.name = name; - this.attributes = attributes; - this.value = value; - - if (parent != null) { - getParentList(parent).add(this); - } - } - - private static List getParentList(Node parent) { - Object parentValue = parent.value(); - List parentList; - if (parentValue instanceof List) { - parentList = (List) parentValue; - } else { - parentList = new NodeList(); - parentList.add(parentValue); - parent.setValue(parentList); - } - return parentList; - } - - /** - * Appends a child to the current node. - * - * @param child the child to append - * @return <code>true</code> - */ - public boolean append(Node child) { - child.setParent(this); - return getParentList(this).add(child); - } - - /** - * Removes a child of the current node. - * - * @param child the child to remove - * @return <code>true</code> if the param was a child of the current node - */ - public boolean remove(Node child) { - child.setParent(null); - return getParentList(this).remove(child); - } - - /** - * Creates a new node as a child of the current node. - * - * @param name the name of the new node - * @param attributes the attributes of the new node - * @return the newly created <code>Node</code> - */ - public Node appendNode(Object name, Map attributes) { - return new Node(this, name, attributes); - } - - /** - * Creates a new node as a child of the current node. - * - * @param name the name of the new node - * @return the newly created <code>Node</code> - */ - public Node appendNode(Object name) { - return new Node(this, name); - } - - /** - * Creates a new node as a child of the current node. - * - * @param name the name of the new node - * @param value the value of the new node - * @return the newly created <code>Node</code> - */ - public Node appendNode(Object name, Object value) { - return new Node(this, name, value); - } - - /** - * Creates a new node as a child of the current node. - * - * @param name the name of the new node - * @param attributes the attributes of the new node - * @param value the value of the new node - * @return the newly created <code>Node</code> - */ - public Node appendNode(Object name, Map attributes, Object value) { - return new Node(this, name, attributes, value); - } - - /** - * Replaces the current node with nodes defined using builder-style notation via a Closure. - * - * @param c A Closure defining the new nodes using builder-style notation. - * @return the original now replaced node - */ - public Node replaceNode(Closure c) { - if (parent() == null) { - throw new UnsupportedOperationException("Replacing the root node is not supported"); - } - appendNodes(c); - getParentList(parent()).remove(this); - this.setParent(null); - return this; - } - - /** - * Replaces the current node with the supplied node. - * - * @param n the new Node - * @return the original now replaced node - */ - public Node replaceNode(Node n) { - if (parent() == null) { - throw new UnsupportedOperationException("Replacing the root node is not supported"); - } - List tail = getTail(); - parent().appendNode(n.name(), n.attributes(), n.value()); - parent().children().addAll(tail); - getParentList(parent()).remove(this); - this.setParent(null); - return this; - } - - private List getTail() { - List list = parent().children(); - int afterIndex = list.indexOf(this); - List tail = new ArrayList(list.subList(afterIndex + 1, list.size())); - list.subList(afterIndex + 1, list.size()).clear(); - return tail; - } - - /** - * Adds sibling nodes (defined using builder-style notation via a Closure) after the current node. - * - * @param c A Closure defining the new sibling nodes to add using builder-style notation. - */ - public void plus(Closure c) { - if (parent() == null) { - throw new UnsupportedOperationException("Adding sibling nodes to the root node is not supported"); - } - appendNodes(c); - } - - private void appendNodes(Closure c) { - List tail = getTail(); - for (Node child : buildChildrenFromClosure(c)) { - parent().appendNode(child.name(), child.attributes(), child.value()); - } - parent().children().addAll(tail); - } - - private static List<Node> buildChildrenFromClosure(Closure c) { - NodeBuilder b = new NodeBuilder(); - Node newNode = (Node) b.invokeMethod("dummyNode", c); - return newNode.children(); - } - - /** - * Extension point for subclasses to override the metaclass. The default - * one supports the property and @ attribute notations. - * - * @param metaClass the original metaclass - * @param nodeClass the class whose metaclass we wish to override (this class or a subclass) - */ - protected static void setMetaClass(final MetaClass metaClass, Class nodeClass) { - // TODO Is protected static a bit of a smell? - // TODO perhaps set nodeClass to be Class<? extends Node> - final MetaClass newMetaClass = new DelegatingMetaClass(metaClass) { - @Override - public Object getAttribute(final Object object, final String attribute) { - Node n = (Node) object; - return n.get("@" + attribute); - } - - @Override - public void setAttribute(final Object object, final String attribute, final Object newValue) { - Node n = (Node) object; - n.attributes().put(attribute, newValue); - } - - @Override - public Object getProperty(Object object, String property) { - if (object instanceof Node) { - Node n = (Node) object; - return n.get(property); - } - return super.getProperty(object, property); - } - - @Override - public void setProperty(Object object, String property, Object newValue) { - if (property.startsWith("@")) { - setAttribute(object, property.substring(1), newValue); - return; - } - delegate.setProperty(object, property, newValue); - } - - }; - GroovySystem.getMetaClassRegistry().setMetaClass(nodeClass, newMetaClass); - } - - /** - * Returns the textual representation of the current node and all its child nodes. - * - * @return the text value of the node including child text - */ - public String text() { - if (value instanceof String) { - return (String) value; - } - if (value instanceof NodeList) { - return ((NodeList) value).text(); - } - if (value instanceof Collection) { - Collection coll = (Collection) value; - String previousText = null; - StringBuilder sb = null; - for (Object child : coll) { - String childText = null; - if (child instanceof String) { - childText = (String) child; - } else if (child instanceof Node) { - childText = ((Node) child).text(); - } - if (childText != null) { - if (previousText == null) { - previousText = childText; - } else { - if (sb == null) { - sb = new StringBuilder(); - sb.append(previousText); - } - sb.append(childText); - } - } - } - if (sb != null) { - return sb.toString(); - } else { - if (previousText != null) { - return previousText; - } - return ""; - } - } - return "" + value; - } - - /** - * Returns an <code>Iterator</code> of the children of the node. - * - * @return the iterator of the nodes children - */ - public Iterator iterator() { - return children().iterator(); - } - - /** - * Returns a <code>List</code> of the nodes children. - * - * @return the nodes children - */ - public List children() { - if (value == null) { - return new NodeList(); - } - if (value instanceof List) { - return (List) value; - } - // we're probably just a String - List result = new NodeList(); - result.add(value); - return result; - } - - /** - * Returns a <code>Map</code> of the attributes of the node or an empty <code>Map</code> - * if the node does not have any attributes. - * - * @return the attributes of the node - */ - public Map attributes() { - return attributes; - } - - /** - * Provides lookup of attributes by key. - * - * @param key the key of interest - * @return the attribute matching the key or <code>null</code> if no match exists - */ - public Object attribute(Object key) { - return (attributes != null) ? attributes.get(key) : null; - } - - /** - * Returns an <code>Object</code> representing the name of the node. - * - * @return the name or <code>null</code> if name is empty - */ - public Object name() { - return name; - } - - /** - * Returns an <code>Object</code> representing the value of the node. - * - * @return the value or <code>null</code> if value is empty - */ - public Object value() { - return value; - } - - /** - * Adds or replaces the value of the node. - * - * @param value the new value of the node - */ - public void setValue(Object value) { - this.value = value; - } - - /** - * Returns the parent of the node. - * - * @return the parent or <code>null</code> for the root node - */ - public Node parent() { - return parent; - } - - /** - * Adds or replaces the parent of the node. - * - * @param parent the new parent of the node - */ - protected void setParent(Node parent) { - this.parent = parent; - } - - /** - * Provides lookup of elements by non-namespaced name - * - * @param key the name (or shortcut key) of the node(s) of interest - * @return the nodes which match key - */ - public Object get(String key) { - if (key != null && key.charAt(0) == '@') { - String attributeName = key.substring(1); - return attributes().get(attributeName); - } - if ("..".equals(key)) { - return parent(); - } - if ("*".equals(key)) { - return children(); - } - if ("**".equals(key)) { - return depthFirst(); - } - return getByName(key); - } - - /** - * Provides lookup of elements by QName. - * - * @param name the QName of interest - * @return the nodes matching name - */ - public NodeList getAt(QName name) { - NodeList answer = new NodeList(); - for (Object child : children()) { - if (child instanceof Node) { - Node childNode = (Node) child; - Object childNodeName = childNode.name(); - if (name.matches(childNodeName)) { - answer.add(childNode); - } - } - } - return answer; - } - - /** - * Provides lookup of elements by name. - * - * @param name the name of interest - * @return the nodes matching name - */ - private NodeList getByName(String name) { - NodeList answer = new NodeList(); - for (Object child : children()) { - if (child instanceof Node) { - Node childNode = (Node) child; - Object childNodeName = childNode.name(); - if (childNodeName instanceof QName) { - QName qn = (QName) childNodeName; - if (qn.matches(name)) { - answer.add(childNode); - } - } else if (name.equals(childNodeName)) { - answer.add(childNode); - } - } - } - return answer; - } - - /** - * Provides a collection of all the nodes in the tree - * using a depth-first preorder traversal. - * - * @return the list of (depth-first) ordered nodes - */ - public List depthFirst() { - return depthFirst(true); - } - - /** - * Provides a collection of all the nodes in the tree - * using a depth-first traversal. - * - * @param preorder if false, a postorder depth-first traversal will be performed - * @return the list of (depth-first) ordered nodes - * @since 2.5.0 - */ - public List depthFirst(boolean preorder) { - List answer = new NodeList(); - if (preorder) answer.add(this); - answer.addAll(depthFirstRest(preorder)); - if (!preorder) answer.add(this); - return answer; - } - - private List depthFirstRest(boolean preorder) { - List answer = new NodeList(); - for (Iterator iter = InvokerHelper.asIterator(value); iter.hasNext(); ) { - Object child = iter.next(); - if (child instanceof Node) { - Node childNode = (Node) child; - List children = childNode.depthFirstRest(preorder); - if (preorder) answer.add(childNode); - if (children.size() > 1 || (children.size() == 1 && !(children.get(0) instanceof String))) answer.addAll(children); - if (!preorder) answer.add(childNode); - } else if (child instanceof String) { - answer.add(child); - } - } - return answer; - } - - /** - * Provides a collection of all the nodes in the tree - * using a depth-first preorder traversal. - * - * @param c the closure to run for each node (a one or two parameter can be used; if one parameter is given the - * closure will be passed the node, for a two param closure the second parameter will be the level). - * @since 2.5.0 - */ - public void depthFirst(Closure c) { - Map<String, Object> options = new ListHashMap<String, Object>(); - options.put("preorder", true); - depthFirst(options, c); - } - - /** - * Provides a collection of all the nodes in the tree - * using a depth-first traversal. - * A boolean 'preorder' options is supported. - * - * @param options map containing options - * @param c the closure to run for each node (a one or two parameter can be used; if one parameter is given the - * closure will be passed the node, for a two param closure the second parameter will be the level). - * @since 2.5.0 - */ - public void depthFirst(Map<String, Object> options, Closure c) { - boolean preorder = Boolean.valueOf(options.get("preorder").toString()); - if (preorder) callClosureForNode(c, this, 1); - depthFirstRest(preorder, 2, c); - if (!preorder) callClosureForNode(c, this, 1); - } - - private static <T> T callClosureForNode(Closure<T> closure, Object node, int level) { - if (closure.getMaximumNumberOfParameters() == 2) { - return closure.call(new Object[]{node, level}); - } - return closure.call(node); - } - - private void depthFirstRest(boolean preorder, int level, Closure c) { - for (Iterator iter = InvokerHelper.asIterator(value); iter.hasNext(); ) { - Object child = iter.next(); - if (child instanceof Node) { - Node childNode = (Node) child; - if (preorder) callClosureForNode(c, childNode, level); - childNode.depthFirstRest(preorder, level + 1, c); - if (!preorder) callClosureForNode(c, childNode, level); - } - } - } - - /** - * Provides a collection of all the nodes in the tree - * using a breadth-first preorder traversal. - * - * @return the list of (breadth-first) ordered nodes - */ - public List breadthFirst() { - return breadthFirst(true); - } - - /** - * Provides a collection of all the nodes in the tree - * using a breadth-first traversal. - * - * @param preorder if false, a postorder breadth-first traversal will be performed - * @return the list of (breadth-first) ordered nodes - * @since 2.5.0 - */ - public List breadthFirst(boolean preorder) { - List answer = new NodeList(); - if (preorder) answer.add(this); - answer.addAll(breadthFirstRest(preorder)); - if (!preorder) answer.add(this); - return answer; - } - - private List breadthFirstRest(boolean preorder) { - List answer = new NodeList(); - Stack stack = new Stack(); - List nextLevelChildren = preorder ? getDirectChildren() : DefaultGroovyMethods.reverse(getDirectChildren()); - while (!nextLevelChildren.isEmpty()) { - List working = new NodeList(nextLevelChildren); - nextLevelChildren = new NodeList(); - for (Object child : working) { - if (preorder) { - answer.add(child); - } else { - stack.push(child); - } - if (child instanceof Node) { - Node childNode = (Node) child; - List children = childNode.getDirectChildren(); - if (children.size() > 1 || (children.size() == 1 && !(children.get(0) instanceof String))) nextLevelChildren.addAll(preorder ? children : DefaultGroovyMethods.reverse(children)); - } - } - } - while (!stack.isEmpty()) { - answer.add(stack.pop()); - } - return answer; - } - - /** - * Calls the provided closure for all the nodes in the tree - * using a breadth-first preorder traversal. - * - * @param c the closure to run for each node (a one or two parameter can be used; if one parameter is given the - * closure will be passed the node, for a two param closure the second parameter will be the level). - * @since 2.5.0 - */ - public void breadthFirst(Closure c) { - Map<String, Object> options = new ListHashMap<String, Object>(); - options.put("preorder", true); - breadthFirst(options, c); - } - - /** - * Calls the provided closure for all the nodes in the tree - * using a breadth-first traversal. - * A boolean 'preorder' options is supported. - * - * @param options map containing options - * @param c the closure to run for each node (a one or two parameter can be used; if one parameter is given the - * closure will be passed the node, for a two param closure the second parameter will be the level). - * @since 2.5.0 - */ - public void breadthFirst(Map<String, Object> options, Closure c) { - boolean preorder = Boolean.valueOf(options.get("preorder").toString()); - if (preorder) callClosureForNode(c, this, 1); - breadthFirstRest(preorder, 2, c); - if (!preorder) callClosureForNode(c, this, 1); - } - - private void breadthFirstRest(boolean preorder, int level, Closure c) { - Stack<Tuple2<Object, Integer>> stack = new Stack<Tuple2<Object, Integer>>(); - List nextLevelChildren = preorder ? getDirectChildren() : DefaultGroovyMethods.reverse(getDirectChildren()); - while (!nextLevelChildren.isEmpty()) { - List working = new NodeList(nextLevelChildren); - nextLevelChildren = new NodeList(); - for (Object child : working) { - if (preorder) { - callClosureForNode(c, child, level); - } else { - stack.push(new Tuple2<Object, Integer>(child, level)); - } - if (child instanceof Node) { - Node childNode = (Node) child; - List children = childNode.getDirectChildren(); - if (children.size() > 1 || (children.size() == 1 && !(children.get(0) instanceof String))) nextLevelChildren.addAll(preorder ? children : DefaultGroovyMethods.reverse(children)); - } - } - level++; - } - while (!stack.isEmpty()) { - Tuple2<Object, Integer> next = stack.pop(); - callClosureForNode(c, next.getFirst(), next.getSecond()); - } - } - - /** - * Returns the list of any direct String nodes of this node. - * - * @return the list of String values from this node - * @since 2.3.0 - */ - public List<String> localText() { - List<String> answer = new ArrayList<String>(); - for (Iterator iter = InvokerHelper.asIterator(value); iter.hasNext(); ) { - Object child = iter.next(); - if (!(child instanceof Node)) { - answer.add(child.toString()); - } - } - return answer; - } - - private List getDirectChildren() { - List answer = new NodeList(); - for (Iterator iter = InvokerHelper.asIterator(value); iter.hasNext(); ) { - Object child = iter.next(); - if (child instanceof Node) { - Node childNode = (Node) child; - answer.add(childNode); - } else if (child instanceof String) { - answer.add(child); - } - } - return answer; - } - - public String toString() { - return name + "[attributes=" + attributes + "; value=" + value + "]"; - } - - /** - * Writes the node to the specified <code>PrintWriter</code>. - * - * @param out the writer receiving the output - */ - public void print(PrintWriter out) { - new NodePrinter(out).print(this); - } -} http://git-wip-us.apache.org/repos/asf/groovy/blob/10110145/src/main/groovy/util/NodeBuilder.java ---------------------------------------------------------------------- diff --git a/src/main/groovy/util/NodeBuilder.java b/src/main/groovy/util/NodeBuilder.java deleted file mode 100644 index babe5c3..0000000 --- a/src/main/groovy/util/NodeBuilder.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * 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.util; - -import java.util.Map; - -/** - * A helper class for creating nested trees of Node objects for - * handling arbitrary data - * - * @author <a href="mailto:[email protected]">James Strachan</a> - */ -public class NodeBuilder extends BuilderSupport { - - public static NodeBuilder newInstance() { - return new NodeBuilder(); - } - - protected void setParent(Object parent, Object child) { - } - - protected Object createNode(Object name) { - return new Node(getCurrentNode(), name); - } - - protected Object createNode(Object name, Object value) { - return new Node(getCurrentNode(), name, value); - } - - protected Object createNode(Object name, Map attributes) { - return new Node(getCurrentNode(), name, attributes); - } - - protected Object createNode(Object name, Map attributes, Object value) { - return new Node(getCurrentNode(), name, attributes, value); - } - - protected Node getCurrentNode() { - return (Node) getCurrent(); - } -} http://git-wip-us.apache.org/repos/asf/groovy/blob/10110145/src/main/groovy/util/NodeList.java ---------------------------------------------------------------------- diff --git a/src/main/groovy/util/NodeList.java b/src/main/groovy/util/NodeList.java deleted file mode 100644 index e54009c..0000000 --- a/src/main/groovy/util/NodeList.java +++ /dev/null @@ -1,202 +0,0 @@ -/* - * 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.util; - -import groovy.lang.Closure; -import groovy.lang.DelegatingMetaClass; -import groovy.lang.GroovyRuntimeException; -import groovy.lang.GroovySystem; -import groovy.lang.MetaClass; -import groovy.xml.QName; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Iterator; -import java.util.List; - -/** - * A List implementation which is returned by queries on a {@link Node} - * which provides some XPath like helper methods for GPath. - * - * @author <a href="mailto:[email protected]">James Strachan</a> - * @author Paul King - */ -public class NodeList extends ArrayList { - static { - // wrap the standard MetaClass with the delegate - setMetaClass(NodeList.class, GroovySystem.getMetaClassRegistry().getMetaClass(NodeList.class)); - } - - public NodeList() { - } - - public NodeList(Collection collection) { - super(collection); - } - - public NodeList(int size) { - super(size); - } - - /** - * Creates a new NodeList containing the same elements as the - * original (but cloned in the case of Nodes). - * - * @return the clone - */ - @Override - public Object clone() { - NodeList result = new NodeList(size()); - for (int i = 0; i < size(); i++) { - Object next = get(i); - if (next instanceof Node) { - Node n = (Node) next; - result.add(n.clone()); - } else { - result.add(next); - } - } - return result; - } - - protected static void setMetaClass(final Class nodelistClass, final MetaClass metaClass) { - final MetaClass newMetaClass = new DelegatingMetaClass(metaClass) { - @Override - public Object getAttribute(final Object object, final String attribute) { - NodeList nl = (NodeList) object; - Iterator it = nl.iterator(); - List result = new ArrayList(); - while (it.hasNext()) { - Node node = (Node) it.next(); - result.add(node.attributes().get(attribute)); - } - return result; - } - - @Override - public void setAttribute(final Object object, final String attribute, final Object newValue) { - for (Object o : (NodeList) object) { - Node node = (Node) o; - node.attributes().put(attribute, newValue); - } - } - - @Override - public Object getProperty(Object object, String property) { - if (object instanceof NodeList) { - NodeList nl = (NodeList) object; - return nl.getAt(property); - } - return super.getProperty(object, property); - } - }; - GroovySystem.getMetaClassRegistry().setMetaClass(nodelistClass, newMetaClass); - } - - /** - * Provides lookup of elements by non-namespaced name. - * - * @param name the name or shortcut key for nodes of interest - * @return the nodes of interest which match name - */ - public NodeList getAt(String name) { - NodeList answer = new NodeList(); - for (Object child : this) { - if (child instanceof Node) { - Node childNode = (Node) child; - Object temp = childNode.get(name); - if (temp instanceof Collection) { - answer.addAll((Collection) temp); - } else { - answer.add(temp); - } - } - } - return answer; - } - - /** - * Provides lookup of elements by QName. - * - * @param name the name or shortcut key for nodes of interest - * @return the nodes of interest which match name - */ - public NodeList getAt(QName name) { - NodeList answer = new NodeList(); - for (Object child : this) { - if (child instanceof Node) { - Node childNode = (Node) child; - NodeList temp = childNode.getAt(name); - answer.addAll(temp); - } - } - return answer; - } - - /** - * Returns the text value of all of the elements in the collection. - * - * @return the text value of all the elements in the collection or null - */ - public String text() { - String previousText = null; - StringBuilder buffer = null; - for (Object child : this) { - String text = null; - if (child instanceof String) { - text = (String) child; - } else if (child instanceof Node) { - text = ((Node) child).text(); - } - if (text != null) { - if (previousText == null) { - previousText = text; - } else { - if (buffer == null) { - buffer = new StringBuilder(); - buffer.append(previousText); - } - buffer.append(text); - } - } - } - if (buffer != null) { - return buffer.toString(); - } - if (previousText != null) { - return previousText; - } - return ""; - } - - public Node replaceNode(Closure c) { - if (size() <= 0 || size() > 1) { - throw new GroovyRuntimeException( - "replaceNode() can only be used to replace a single node, but was applied to " + size() + " nodes"); - } - return ((Node)get(0)).replaceNode(c); - } - - public void plus(Closure c) { - for (Object o : this) { - ((Node) o).plus(c); - } - } - -}
