com.adobe.xfa.scripthandler.formcalc.FormCalcScriptHandler 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.formcalc;
import com.adobe.xfa.AppModel;
import com.adobe.xfa.Arg;
import com.adobe.xfa.DependencyTracker;
import com.adobe.xfa.Node;
import com.adobe.xfa.Obj;
import com.adobe.xfa.ScriptDebugger;
import com.adobe.xfa.ScriptHandler;
import com.adobe.xfa.SOMParser;
import com.adobe.xfa.formcalc.CalcException;
import com.adobe.xfa.formcalc.CalcSymbol;
import com.adobe.xfa.formcalc.CalcParser;
import com.adobe.xfa.formcalc.DebugHost;
import com.adobe.xfa.formcalc.Frame;
import com.adobe.xfa.formcalc.FrameTable;
import com.adobe.xfa.formcalc.ProtocolHost;
import com.adobe.xfa.formcalc.ScriptHost;
import com.adobe.xfa.ut.ExFull;
import com.adobe.xfa.ut.MsgFormat;
import com.adobe.xfa.ut.MsgFormatPos;
import com.adobe.xfa.ut.ResId;
import com.adobe.xfa.ut.ResourceLoader;
import com.adobe.xfa.ut.IntegerHolder;
import com.adobe.xfa.ut.StringUtils;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
import java.util.StringTokenizer;
/**
* A class to enable scripting support for the FormCalc language.
*
* @author Darren Burns
*/
public class FormCalcScriptHandler extends ScriptHandler {
/**
* @exclude from published api.
*/
public static class FormCalcParser extends CalcParser implements ScriptHost, ProtocolHost, DebugHost {
public FormCalcParser(AppModel oAppModel, FormCalcScriptHandler oScriptHandler) {
super();
moAppModel = oAppModel;
moScriptHandler = oScriptHandler;
moParser = new CalcParser();
moParser.setScriptHost(this);
//
// Fix for Watson 1100043. There's a need to initialize a
// protocol host at this stage, for otherwise the functions
// Get, Put and Post don't get defined as FormCalc builtin
// functions. A real protocol host will be installed at
// a later stage.
//
moParser.setProtocolHost(this);
moParser.setDebugHost(this);
EnumSet oLegacyScripting = EnumSet.noneOf(CalcParser.LegacyVersion.class);
if (moAppModel.getLegacySetting(AppModel.XFA_LEGACY_V30_SCRIPTING))
oLegacyScripting.add(CalcParser.LegacyVersion.V30_SCRIPTING);
if (moAppModel.getLegacySetting(AppModel.XFA_LEGACY_V32_SCRIPTING))
oLegacyScripting.add(CalcParser.LegacyVersion.V32_SCRIPTING);
if (oLegacyScripting.size() == 0) oLegacyScripting.add(CalcParser.LegacyVersion.CUR_SCRIPTING);
moParser.setLegacyScripting(oLegacyScripting);
}
String execute(String script, String locale, int nScriptID, Arg returnCode, boolean bSyntaxCheckOnly) {
CalcParser oCalcParser = moParser;
//
// Vantive 661756, 662032
// the parser is already in use (and FormCalc is not re-entrant)
// so we need to create a temporaty parser (that is basically a
// clone of one already in use) to use to execute the script.
//
if (moParser.inUse()) {
oCalcParser = (CalcParser) moParser.clone();
}
oCalcParser.putScript(script);
oCalcParser.setScriptID(nScriptID);
if (!StringUtils.isEmpty(locale))
oCalcParser.setLocale(locale);
ScriptDebugger oDebugger = moScriptHandler.getDebugger();
if (oDebugger != null)
oCalcParser.debugEnable(true);
//
// Don't save declarations and code if we're just syntax-checking
//
boolean bSave = ! bSyntaxCheckOnly;
boolean bSuccess = oCalcParser.compile(bSave, bSave, bSyntaxCheckOnly ? true : false);
if (bSuccess && ! bSyntaxCheckOnly) {
if (oDebugger != null)
oDebugger.willExecuteScript(nScriptID);
oCalcParser.evaluate(true, true);
}
CalcSymbol oResult = oCalcParser.getCalcResult();
if (oResult == null)
return ""; // When doing an error-free syntax check.
String sReturnMessage = null;
if (oResult.getType() == CalcSymbol.TypeError) {
IntegerHolder oErrorLine = new IntegerHolder();
IntegerHolder oErrorCode = new IntegerHolder();
String sErr = oResult.getErrorValue(oErrorLine, oErrorCode);
//
// It's been decided that an empty (or all-comment) script
// should return undefined (Arg.EMPTY). This is essentially
// so that users can comment out scripts without generating
// a syntax error.
//
String sNoExpr
= ResourceLoader.loadResource(ResId.FC_ERR_NO_EXPR);
if (sErr.equals(sNoExpr)) {
returnCode.empty();
return sReturnMessage;
}
//
// There's no reason why a scriptException shouldn't be thrown
// regardless of bSyntaxCheckOnly, except that FormCalc won't
// necessarily be very reliable about line numbers in the
// non-syntax-error case. So maintain old behaviour
// until a change is deemed necessary.
//
MsgFormat oFmt = new MsgFormat(ResId.ScriptHandlerError, sErr);
if (bSyntaxCheckOnly)
throw new ScriptHandler.ScriptException(oFmt, oErrorLine.value, FCResIdToErrorCode(oErrorCode.value));
throw new ExFull(oFmt);
}
else if (oResult.getType() == CalcSymbol.TypeReturn) {
//
// Store returned string for a derived class to use if desired.
// This class quietly ignores it.
//
sReturnMessage = oResult.getStringValue();
returnCode.empty();
return sReturnMessage;
}
FCValToXFAArg(oResult, returnCode);
return sReturnMessage;
}
/*
* Overridden from ScriptHost
*/
public Obj getItem(String sItem, Obj[] oObj) {
try {
DependencyTracker oDependencyTracker
= moAppModel.dependencyTracker();
SOMParser oParser = new SOMParser(oDependencyTracker);
List oResultList = new ArrayList();
int resultListLength = 0;
if (oParser.resolve(moAppModel.getContext(), sItem, oObj, oResultList, null))
resultListLength = oResultList.size();
if (resultListLength == 0) {
moScriptHandler.setFatalError(false);
//
// Not handled. Supply an error return value.
// Load "unknown accessor" error message from resources.
//
MsgFormatPos sFmt = new MsgFormatPos(ResId.FC_ERR_ACCESSOR);
sFmt.format(sItem);
CalcSymbol calcsymbol
= new CalcSymbol(sFmt.toString(), true, 0, 0);
throw new CalcException(calcsymbol);
}
Arg arg = oResultList.get(0).value;
return arg.getObject();
} catch (ExFull oError) {
//
// Exception thrown. Convert it into an error return value
//
CalcSymbol calcsymbol
= new CalcSymbol(oError.toString(), true, 0, 0);
throw new CalcException(calcsymbol);
}
}
/*
* Overridden from ScriptHost
*/
public CalcSymbol[] getItemValue(String sItem, Obj[] oObj) {
try {
DependencyTracker oDependencyTracker
= moAppModel.dependencyTracker();
SOMParser oParser = new SOMParser(oDependencyTracker);
List oResultList = new ArrayList();
int resultListLength = 0;
if (oParser.resolve(moAppModel.getContext(), sItem, oObj, oResultList, null))
resultListLength = oResultList.size();
if (resultListLength == 0) {
moScriptHandler.setFatalError(false);
//
// Not handled. Supply an error return value.
// Load "unknown accessor" error message from resources.
//
MsgFormatPos sFmt = new MsgFormatPos(ResId.FC_ERR_ACCESSOR);
sFmt.format(sItem);
CalcSymbol calcsymbol
= new CalcSymbol(sFmt.toString(), true, 0, 0);
throw new CalcException(calcsymbol);
}
CalcSymbol[] oSym = new CalcSymbol[resultListLength];
for (int i = 0; i < resultListLength; i++) {
Obj obj = oResultList.get(i).object;
Arg arg = oResultList.get(i).value;
boolean bNullValue = false;
if (arg.getArgType() == Arg.OBJECT) {
//
// attempt to get the default value ... the default
// value could in turn be another Object, theoretically,
// but the logic to avoid looping endlessly
// is troublesome
//
Obj o = arg.getObject();
bNullValue = ! o.getScriptProperty(arg,
"", oDependencyTracker, true, true);
}
//
// Trace to the debugger if attached
//
ScriptDebugger oDebugger = moScriptHandler.getDebugger();
if (oDebugger != null)
oDebugger.resolvedValue(sItem, arg);
if (arg.getArgType() == Arg.EXCEPTION)
throw arg.getException();
if (bNullValue) {
oSym[i] = new CalcSymbol();
}
else if (arg.getArgType() == Arg.STRING) {
oSym[i] = new CalcSymbol(arg.getString());
}
else if (arg.getArgType() == Arg.DOUBLE) {
oSym[i] = new CalcSymbol(arg.getDouble(false).doubleValue());
}
else if (arg.getArgType() == Arg.INTEGER) {
oSym[i] = new CalcSymbol(arg.getInteger().doubleValue());
}
else if (arg.getArgType() == Arg.BOOL) {
oSym[i] = new CalcSymbol(arg.getBool().booleanValue() ? 1.0 : 0.0);
}
else if (arg.getArgType() == Arg.OBJECT) {
oSym[i] = new CalcSymbol(obj, null);
}
else {
oSym[i] = new CalcSymbol();
}
}
return oSym;
} catch (ExFull oError) {
//
// Exception thrown. Convert it into an error return value
//
CalcSymbol calcsymbol
= new CalcSymbol(oError.toString(), true, 0, 0);
throw new CalcException(calcsymbol);
}
}
/*
* Overridden from ScriptHost
*/
public int putItemValue(String sItem, Obj[] oObj, CalcSymbol oValue) {
try {
String sValue = null;
if (oValue.getType() != CalcSymbol.TypeNull)
sValue = oValue.getStringValue();
Node oNode = moAppModel.getContext();
if ( ! oNode.performSOMAssignment(sItem, sValue, oObj)) {
moScriptHandler.setFatalError(false);
//
// Not handled. Supply an error return value.
// Load "unknown accessor" error message from resources.
//
MsgFormatPos sFmt = new MsgFormatPos(ResId.FC_ERR_ACCESSOR);
sFmt.format(sItem);
CalcSymbol calcsymbol
= new CalcSymbol(sFmt.toString(), true, 0, 0);
throw new CalcException(calcsymbol);
}
return 0;
} catch (ExFull oError) {
//
// Exception thrown. Convert it into an error return value
//
CalcSymbol calcsymbol
= new CalcSymbol(oError.toString(), true, 0, 0);
throw new CalcException(calcsymbol);
}
}
/*
* Overridden from ScriptHost
*/
public int putItem(Obj[] oObj, CalcSymbol oValue) {
return 0; // needs work -- TBD
}
/*
* Overridden from ProtocolHost
*/
public CalcSymbol getUrl(String sUrl) throws CalcException {
MsgFormatPos sFmt = new MsgFormatPos(ResId.PROTOCOL_ERR_SYS);
sFmt.format(sUrl);
CalcSymbol oErr = new CalcSymbol(sFmt.toString(), true, 0, 0);
throw new CalcException(oErr);
}
/*
* Overridden from ProtocolHost
*/
public CalcSymbol putUrl(String sUrl, String sData, String sEnc)
throws CalcException {
MsgFormatPos sFmt = new MsgFormatPos(ResId.PROTOCOL_ERR_SYS);
sFmt.format(sUrl);
CalcSymbol oErr = new CalcSymbol(sFmt.toString(), true, 0, 0);
throw new CalcException(oErr);
}
/*
* Overridden from ProtocolHost
*/
public CalcSymbol postUrl(String sUrl, String sSoapHeader,
String sData, String sContentType, String sEnc)
throws CalcException {
MsgFormatPos sFmt = new MsgFormatPos(ResId.PROTOCOL_ERR_SYS);
sFmt.format(sUrl);
CalcSymbol oErr = new CalcSymbol(sFmt.toString(), true, 0, 0);
throw new CalcException(oErr);
}
/*
* Overridden from DebugHost
*/
public int stopped(int nScriptID, int nLine) {
ScriptDebugger oDebugger = moScriptHandler.getDebugger();
if (oDebugger != null)
oDebugger.stopped(nScriptID, nLine);
return -1;
}
/*
* Overridden from DebugHost
*/
public void poll() {
ScriptDebugger oDebugger = moScriptHandler.getDebugger();
if (oDebugger != null)
oDebugger.poll(moScriptHandler);
}
/*
* Overridden from ScriptHost
*/
public boolean breakPoint(CalcParser oParser, int nScriptID, int nLine, boolean bSet) {
return oParser.moCode.debugBreakPoint(nScriptID, nLine, bSet);
}
/*
* Overridden from ScriptHost
*/
public boolean command(CalcParser oParser, int eCmd) {
return oParser.moCode.debugCommand(oParser, eCmd);
}
/*
* Overridden from ScriptHost
*/
public String getStackTrace(CalcParser oParser) {
return oParser.moFrame.getStackTrace(oParser.mStack);
}
/*
* Overridden from ScriptHost
*/
public void getVariables(CalcParser oParser, List oNames, List oValues) {
List oSymbols = new ArrayList();
oParser.moData.enumerate(oParser.moScope, oSymbols);
//
// Peek at the stack to see if we're in a function.
// If not, ignore parameters.
//
Frame oTopFrame = null;
CalcSymbol oFuncSym = null;
String sFuncPrefix = "";
FrameTable oFrameTable = oParser.moFrame;
if (oFrameTable.getDepth() > 0) {
oTopFrame = oFrameTable.peek();
oFuncSym = oTopFrame.getFuncSym();
sFuncPrefix = oFuncSym.getName();
sFuncPrefix += '`';
}
for (CalcSymbol oSym : oSymbols) {
String sName = oSym.getName();
if (oSym.getType() == CalcSymbol.TypeParameter) {
if (oFuncSym == null)
continue; // not in function
if (! sFuncPrefix.startsWith(sName))
continue; // not a parameter for current function
else
sName = sName.substring(sFuncPrefix.length());
int nStackAddr = oTopFrame.getStackAddr();
int nArgCount = oTopFrame.getArgCount();
int nStackIdx = oSym.getIdxValue();
oSym = oParser.mStack.peek(nStackAddr
- nArgCount + nStackIdx);
}
oNames.add(sName);
oValues.add(oSym);
}
}
/**
* @exclude from published api.
*/
public boolean cancelActionOccured()
{
return moScriptHandler.getCancelOrTimeState();
}
//
// Fix for Watson 1100043. There's no need to overide ProtocolHost
// methods GetUrl(), PutUrl() and PostUrl() herein because the base
// class implementation suffices at this stage.
//
private final CalcParser moParser;
private final AppModel moAppModel;
private final FormCalcScriptHandler moScriptHandler;
}
/**
* Instantiates a script handler for the FormCalc language.
*
* @param oAppModel the application AppModel.
*/
public FormCalcScriptHandler(AppModel oAppModel) {
this(oAppModel, null);
}
/**
* Instantiates a script handler for the FormCalc language.
*
* @param oAppModel the application model.
* @param oScriptDebugger the option script debugger.
*
* @exclude from published api.
*/
public FormCalcScriptHandler(AppModel oAppModel,
ScriptDebugger oScriptDebugger /* = null */) {
super(oScriptDebugger);
moParser = null;
moAppModel = oAppModel;
mbFatalError = true;
}
/**
* @exclude from published api.
*/
public void executeOrSyntaxCheck(String script,
Arg returnCode,
int eReason /* = UNSPECIFIED */,
boolean bSyntaxCheckOnly) {
if (moParser == null)
moParser = new FormCalcParser(moAppModel, this);
//
// Assume fatal error unless told otherwise.
//
mbFatalError = true;
msReturnMessage = "";
int nScriptID = -1;
ScriptDebugger oDebugger = getDebugger();
if (oDebugger != null)
nScriptID = oDebugger.getScriptID(this, script,
moAppModel.getContext(), eReason);
msReturnMessage = moParser.execute(script, null,
nScriptID, returnCode, false);
if (oDebugger != null)
oDebugger.didExecuteScript(nScriptID, returnCode);
}
/**
* @exclude from published api.
*/
public void syntaxCheck(String script) {
if (moParser == null)
moParser = new FormCalcParser(moAppModel, this);
//
// Assume fatal error unless told otherwise.
//
mbFatalError = true;
msReturnMessage = "";
int nScriptID = -1;
Arg returnCode = null; // Not used in this case.
msReturnMessage = moParser.execute(script, "",
nScriptID, returnCode, true);
}
public String languageName() {
return "formcalc";
}
/**
* Method to check for the Esc Key press to halt the execution.
* May be we can extend it to set server side time-out for FormCalc execution.
* @exclude from published api.
*/
public boolean getCancelOrTimeState() {
return false;
}
/**
* @exclude from published api.
*/
public void setOption(String sOptionName, String sOptionValue) {
if (moParser == null)
moParser = new FormCalcParser(moAppModel, this);
if (sOptionName.equals("DupsMode"))
moParser.setDupsMode((sOptionValue.length() >= 1 ? sOptionValue.charAt(0) : 0) == '1');
}
/**
* @exclude from published api.
*/
public String getOption(String sOptionName) {
if (sOptionName.equals("DupsMode") && moParser != null)
return moParser.getDupsMode() ? "1" : "0";
return "";
}
public FormCalcScriptHandler clone() {
FormCalcScriptHandler oNewScriptHandler
= new FormCalcScriptHandler(moAppModel, getDebugger());
oNewScriptHandler.moParser = moParser;
oNewScriptHandler.msReturnMessage = msReturnMessage;
return oNewScriptHandler;
}
/**
* @exclude from published api.
*/
public boolean wasFatalError() {
return mbFatalError;
}
/**
* @exclude from published api.
*/
void setFatalError(boolean bFatal) {
mbFatalError = bFatal;
}
// Debugging support
/**
* @exclude from published api.
*/
public boolean debugCommand(int eCmd) {
switch(eCmd) {
case ScriptHandler.STEP_OVER:
moParser.command(getParser(true), DebugHost.STEP_OVER);
return true;
case ScriptHandler.STEP_INTO:
moParser.command(getParser(true), DebugHost.STEP_INTO);
return true;
case ScriptHandler.STEP_OUT:
moParser.command(getParser(true), DebugHost.STEP_OUT);
return true;
case ScriptHandler.BREAK:
moParser.command(getParser(true), DebugHost.STEP_INTO);
return true;
case ScriptHandler.HALT:
moParser.command(getParser(true), DebugHost.STOP);
return true;
}
return false;
}
/**
* @exclude from published api.
*/
public boolean debugBreakPoint(int nScriptID, int nLine, int eSetType) {
if (eSetType == ScriptHandler.BP_SET
|| eSetType == ScriptHandler.BP_CLEAR)
return moParser.breakPoint(getParser(true), nScriptID,
nLine, eSetType == ScriptHandler.BP_SET);
return false;
}
/**
* @exclude from published api.
*/
public boolean debugGetStack(List oStack) {
oStack.clear();
String sStackTrace = moParser.getStackTrace(getParser(true));
StringTokenizer sToke = new StringTokenizer(sStackTrace, "\n");
while (sToke.hasMoreTokens()) {
String sEntry = sToke.nextToken();
oStack.add(sEntry);
}
return true;
}
/**
* @exclude from published api.
*/
public boolean debugGetVariables(List oVarNames, List oVarValues) {
oVarNames.clear();
oVarValues.clear();
List oCalcSymbols = new ArrayList();
moParser.getVariables(getParser(true), oVarNames, oCalcSymbols);
for (int i = 0; i < oVarNames.size(); i++) {
Arg oArg = new Arg();
FCValToXFAArg(oCalcSymbols.get(i), oArg);
oVarValues.add(oArg);
}
return true;
}
/**
* @exclude from published api.
*/
protected int debugFeatures() {
int nFeatures =
ScriptHandler.FEATURE_CAN_SET_BREAKPOINT |
ScriptHandler.FEATURE_CAN_STEP_OVER |
ScriptHandler.FEATURE_CAN_STEP_INTO |
ScriptHandler.FEATURE_CAN_STEP_OUT;
return nFeatures;
}
/*
* ArgToFCVal existed but was unused as of rev 34 of this file,
* in case we ever need to retrieve it...
*/
static void FCValToXFAArg(CalcSymbol oFCVal, Arg oArgVal) {
switch (oFCVal.getType()) {
case CalcSymbol.TypeDouble:
oArgVal.setDouble(new Double(oFCVal.getNumericValue()));
break;
case CalcSymbol.TypeReference:
oArgVal.setObject(oFCVal.getObjValue());
break;
case CalcSymbol.TypeVariable:
case CalcSymbol.TypeString:
oArgVal.setString(oFCVal.getStringValue());
break;
case CalcSymbol.TypeNull:
oArgVal.setNull();
break;
default:
oArgVal.empty();
// TBD -- failure
break;
}
}
/*
* Map FormCalc resource IDs to common error codes. This is only
* intended to handle those that may occur during syntax checking,
* not execution.
*/
static int FCResIdToErrorCode(int nErrorResId) {
if (nErrorResId == ResId.FC_ERR_SYNTAX)
return ScriptHandler.ERR_Syntax;
else if (nErrorResId == ResId.FC_ERR_LOOP)
return ScriptHandler.ERR_BadBreakContinue;
else if (nErrorResId == ResId.FC_ERR_FUNC_USED)
return ScriptHandler.ERR_FuncBuiltIn;
else if (nErrorResId == ResId.FC_ERR_FUNC_UNKN)
return ScriptHandler.ERR_FuncUnknown;
//
// Not a serious problem, but a new case should be handled if we
// hit this assert. Default to a syntax error.
//
// Javaport: asserts in Java are a problem.
// assert(false);
return ScriptHandler.ERR_Syntax;
}
/**
* If the script does a return("foo"), then the returnCode from
* execute will be Arg.EMPTY, and
* getReturnMessage() will return "foo". Otherwise getReturnMessage()
* returns an empty string.
*
* @exclude from published api.
*/
protected String getReturnMessage() {
return msReturnMessage;
}
/**
* Provides access to the FormCalc Parser for derived classes.
* If bForceCreation is false, the
* return value may be null if execute() has not been called
* (the parser is normally only
* instantiated on the first call to execute()). If bForceCreation
* is true, the parser will be created and returned.
*
* @exclude from published api.
*/
protected CalcParser getParser(boolean bForceCreation) {
if (moParser == null) {
if (bForceCreation)
moParser = new FormCalcParser(moAppModel, this);
else
return null;
}
return moParser;
}
private String msReturnMessage;
private FormCalcParser moParser;
private final AppModel moAppModel;
private boolean mbFatalError;
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy