com.adobe.xfa.scripthandler.rhino.RhinoScriptHandler Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of aem-sdk-api Show documentation
Show all versions of aem-sdk-api Show documentation
The Adobe Experience Manager SDK
/*
* ADOBE CONFIDENTIAL
*
* Copyright 2007 Adobe Systems Incorporated All Rights Reserved.
*
* NOTICE: All information contained herein is, and remains the property of
* Adobe Systems Incorporated and its suppliers, if any. The intellectual and
* technical concepts contained herein are proprietary to Adobe Systems
* Incorporated and its suppliers and may be covered by U.S. and Foreign
* Patents, patents in process, and are protected by trade secret or copyright
* law. Dissemination of this information or reproduction of this material
* is strictly forbidden unless prior written permission is obtained from
* Adobe Systems Incorporated.
*/
package com.adobe.xfa.scripthandler.rhino;
import java.util.IdentityHashMap;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.JavaScriptException;
import org.mozilla.javascript.EvaluatorException;
import org.mozilla.javascript.RhinoException;
import org.mozilla.javascript.Script;
import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.Undefined;
import org.mozilla.javascript.WrappedException;
import com.adobe.xfa.AppModel;
import com.adobe.xfa.Arg;
import com.adobe.xfa.Element;
import com.adobe.xfa.Obj;
import com.adobe.xfa.ScriptDebugger;
import com.adobe.xfa.ScriptHandler;
import com.adobe.xfa.TextNode;
import com.adobe.xfa.XFA;
import com.adobe.xfa.ut.ExFull;
import com.adobe.xfa.ut.FindBugsSuppress;
import com.adobe.xfa.ut.MsgFormat;
import com.adobe.xfa.ut.ResId;
/**
* A class to enable scripting support for the JavaScript language.
*
* @author mtardif
*/
public class RhinoScriptHandler extends ScriptHandler implements ScriptHandlerIF {
/**
* Instantiates a JavaScript script handler.
* The no-argument ctor ensures that a script host
* is initialized.
*
* @exclude from published api.
*/
protected RhinoScriptHandler() {
mScriptHost = this;
mAppModel = null;
mAppModelLiveObject = null;
mObjectMap = new IdentityHashMap();
}
/**
* Instantiates a JavaScript script handler.
* @param appModel the application model.
*/
public RhinoScriptHandler(AppModel appModel) {
this(appModel, null);
}
/**
* Instantiates a JavaScript script handler.
* @param appModel an application model.
* @param scriptDebugger an script debugger.
*
* @exclude from published api.
*/
public RhinoScriptHandler(AppModel appModel, ScriptDebugger scriptDebugger /* = null */) {
this(appModel, null, 0);
}
/**
* @param appModel the application's XFAAppModel.
* @param scriptDebugger the application's XFAScriptDebugger-derived class.
* @param javaScriptTimeout the maximum amount of time, in milliseconds, a
* single script is allowed to execute before it gets timed out.
* A value of '0' means infinite which also is the default.
*/
public RhinoScriptHandler(AppModel appModel,
ScriptDebugger scriptDebugger /* = null */,
int javaScriptTimeout /* = 0 */) {
super(scriptDebugger);
mAppModel = appModel;
mScriptHost = this;
mJavaScriptTimeout = javaScriptTimeout;
// Don't want a negative value for the timeout
if (mJavaScriptTimeout < 0)
mJavaScriptTimeout = 0;
LiveComponent oLiveComponent = mScriptHost.newLiveComponent(this, mAppModel);
//
// Add this live component to the global scope.
//
RhinoEngine.setTopLevelScope(oLiveComponent);
//
// Set the value of the "xfa" object.
//
mAppModelLiveObject = mScriptHost.newLiveObject(this, mAppModel);
mObjectMap = new IdentityHashMap();
}
/**
* Instantiates a JavaScript script handler form the given.
* @param appModel an application model.
* @param scriptHost a Rhino script host.
* @param liveObject a live object.
* @param scriptDebugger an script debugger.
* @param objectMap an object map.
*
* @exclude from published api.
*/
protected RhinoScriptHandler(AppModel appModel, RhinoScriptHandler scriptHost, LiveObject liveObject, ScriptDebugger scriptDebugger /* = null */, IdentityHashMap objectMap) {
this(appModel, scriptHost, liveObject, scriptDebugger, 0, objectMap);
}
/**
* Instantiates a JavaScript script handler form the given.
* @param appModel an application model.
* @param scriptHost a Rhino script host.
* @param liveObject a live object.
* @param scriptDebugger an script debugger.
* @param javaScriptTimeout the maximum amount of time, in milliseconds, a
* single script is allowed to exeucte before it gets timed out.
* @param objectMap an object map.
*
* @exclude from published api.
*/
protected RhinoScriptHandler(AppModel appModel,
RhinoScriptHandler scriptHost,
LiveObject liveObject,
ScriptDebugger scriptDebugger /* = null */,
int javaScriptTimeout /* = 0 */,
IdentityHashMap objectMap) {
super(scriptDebugger);
mAppModel = appModel;
mScriptHost = scriptHost;
mJavaScriptTimeout = javaScriptTimeout;
// Don't want a negative value for the timeout
if (mJavaScriptTimeout < 0)
mJavaScriptTimeout = 0;
mAppModelLiveObject = liveObject;
mObjectMap = objectMap;
}
/**
* Clones this JavaScript handler.
*
* @exclude from published api.
*/
public RhinoScriptHandler clone() {
RhinoScriptHandler oNewScriptHandler
= new RhinoScriptHandler(mAppModel, mScriptHost, mAppModelLiveObject, getDebugger(), mObjectMap);
// oNewScriptHandler.mbFatalError = mbFatalError;
oNewScriptHandler.mError = mError;
return oNewScriptHandler;
}
public LiveObject newLiveObject(RhinoScriptHandler handler, Obj xfaObject) {
return new LiveObject(handler, xfaObject);
}
public LiveComponent newLiveComponent(RhinoScriptHandler handler, Obj xfaObject) {
return new LiveComponent(handler, xfaObject);
}
/**
* @exclude from published api.
*/
@FindBugsSuppress(code="RCN") // oDebugger
public void executeOrSyntaxCheck(String sScript, Arg oReturnCode, int eReason, boolean bSyntaxCheckOnly) {
clearError();
int nScriptID = -1;
ScriptDebugger oDebugger = getDebugger();
if (oDebugger != null) {
// Javaport: not needed.
// nScriptID = oDebugger.getScriptID(this, sScript, moAppModel.getContext(), eReason);
// if (moRhinoDebugger == null) {
// moRhinoDebugger = moEngine.getContext().getDebugger();
// moEngine.getContext().setDebugger(moRhinoDebugger, oDebugger);
// }
assert(false);
}
//
// Set the context for the script to be the current XFANode.
//
String oScriptID = "";
if (oDebugger != null) {
//
// Form a string "#n" where n is the script ID. This
// can be parsed back out in break-point callbacks.
//
oScriptID = "#" + nScriptID;
}
Script oScript = null;
try {
oScript = RhinoEngine.getThreadLocalRuntimeContext().compileString(sScript, oScriptID, 1, null);
} catch (RhinoException oError) {
setError(oError);
}
boolean bSuccess = (oScript != null);
if (oScript != null) {
if ( ! bSyntaxCheckOnly) {
if (oDebugger != null) {
// Javaport: not needed.
// moEsDebugger->addScript(nScriptID, oScript);
// oDebugger->willExecuteScript(nScriptID);
// bSuccess = mpEngine->eval(*poScript, &oResult, -1, ScScript::Engine::kEvalBreakOnEntry, poThis);
// // Allow script to be thrown away if it contains no function declarations. We check for 2 because
// // we have a reference in poScript (about to be released, below), and there's one in mpoEsDebugger's
// // map. If there's a function declaration, then the ExtendScript engine holds onto a reference
// // in case someone debugs into it, in which case the ref-count is 3.
// if (poScript->getRefCount() == 2)
// mpoEsDebugger->clearScript(nScriptID, poScript);
assert(false);
}
else {
bSuccess = false;
try {
//
// Javaport: the Rhino API says this must be the top level
// scope, and not the context object, contrary to C++!
//
Context ctx = RhinoEngine.getThreadLocalRuntimeContext();
Scriptable topScope = RhinoEngine.getTopLevelScope();
Object oResult = oScript.exec(ctx, topScope);
if (! (oResult instanceof Undefined)) {
oReturnCode.assign(variantToArg(oResult));
bSuccess = true;
}
} catch (RhinoException f) {
setError(f);
} catch (ExFull g) {
setError(g);
}
}
}
}
if (! bSuccess) {
Exception error = getError();
String sErrorText = null;
//
// Watson 1252722: a comment-only script causes bSuccess to be false, but
// there's no associated error message. Workaround is to double-check here
// that error.getCode() != ScCore::kErrOK.
//
if (error instanceof JavaScriptException) {
StringBuilder sError = new StringBuilder(((JavaScriptException) error).getMessage());
sErrorText = sError.toString();
}
else if (error instanceof WrappedException) {
StringBuilder sError = new StringBuilder(((WrappedException) error).getMessage());
final String sRhinoPrefix = "Wrapped ";
int nErrorPrefix = sError.indexOf(sRhinoPrefix);
if (nErrorPrefix >= 0)
sError.replace(0, nErrorPrefix + sRhinoPrefix.length(), "");
final String sRhinoSuffix = "\n (#";
int nLineNumberSuffix = sError.indexOf(sRhinoSuffix);
if (nLineNumberSuffix >= 0)
sError.delete(nLineNumberSuffix + 1, sError.length());
if (sError.charAt(sError.length() - 1) == '\n')
sError.setLength(sError.length() - 1);
sErrorText = sError.toString();
}
else if (error instanceof RhinoException) {
StringBuilder sError = new StringBuilder(((RhinoException) error).getMessage());
final String sRhinoPrefix = "Error: ";
int nErrorPrefix = sError.indexOf(sRhinoPrefix);
if (nErrorPrefix >= 0)
sError.delete(0, nErrorPrefix + sRhinoPrefix.length());
sErrorText = sError.toString();
int nErrorLine = ((RhinoException) error).lineNumber();
//
// There's no reason why a scriptException shouldn't be thrown regardless
// of bSyntaxCheckOnly, except that FormCalc won't necessarily be as reliable
// about line numbers in the non-syntax-error case. So for consistency keep
// that behaviour.
//
if (bSyntaxCheckOnly) {
MsgFormat oFmt = new MsgFormat(ResId.ScriptHandlerError, sErrorText);
ScriptException oScriptEx = new ScriptException(oFmt, nErrorLine, RhinoErrorIdToErrorCode(0));
throw oScriptEx;
}
}
else if (error instanceof ExFull) {
sErrorText = error.toString();
}
if (sErrorText != null) {
Arg arg = variantToArg(sErrorText);
oReturnCode.assign(arg);
throw new ExFull(new MsgFormat(ResId.ScriptHandlerError, sErrorText));
}
}
if (bSyntaxCheckOnly)
return; // Compiled successfully
if (oDebugger != null) {
// Javaport: not needed.
// oDebugger.didExecuteScript(nScriptID, oReturnCode);
assert(false);
}
}
/**
* @exclude from published api.
*/
public AppModel getAppModel() {
return mAppModel;
}
/**
* @exclude from published api.
*/
protected RhinoScriptHandler getScriptHost() {
return mScriptHost;
}
/**
* @exclude from published api.
*/
protected IdentityHashMap getObjectMap() {
return mObjectMap;
}
/**
* @exclude from published api.
*/
protected LiveObject getAppModelLiveObject() {
return mAppModelLiveObject;
}
public String languageName() {
return "javascript";
}
/**
* @exclude from published api.
*/
public void throwError(ExFull oError) {
StringBuilder sErrorBuf = new StringBuilder(oError.toString());
int nLen = sErrorBuf.length();
while (sErrorBuf.charAt(nLen - 1) == '\n')
nLen--;
sErrorBuf.setLength(nLen);
RhinoEngine.throwException(sErrorBuf.toString());
}
/**
* @exclude from published api.
*/
public boolean wasFatalError() {
//return mbFatalError;
return false;
}
/**
* Deletes any accumulated script execution contexts.
*
* @exclude from published api.
*/
protected void clearExecutionContexts() {
mObjectMap.clear();
RhinoEngine.destroy();
}
// JavaPort: not needed in Rhino.
// public String getOption(String sOptionName) {
// }
//
// public void setOption(String sOptionName, String sOptionValue) {
// }
void clearError() {
setError(null);
}
Exception getError() {
return mError;
}
void setError(Exception error) {
mError = error;
}
// JavaPort: not needed for XFA4J.
// public ScriptDebugger getDebugger() {
// }
//
// public boolean debugCommand(int eCmd) {
// }
//
// public boolean debugBreakPoint(int nScriptID, int nLine, int eSetType) {
// }
//
// public boolean debugGetStack(Storage oStack) {
// }
//
// public boolean debugGetVariables(Storage oVarNames, Storage oVarValues) {
// }
//
// public void setDebugger(ScriptDebugger poDebugger) {
// }
//
// public void removeReference(Node oNode) {
// }
private final RhinoScriptHandler mScriptHost;
private final AppModel mAppModel;
private final LiveObject mAppModelLiveObject;
// private boolean mbFatalError;
private Exception mError;
private int mJavaScriptTimeout; // for futures.
private final IdentityHashMap mObjectMap; // List of scripted XFA objects.
// JavaPort: not needed for XFA4J.
// private Debugger moRhinoDebugger;
LiveObject ObjectToLiveObject(Obj object) {
LiveObject liveObject = lookupObject(object);
if (liveObject == null) {
//
// not found; create a new entry
//
liveObject = mScriptHost.newLiveObject(this, object);
addObject(object, liveObject);
}
return liveObject;
}
LiveObject lookupObject(Obj object) {
//
// Special handling to make sure we don't add a circular dependency.
//
if (object == mAppModel) {
return mAppModelLiveObject;
}
return mObjectMap.get(object);
}
void addObject(Obj object, LiveObject liveObject) {
// Make sure we don't add a circular dependency.
assert(object != mAppModel);
mObjectMap.put(object, liveObject);
//
// check if it is a script element
//
if (object.isSameClass(XFA.SCRIPTTAG)) {
Element oNode = (Element) object;
Element oParent = oNode.getXFAParent();
if (oParent != null && oParent.isSameClass(XFA.VARIABLESTAG)) {
TextNode oText = (TextNode) oNode.getProperty(XFA.TEXTNODETAG, 0);
if (oText != null) {
String sScript = oText.getValue();
compileObject(object, sScript);
}
}
}
}
boolean compileObject(Obj object, String sScript) {
clearError();
Script oScript = null;
Context ctx = RhinoEngine.getThreadLocalRuntimeContext();
int nLevel = ctx.getOptimizationLevel();
try {
ctx.setOptimizationLevel(-1);
oScript = ctx.compileString(sScript, null, 1, null);
} catch (RhinoException oError) {
setError(oError);
} finally {
ctx.setOptimizationLevel(nLevel);
}
boolean bSuccess = (oScript != null);
boolean bRet = false;
if (bSuccess) {
LiveObject liveObject = lookupObject(object);
//
// create our script object.
//
ScriptObject oScriptObj = new ScriptObject(oScript);
//
// Set the live object's script object.
//
liveObject.setScriptObject(oScriptObj);
bRet = true;
}
else {
String sError = "";
Exception error = getError();
if (error instanceof RhinoException) {
sError = ((RhinoException) error).getMessage();
}
throw new ExFull(new MsgFormat(ResId.ScriptHandlerError, sError));
}
return bRet;
}
public Object argToVariant(Arg arg) {
Object variant = null;
switch (arg.getArgType()) {
case Arg.EMPTY:
variant = Undefined.instance;
break;
case Arg.NULL:
variant = null;
break;
case Arg.BOOL:
variant = Boolean.valueOf(arg.getBool().booleanValue());
break;
case Arg.INTEGER:
variant = Integer.valueOf(arg.getInteger().intValue());
break;
case Arg.DOUBLE:
variant = new Double(arg.getDouble(false).doubleValue());
break;
case Arg.STRING:
variant = arg.getString();
break;
case Arg.OBJECT:
Obj oObj = arg.getObject();
if (oObj == null) {
variant = null;
break;
}
LiveObject oXFALiveObject = (LiveObject) ObjectToLiveObject(oObj);
variant = oXFALiveObject;
break;
case Arg.EXCEPTION:
throw new EvaluatorException(arg.getException().toString());
default:
assert(false);
break;
}
return variant;
}
public Arg variantToArg(Object variant) {
Arg arg = new Arg();
if (variant == null)
arg.setNull();
else if (variant instanceof Undefined)
arg.empty();
else if (variant instanceof Boolean)
arg.setBool(Boolean.valueOf(((Boolean) variant).booleanValue()));
else if (variant instanceof Integer)
arg.setInteger(Integer.valueOf(((Integer) variant).intValue()));
else if (variant instanceof Double)
arg.setDouble(new Double(((Double) variant).doubleValue()));
else if (variant instanceof String)
arg.setString((String) variant);
else if (variant instanceof LiveObject)
arg.setObject(((LiveObject) variant).getXFAObject());
else
arg.setVoid(variant);
return arg;
}
/*
* Map ExtendScript error codes to the common error codes. This is only
* intended to handle those that may occur during syntax checking, not execution.
*/
static int RhinoErrorIdToErrorCode(int nErrorCode) {
// Javaport: there's no such thing in Rhino.
// switch (nErrorCode) {
// case ScCore::kErrGeneral:
// return ScriptHandler.ERR_General;
// case ScCore::kErrUndefined:
// return ScriptHandler.ERR_Undefined;
// case ScCore::kErrNoLvalue:
// return ScriptHandler.ERR_NoLvalue;
// case ScCore::kErrOpenString:
// return ScriptHandler.ERR_OpenString;
// case ScCore::kErrOpenComment:
// return ScriptHandler.ERR_OpenComment;
// case ScCore::kErrBadDigit:
// return ScriptHandler.ERR_BadDigit;
// case ScCore::kErrUnsupported:
// return ScriptHandler.ERR_Unsupported;
// case ScCore::kErrSyntax:
// return ScriptHandler.ERR_Syntax;
// case ScCore::kErrKeyword:
// return ScriptHandler.ERR_Keyword;
// case ScCore::kErrBadBreakContinue:
// return ScriptHandler.ERR_BadBreakContinue;
// case ScCore::kErrBadLabel:
// return ScriptHandler.ERR_BadLabel;
// case ScCore::kErrExpressionNotConst:
// return ScriptHandler.ERR_ExpressionNotConst;
// case ScCore::kErrClosedBlock:
// return ScriptHandler.ERR_ClosedBlock;
// case ScCore::kErrOpenBlock:
// return ScriptHandler.ERR_OpenBlock;
// case ScCore::kErrNoCatch:
// return ScriptHandler.ERR_NoCatch;
// case ScCore::kErrNoTry:
// return ScriptHandler.ERR_NoTry;
// case ScCore::kErrVarExpected:
// return ScriptHandler.ERR_VarExpected;
// case ScCore::kErrScalarExpected:
// return ScriptHandler.ERR_ScalarExpected;
// case ScCore::kErrBadArgument:
// return ScriptHandler.ERR_BadArgument;
// case ScCore::kErrBadArgumentList:
// return ScriptHandler.ERR_BadArgumentList;
// case ScCore::kErrObjectExpected:
// return ScriptHandler.ERR_ObjectExpected;
// case ScCore::kErrNoCtor:
// return ScriptHandler.ERR_NoCtor;
// case ScCore::kErrNoValue:
// return ScriptHandler.ERR_NoValue;
// case ScCore::kErrNoFunction:
// return ScriptHandler.ERR_NoFunction;
// case ScCore::kErrExpected:
// return ScriptHandler.ERR_Expected;
// case ScCore::kErrWrongClass:
// return ScriptHandler.ERR_WrongClass;
// case ScCore::kErrBadReturn:
// return ScriptHandler.ERR_BadReturn;
// case ScCore::kErrCharConversion:
// return ScriptHandler.ERR_CharConversion;
// case ScCore::kErrCharPartial:
// return ScriptHandler.ERR_CharPartial;
// case ScCore::kErrDuplicateDefault:
// return ScriptHandler.ERR_DuplicateDefault;
// case ScCore::kErrRedeclared:
// return ScriptHandler.ERR_Redeclared;
// case ScCore::kErrRange:
// return ScriptHandler.ERR_Range;
// case ScCore::kErrCatchAfterCatch:
// return ScriptHandler.ERR_CatchAfterCatch;
// }
// //
// // Not a serious problem, but a new case should be handled if we
// // hit this assert. Default to a syntax error.
// //
// assert(false);
return ScriptHandler.ERR_Syntax;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy