com.adobe.xfa.form.CalculateDispatcher 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
The newest version!
/*
* ADOBE CONFIDENTIAL
*
* Copyright 2005 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.form;
import com.adobe.xfa.AppModel;
import com.adobe.xfa.Arg;
import com.adobe.xfa.Attribute;
import com.adobe.xfa.Element;
import com.adobe.xfa.EnumAttr;
import com.adobe.xfa.EventManager;
import com.adobe.xfa.Int;
import com.adobe.xfa.Node;
import com.adobe.xfa.ProtoableNode;
import com.adobe.xfa.Schema;
import com.adobe.xfa.ScriptHandler;
import com.adobe.xfa.XFA;
import com.adobe.xfa.template.TemplateModel;
import com.adobe.xfa.template.containers.Container;
import com.adobe.xfa.ut.ExFull;
import com.adobe.xfa.ut.MsgFormatPos;
import com.adobe.xfa.ut.Numeric;
import com.adobe.xfa.ut.Peer;
import com.adobe.xfa.ut.ResId;
import com.adobe.xfa.ut.StringUtils;
/**
* @exclude from public api.
*/
class CalculateDispatcher extends com.adobe.xfa.ScriptDispatcher {
private final int meRunAt;
CalculateDispatcher(Element scriptContextNode,
String sEventContext,
int nEventID,
EventManager eventManager,
String sScript,
String sContentType,
int eRunAt) {
super(scriptContextNode,
sEventContext,
nEventID,
eventManager,
sScript,
sContentType);
meRunAt = eRunAt;
}
public void dispatch() {
Element node = getActionContextNode();
if (node == null)
return;
String sScript = getScript();
String sContentType = getContentType();
assert(node instanceof FormField ||
node instanceof FormSubform ||
node instanceof FormExclGroup);
// note would be nice to directly access mpoNodeImpl.mpModel
FormModel formModel = (FormModel) node.getModel();
if (formModel.isActivityExcluded("calculate"))
return;
// As of //https://zerowing.corp.adobe.com/display/xtg/InactivePresenceXFAProposal,
// event processing associated with inactive containers must not occur.
// To mitigate performance on older forms, only do this check for XFA 3.0 documents and higher.
AppModel appModel = node.getAppModel();
if (appModel != null) {
TemplateModel templateModel = TemplateModel.getTemplateModel(appModel, false);
if ((templateModel != null) &&
(templateModel.getOriginalXFAVersion() >= Schema.XFAVERSION_30) &&
(node instanceof Container)) {
Container container = (Container)node;
int ePresence = container.getRuntimePresence(EnumAttr.UNDEFINED);
if (EnumAttr.PRESENCE_INACTIVE == ePresence)
return;
}
}
int eModelRunAtSetting = formModel.getRunScripts();
int eRunAt = getRunAt();
// ensure we can run the script
if (eModelRunAtSetting == EnumAttr.RUNSCRIPTS_NONE)
return;
else if (eModelRunAtSetting == EnumAttr.RUNSCRIPTS_SERVER && eRunAt == EnumAttr.RUNAT_CLIENT)
return;
else if (eModelRunAtSetting == EnumAttr.RUNSCRIPTS_CLIENT && eRunAt == EnumAttr.RUNAT_SERVER)
return;
int nNumErrorsBefore = formModel.getErrorList().size();
// remove old Dependencies
formModel.removeDependency(node, true);
FormDependencyTracker tracker = new FormDependencyTracker(node, true);
try {
Arg returnCode = new Arg();
boolean bCalcEnabled = formModel.getCalculationsEnabled();
if (bCalcEnabled && node instanceof FormField) {
FormField field = (FormField)node;
// check for override setting on the value node.
// if set to true don't run the script
Element value = field.getElement(XFA.VALUETAG, true, 0, false, false);
if (value != null && value.getEnum(XFA.OVERRIDETAG) == EnumAttr.BOOL_TRUE) {
// watson bug 1440694 old 7.0 forms don't respect the override attribute,
// must continue to respect this
if (!node.getAppModel().getLegacySetting(AppModel.XFA_LEGACY_CALCOVERRIDE))
return;
}
returnCode = field.evaluate(sScript, sContentType, ScriptHandler.CALCULATE, true);
String sReturnValue = null;
if ((Arg.EXCEPTION != returnCode.getArgType()) &&
(Arg.EMPTY != returnCode.getArgType())) {
if (Arg.NULL != returnCode.getArgType())
sReturnValue = returnCode.getAsString(false);
// watson 1776934: Do not detect permissions violations for calculations unless the
// calculation is modifying the existing value.
String sRawValueOld = field.getRawValue();
//Bug#3018085
boolean doContinueSettingNewRawValue=true;
{
// get the value
Element pValueNode = field.getElement(XFA.VALUETAG, true, 0, false, false);
// get the value's content
if (pValueNode != null) {
Node pContentNode = pValueNode.getOneOfChild();
//Continue only if content is of type Decimal OR Float
if (pContentNode != null && (pContentNode.isSameClass(XFA.DECIMALTAG) || pContentNode.isSameClass(XFA.FLOATTAG))) {
//Verify that both the old and new values are of double type and comparable
if (!StringUtils.isEmpty(sReturnValue) && !StringUtils.isEmpty(sRawValueOld)){
double dReturnValue = Numeric.stringToDouble(sReturnValue, true);
double dRawValueOld = Numeric.stringToDouble(sRawValueOld, true);
//If both values are comparable and equal by applying double semantics (IEEE-754 1985)
//then just consider these values as equivalent and skip setting rawValue and avoid triggering peer notifications
if (!Double.isInfinite(dReturnValue) && !Double.isNaN(dReturnValue) &&
!Double.isInfinite(dRawValueOld) && !Double.isNaN(dRawValueOld)){
//fracDigits exist only in case of DecimalValue.
//Assume it to be 8 (in case of FloatValue it is hardcoded to 8 (ref FloatValue.class))
int fracDigits = 8;
if (pContentNode.isSameClass(XFA.DECIMALTAG)){
Attribute fracDigitAttr = ((Element)pContentNode).getAttribute(XFA.FRACDIGITSTAG);
//fracDigitAttr can't be null for DecimalValue. No need to check for null value.
fracDigits = ((Int)fracDigitAttr).getValue();
}
String sReturnValueNormalized = Numeric.doubleToStringUsingBigDecimal(dReturnValue, fracDigits, false);
String sRawValueOldNormalized = Numeric.doubleToStringUsingBigDecimal(dRawValueOld, fracDigits, false);
doContinueSettingNewRawValue = !sReturnValueNormalized.equals(sRawValueOldNormalized);
}
}
}
}
}
if (doContinueSettingNewRawValue && sReturnValue != null && ! sReturnValue.equals(sRawValueOld)) {
field.setRawValue(sReturnValue);
String sRawValueNew = field.getRawValue();
// bug 1816666 (cover cases like 24.2499 != 24.25, in sReturnValue check
// above, though setRawVal/getRawVal treat it that way)
// added another condition for that below apart from check permissions
// more details in bug notes / review notes (reviewid=224101)
// check permissions
if ((null!=sRawValueNew || null!=sRawValueOld) && (null==sRawValueNew || ! sRawValueNew.equals(sRawValueOld)) &&
!node.checkAncestorPerms()){
field.setRawValue(sRawValueOld);
MsgFormatPos message = new MsgFormatPos(ResId.PermissionsViolationExceptionMethod);
message.format("calculate");
throw new ExFull(message);
}
}
}
}
if (bCalcEnabled && node instanceof FormExclGroup) {
FormExclGroup exclGroup = (FormExclGroup)node;
// ensure none of the field children have the value overwritten
for (Node child = exclGroup.getFirstXFAChild(); child != null; child = child.getNextXFASibling()) {
if (child instanceof FormField) {
FormField formField = (FormField) child;
// check for override setting on the value node.
// if set to true don't run the script
Element value = formField.getElement(XFA.VALUETAG, true, 0, false, false);
if (value != null && value.getEnum(XFA.OVERRIDETAG) == EnumAttr.BOOL_TRUE) {
// watson bug 1440694 old 7.0 forms don't respect the override attribute,
// must continue to respect this
if (!node.getAppModel().getLegacySetting(AppModel.XFA_LEGACY_CALCOVERRIDE))
return;
}
}
}
returnCode = exclGroup.evaluate(sScript, sContentType, ScriptHandler.CALCULATE, true);
String sReturnValue = "";
if ((Arg.EXCEPTION != returnCode.getArgType()) &&
(Arg.EMPTY != returnCode.getArgType())) {
if (Arg.NULL != returnCode.getArgType())
sReturnValue = returnCode.getAsString(false);
// watson 1776934: Do not detect permissions violations for calculations unless the
// calculation is modifying the existing value.
if (sReturnValue != null && ! sReturnValue.equals(exclGroup.getRawValue())) {
// check permissions
if (! node.checkAncestorPerms()) {
MsgFormatPos message = new MsgFormatPos(ResId.PermissionsViolationExceptionMethod);
message.format("calculate");
throw new ExFull(message);
}
exclGroup.setRawValue(sReturnValue);
}
}
}
else if (bCalcEnabled && node instanceof FormSubform) {
FormSubform subform = (FormSubform)node;
returnCode = subform.evaluate(sScript, sContentType, ScriptHandler.CALCULATE, true);
}
if (Arg.EXCEPTION == returnCode.getArgType()) {
//Vantive 567857
//An exception occurred when evaluating this script but it's possible
//that this script will pass if run again later. If we're able to requeue it
//(i.e. not cyclic dependency) then we'll remove the errors it just generated.
//If will only be allowed to fail a finite number of times before
//we stop giving it another chance.
int nNumErrorsOccurred = formModel.getErrorList().size() - nNumErrorsBefore;
if (0 < nNumErrorsOccurred) {
// Queue it up again
if ( formModel.queueCalculate((ProtoableNode)node) ) {
//Remove the errors logged this time.
for (int e = 0; e < nNumErrorsOccurred; e++) {
formModel.removeLastError();
}
assert nNumErrorsBefore == formModel.getErrorList().size();
}
}
}
}
finally {
tracker.dispose();
}
}
int getRunAt() {
return meRunAt;
}
@Override
public void updateFromPeer(Object peerNode,
int eventType,
String arg1,
Object arg2) {
Element node = getActionContextNode();
if (node == null)
return;
// Change of presence means we need to queue calcs
// (In case the object was inactive before)
// This won't do anything if the object is still inactive.
if (peerNode == node &&
node instanceof Container &&
eventType == Peer.ATTR_CHANGED &&
arg1.equals(XFA.PRESENCE) ) {
// note would be nice to directly access mpoNodeImpl->mpModel
FormModel formModel = (FormModel)node.getModel();
formModel.queueCalculatesAndValidates(node, true);
}
}
}