/*
* Copyright (c) 2006 Stiftung Deutsches Elektronen-Synchroton,
* Member of the Helmholtz Association, (DESY), HAMBURG, GERMANY.
*
* THIS SOFTWARE IS PROVIDED UNDER THIS LICENSE ON AN "../AS IS" BASIS.
* WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR PARTICULAR PURPOSE AND
* NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
* FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
* THE USE OR OTHER DEALINGS IN THE SOFTWARE. SHOULD THE SOFTWARE PROVE DEFECTIVE
* IN ANY RESPECT, THE USER ASSUMES THE COST OF ANY NECESSARY SERVICING, REPAIR OR
* CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE.
* NO USE OF ANY SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
* DESY HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
* OR MODIFICATIONS.
* THE FULL LICENSE SPECIFYING FOR THE SOFTWARE THE REDISTRIBUTION, MODIFICATION,
* USAGE AND OTHER RIGHTS AND OBLIGATIONS IS INCLUDED WITH THE DISTRIBUTION OF THIS
* PROJECT IN THE FILE LICENSE.HTML. IF THE LICENSE IS NOT INCLUDED YOU MAY FIND A COPY
* AT HTTP://WWW.DESY.DE/LEGAL/LICENSE.HTM
*/
package org.csstudio.sds.ui.scripting;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import org.csstudio.sds.internal.rules.LogicException;
import org.csstudio.sds.model.IScript;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.ContextAction;
import org.mozilla.javascript.Function;
import org.mozilla.javascript.ImporterTopLevel;
import org.mozilla.javascript.Scriptable;
/**
* This calls describes a script, which can be executed by a Timer-widget.
* @author Kai Meyer
*
*/
public final class RunnableScript implements IScript {
/**
* The name of the script function that will be executed.
*/
private static final String SCRIPT_LOGIC_FUNCTION_NAME = "execute"; //$NON-NLS-1$
/**
* The name of the script field that contains the textual description of the
* script.
*/
private static final String SCRIPT_DESCRIPTION = "description"; //$NON-NLS-1$
/**
* A textual description of this rule.
*/
private String _description;
/**
* The script function that will be executed.
*/
private Function _scriptFunction;
/**
* The scripting scope.
*/
private Scriptable _scriptScope;
/**
* Constructor.
* @param name The name of the script.
* @param scriptFileInputStream The {@link InputStream} for the script
* @throws LogicException Thrown if an error occurs during parsing the script
*/
public RunnableScript(final String name, final InputStream scriptFileInputStream)
throws LogicException {
_description = null;
try {
Context scriptContext = Context.enter();
scriptContext.setApplicationClassLoader(RunnableScript.class.getClassLoader());
_scriptScope = new ImporterTopLevel(scriptContext);
_scriptFunction = parseScriptFile(scriptFileInputStream,
scriptContext);
} catch (Exception e) {
throw new LogicException(
"Script " + name + ": Error parsing script", e); //$NON-NLS-1$ //$NON-NLS-2$
} finally {
Context.exit();
}
if (_scriptFunction == null) {
throw new LogicException(
"Script " + name + ": " + SCRIPT_LOGIC_FUNCTION_NAME + " is undefined!"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
if (_description == null) {
throw new LogicException("Script " + name //$NON-NLS-1$
+ ": No textual description was defined!"); //$NON-NLS-1$
}
}
/**
* Parse the given script file and try to allocate the "doLogic" function.
*
* @param scriptFileInputStream
* The input stream that contains the script
* @param scriptContext
* The script context that is used to initially parse the script
* file.
* @return The "doLogic" function or null if it is not defined within the
* given script.
* @throws IOException
* If an IO error occurs while the script file is parsed.
*/
private Function parseScriptFile(final InputStream scriptFileInputStream,
final Context scriptContext) throws IOException {
Function result = null;
String scriptString = ""; //$NON-NLS-1$
BufferedReader reader = new BufferedReader(new InputStreamReader(
scriptFileInputStream));
while (reader.ready()) {
scriptString += reader.readLine();
}
reader.close();
// Evaluate the script string. Ignore the result. This is needed to
// allocate the proper function object.
scriptContext.evaluateString(_scriptScope, scriptString,
"script file", 1, null); //$NON-NLS-1$
_description = fetchTextualDescription();
// Try to allocate the function object.
Object functionObject = _scriptScope.get(SCRIPT_LOGIC_FUNCTION_NAME,
_scriptScope);
if (functionObject instanceof Function) {
result = (Function) functionObject;
}
return result;
}
/**
* Try to fetch the textual description from the script.
* @return The textual description for the script
*/
private String fetchTextualDescription() {
String result = "";
Object descriptionObject = _scriptScope.get(SCRIPT_DESCRIPTION,
_scriptScope);
if (descriptionObject != Scriptable.NOT_FOUND) {
result = Context.toString(descriptionObject);
}
return result;
}
/**
* {@inheritDoc}
*/
@Override
public void execute() {
Context.call(new ContextAction() {
/**
* {@inheritDoc}
*/
@Override
public Object run(final Context cx) {
_scriptFunction.call(cx, _scriptScope,
_scriptScope, new Object[] {});
return null;
}
});
}
}