All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.springframework.scripting.bsh.BshScriptFactory Maven / Gradle / Ivy

There is a newer version: 6.1.6
Show newest version
/*
 * Copyright 2002-2016 the original author or authors.
 *
 * Licensed 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.springframework.scripting.bsh;

import java.io.IOException;

import bsh.EvalError;

import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.scripting.ScriptCompilationException;
import org.springframework.scripting.ScriptFactory;
import org.springframework.scripting.ScriptSource;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;

/**
 * {@link org.springframework.scripting.ScriptFactory} implementation
 * for a BeanShell script.
 *
 * 

Typically used in combination with a * {@link org.springframework.scripting.support.ScriptFactoryPostProcessor}; * see the latter's javadoc for a configuration example. * * @author Juergen Hoeller * @author Rob Harrop * @since 2.0 * @see BshScriptUtils * @see org.springframework.scripting.support.ScriptFactoryPostProcessor */ public class BshScriptFactory implements ScriptFactory, BeanClassLoaderAware { private final String scriptSourceLocator; private final Class[] scriptInterfaces; private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader(); private Class scriptClass; private final Object scriptClassMonitor = new Object(); private boolean wasModifiedForTypeCheck = false; /** * Create a new BshScriptFactory for the given script source. *

With this {@code BshScriptFactory} variant, the script needs to * declare a full class or return an actual instance of the scripted object. * @param scriptSourceLocator a locator that points to the source of the script. * Interpreted by the post-processor that actually creates the script. */ public BshScriptFactory(String scriptSourceLocator) { Assert.hasText(scriptSourceLocator, "'scriptSourceLocator' must not be empty"); this.scriptSourceLocator = scriptSourceLocator; this.scriptInterfaces = null; } /** * Create a new BshScriptFactory for the given script source. *

The script may either be a simple script that needs a corresponding proxy * generated (implementing the specified interfaces), or declare a full class * or return an actual instance of the scripted object (in which case the * specified interfaces, if any, need to be implemented by that class/instance). * @param scriptSourceLocator a locator that points to the source of the script. * Interpreted by the post-processor that actually creates the script. * @param scriptInterfaces the Java interfaces that the scripted object * is supposed to implement (may be {@code null}) */ public BshScriptFactory(String scriptSourceLocator, Class... scriptInterfaces) { Assert.hasText(scriptSourceLocator, "'scriptSourceLocator' must not be empty"); this.scriptSourceLocator = scriptSourceLocator; this.scriptInterfaces = scriptInterfaces; } @Override public void setBeanClassLoader(ClassLoader classLoader) { this.beanClassLoader = classLoader; } @Override public String getScriptSourceLocator() { return this.scriptSourceLocator; } @Override public Class[] getScriptInterfaces() { return this.scriptInterfaces; } /** * BeanShell scripts do require a config interface. */ @Override public boolean requiresConfigInterface() { return true; } /** * Load and parse the BeanShell script via {@link BshScriptUtils}. * @see BshScriptUtils#createBshObject(String, Class[], ClassLoader) */ @Override public Object getScriptedObject(ScriptSource scriptSource, Class... actualInterfaces) throws IOException, ScriptCompilationException { Class clazz; try { synchronized (this.scriptClassMonitor) { boolean requiresScriptEvaluation = (this.wasModifiedForTypeCheck && this.scriptClass == null); this.wasModifiedForTypeCheck = false; if (scriptSource.isModified() || requiresScriptEvaluation) { // New script content: Let's check whether it evaluates to a Class. Object result = BshScriptUtils.evaluateBshScript( scriptSource.getScriptAsString(), actualInterfaces, this.beanClassLoader); if (result instanceof Class) { // A Class: We'll cache the Class here and create an instance // outside of the synchronized block. this.scriptClass = (Class) result; } else { // Not a Class: OK, we'll simply create BeanShell objects // through evaluating the script for every call later on. // For this first-time check, let's simply return the // already evaluated object. return result; } } clazz = this.scriptClass; } } catch (EvalError ex) { this.scriptClass = null; throw new ScriptCompilationException(scriptSource, ex); } if (clazz != null) { // A Class: We need to create an instance for every call. try { return clazz.newInstance(); } catch (Throwable ex) { throw new ScriptCompilationException( scriptSource, "Could not instantiate script class: " + clazz.getName(), ex); } } else { // Not a Class: We need to evaluate the script for every call. try { return BshScriptUtils.createBshObject( scriptSource.getScriptAsString(), actualInterfaces, this.beanClassLoader); } catch (EvalError ex) { throw new ScriptCompilationException(scriptSource, ex); } } } @Override public Class getScriptedObjectType(ScriptSource scriptSource) throws IOException, ScriptCompilationException { synchronized (this.scriptClassMonitor) { try { if (scriptSource.isModified()) { // New script content: Let's check whether it evaluates to a Class. this.wasModifiedForTypeCheck = true; this.scriptClass = BshScriptUtils.determineBshObjectType( scriptSource.getScriptAsString(), this.beanClassLoader); } return this.scriptClass; } catch (EvalError ex) { this.scriptClass = null; throw new ScriptCompilationException(scriptSource, ex); } } } @Override public boolean requiresScriptedObjectRefresh(ScriptSource scriptSource) { synchronized (this.scriptClassMonitor) { return (scriptSource.isModified() || this.wasModifiedForTypeCheck); } } @Override public String toString() { return "BshScriptFactory: script source locator [" + this.scriptSourceLocator + "]"; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy