/* * Copyright (c) 2006-2011 Nuxeo SA (http://nuxeo.com/) and others. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * bstefanescu */ package org.eclipse.ecr.automation.core.scripting; import groovy.lang.Binding; import groovy.lang.GroovyClassLoader; import groovy.lang.GroovyCodeSource; import groovy.lang.Script; import java.io.File; import java.io.IOException; import java.net.URL; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import org.codehaus.groovy.control.CompilerConfiguration; import org.codehaus.groovy.runtime.InvokerHelper; /** * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a> * */ public class GroovyScripting { protected final GroovyClassLoader loader; // compiled script class cache protected Map<File, Entry> cache; public static ClassLoader getParentLoader() { ClassLoader cl = Thread.currentThread().getContextClassLoader(); return cl == null ? GroovyScripting.class.getClassLoader() : cl; } public GroovyScripting() { this(getParentLoader(), new CompilerConfiguration()); } public GroovyScripting(boolean debug) { this(getParentLoader(), debug); } public GroovyScripting(ClassLoader parent, boolean debug) { CompilerConfiguration cfg = new CompilerConfiguration(); cfg.setDebug(debug); if (debug) { cfg.setRecompileGroovySource(true); } loader = new GroovyClassLoader(parent, cfg); cache = new ConcurrentHashMap<File, Entry>(); } public GroovyScripting(ClassLoader parent, CompilerConfiguration cfg) { loader = new GroovyClassLoader(parent, cfg); cache = new ConcurrentHashMap<File, Entry>(); } public void addClasspath(String cp) { loader.addClasspath(cp); } public void addClasspathUrl(URL cp) { loader.addURL(cp); } public void clearCache() { cache = new ConcurrentHashMap<File, Entry>(); loader.clearCache(); } public Class<?> loadClass(String className) throws ClassNotFoundException { return loader.loadClass(className); } public GroovyClassLoader getGroovyClassLoader() { return loader; } // TODO add debug mode : return new GroovyShell(new // Binding(args)).evaluate(script.getFile()); ? public Object eval(File file, Map<String, Object> context) throws IOException { return eval(file, context == null ? new Binding() : new Binding(context)); } public Object eval(File file, Binding context) throws IOException { // convenience out global variable (for compatibility with scripts on // webengine 1.0 beta) context.setVariable("out", System.out); return getScript(file, context).run(); } public Class<?> compile(File file) throws IOException { GroovyCodeSource codeSource = new GroovyCodeSource(file); // do not use cache - we are maintaining our proper cache - based on // lastModified return loader.parseClass(codeSource, false); } public Script getScript(File file, Binding context) throws IOException { Class<?> klass = null; long lastModified = file.lastModified(); Entry entry = cache.get(file); if (entry != null && entry.lastModified == lastModified) { // in cache - // use it klass = entry.klass; } else { // not in cache or invalid klass = compile(file); // compile cache.put(file, new Entry(klass, lastModified)); // cache it } return InvokerHelper.createScript(klass, context); } public Script getScript(String content, Binding context) { Class<?> klass = loader.parseClass(content); // compile return InvokerHelper.createScript(klass, context); } static class Entry { final long lastModified; final Class<?> klass; Entry(Class<?> klass, long lastModified) { this.klass = klass; this.lastModified = lastModified; } } }