001/*
002 * Copyright 2002-2016 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.scripting.groovy;
018
019import java.io.IOException;
020import java.util.Map;
021
022import groovy.lang.Binding;
023import groovy.lang.GroovyRuntimeException;
024import groovy.lang.GroovyShell;
025import org.codehaus.groovy.control.CompilerConfiguration;
026import org.codehaus.groovy.control.customizers.CompilationCustomizer;
027
028import org.springframework.beans.factory.BeanClassLoaderAware;
029import org.springframework.scripting.ScriptCompilationException;
030import org.springframework.scripting.ScriptEvaluator;
031import org.springframework.scripting.ScriptSource;
032import org.springframework.scripting.support.ResourceScriptSource;
033
034/**
035 * Groovy-based implementation of Spring's {@link ScriptEvaluator} strategy interface.
036 *
037 * @author Juergen Hoeller
038 * @since 4.0
039 * @see GroovyShell#evaluate(String, String)
040 */
041public class GroovyScriptEvaluator implements ScriptEvaluator, BeanClassLoaderAware {
042
043        private ClassLoader classLoader;
044
045        private CompilerConfiguration compilerConfiguration = new CompilerConfiguration();
046
047
048        /**
049         * Construct a new GroovyScriptEvaluator.
050         */
051        public GroovyScriptEvaluator() {
052        }
053
054        /**
055         * Construct a new GroovyScriptEvaluator.
056         * @param classLoader the ClassLoader to use as a parent for the {@link GroovyShell}
057         */
058        public GroovyScriptEvaluator(ClassLoader classLoader) {
059                this.classLoader = classLoader;
060        }
061
062
063        /**
064         * Set a custom compiler configuration for this evaluator.
065         * @since 4.3.3
066         * @see #setCompilationCustomizers
067         */
068        public void setCompilerConfiguration(CompilerConfiguration compilerConfiguration) {
069                this.compilerConfiguration =
070                                (compilerConfiguration != null ? compilerConfiguration : new CompilerConfiguration());
071        }
072
073        /**
074         * Return this evaluator's compiler configuration (never {@code null}).
075         * @since 4.3.3
076         * @see #setCompilerConfiguration
077         */
078        public CompilerConfiguration getCompilerConfiguration() {
079                return this.compilerConfiguration;
080        }
081
082        /**
083         * Set one or more customizers to be applied to this evaluator's compiler configuration.
084         * <p>Note that this modifies the shared compiler configuration held by this evaluator.
085         * @since 4.3.3
086         * @see #setCompilerConfiguration
087         */
088        public void setCompilationCustomizers(CompilationCustomizer... compilationCustomizers) {
089                this.compilerConfiguration.addCompilationCustomizers(compilationCustomizers);
090        }
091
092        @Override
093        public void setBeanClassLoader(ClassLoader classLoader) {
094                this.classLoader = classLoader;
095        }
096
097
098        @Override
099        public Object evaluate(ScriptSource script) {
100                return evaluate(script, null);
101        }
102
103        @Override
104        public Object evaluate(ScriptSource script, Map<String, Object> arguments) {
105                GroovyShell groovyShell = new GroovyShell(
106                                this.classLoader, new Binding(arguments), this.compilerConfiguration);
107                try {
108                        String filename = (script instanceof ResourceScriptSource ?
109                                        ((ResourceScriptSource) script).getResource().getFilename() : null);
110                        if (filename != null) {
111                                return groovyShell.evaluate(script.getScriptAsString(), filename);
112                        }
113                        else {
114                                return groovyShell.evaluate(script.getScriptAsString());
115                        }
116                }
117                catch (IOException ex) {
118                        throw new ScriptCompilationException(script, "Cannot access Groovy script", ex);
119                }
120                catch (GroovyRuntimeException ex) {
121                        throw new ScriptCompilationException(script, ex);
122                }
123        }
124
125}