com.adobe.xfa.data.DataModelFactory 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.data;
import org.xml.sax.Attributes;
import com.adobe.xfa.AppModel;
import com.adobe.xfa.Element;
import com.adobe.xfa.Model;
import com.adobe.xfa.ModelFactory;
import com.adobe.xfa.ModelPeer;
import com.adobe.xfa.Node;
import com.adobe.xfa.Option;
import com.adobe.xfa.STRS;
import com.adobe.xfa.XFA;
import com.adobe.xfa.ut.ExFull;
import com.adobe.xfa.ut.FindBugsSuppress;
import com.adobe.xfa.ut.MsgFormatPos;
import com.adobe.xfa.ut.ResId;
/**
* A class to represent XFA data model factories. A data model factory
* is used by an application model to create a data model where
* appropriate, when loading an XML file.
*/
public final class DataModelFactory extends ModelFactory {
private static final String gsAttrOption = "delegate|ignore|preserve";
private static final String gsRecordOption = "%d|%s";
private Option mAttributesOption;
private Option mDataWindowOption; // mDataWindowOption is stored as a string, but is parsed into
private Option mExcludeNSOption;
private int mnDataWindowRecordsAfter;
private int mnDataWindowRecordsBefore; // mnDataWindowRecordsBefore and mnDataWindowRecordsAfter.
private Option mRangeOption;
private Option mRecordOption;
private Option mStartNodeOption;
private DataTransformations mTransformations;
private Option mTransformOption;
/**
* Instantiates a data model factory.
*/
public DataModelFactory() {
super(XFA.DATAMODELTAG, XFA.DATA, STRS.DOLLARDATA);
mAttributesOption = new Option(XFA.ATTRIBUTES, gsAttrOption);
mRecordOption = new Option(XFA.RECORD, gsRecordOption); // integer | name
mTransformOption = new Option(XFA.TRANSFORM, STRS.PERCENTS); // transformations
mRangeOption = new Option(XFA.RANGE, STRS.PERCENTS); // num,num-num,num-*,...
mStartNodeOption = new Option(XFA.STARTNODE, STRS.PERCENTS); // path
mExcludeNSOption = new Option(XFA.EXCLUDENS, STRS.PERCENTS); // string (list of namespaces separated by blanks)
mDataWindowOption = new Option(XFA.WINDOW, STRS.PERCENTS); // string ("number", or "number,number")
mnDataWindowRecordsBefore = 0;
mnDataWindowRecordsAfter = 0;
mTransformations = null;
attributesAreValues(true);
}
/**
* Return a boolean indicating whether XML attributes are to be treated as
* XFADataValues or ignored. The default is false.
*
* @return true if attributes are to be XFADataValues
*
* @exclude from published api.
*/
public boolean attributesAreValues() {
// This may have to be revisited if the meaning of "delegate" ever changes.
// Right now it's equivalent to "ignore".
return (mAttributesOption.getMatchingIndex() == 2); // 2 == "preserve"
}
/**
* Set the behavior for interpreting XML attributes.
*
* @param bSetting
* if true, non-namespaced attributes are to be interpreted as
* XFADataValues. If false, attributes are essentially ignored
* within the context of the XFA-Data DOM. The default is false.
*
* @exclude from published api.
*/
public void attributesAreValues(boolean bSetting) {
String sSetting = bSetting ? STRS.PRESERVE : STRS.IGNORE;
mAttributesOption.setValue(sSetting, false);
}
/**
* @exclude from published api.
*/
public Model createDOM(Element parent) {
DataModel m = new DataModel(parent.getAppModel(), null);
// The model might not be created in the same document as the AppModel,
// so make sure that the document is correct now.
m.setDocument(parent.getOwnerDocument());
ModelPeer modelPeer = new ModelPeer(
parent, null,
STRS.XFADATANS_CURRENT, STRS.DATASETS, STRS.XFADATASETS,
null, m);
m.setXmlPeer(modelPeer);
Element dataPeer = new Element(modelPeer, null, STRS.XFADATANS_CURRENT, XFA.DATA, STRS.XFADATA, null, XFA.INVALID_ELEMENT, "");
dataPeer.setModel(m);
// Set xfa:dataNode="dataGroup" so that data is always a dataGroup, never a dataValue.
dataPeer.setAttribute(STRS.XFADATANS_CURRENT, STRS.XFADATANODE, XFA.DATANODE, XFA.DATAGROUP, false);
DataNode dataNode = new DataNode(m, null, null, null, null, null);
dataNode.setClass(XFA.DATAGROUP, XFA.DATAGROUPTAG);
dataNode.setModel(m);
dataNode.setXmlPeer(dataPeer);
dataPeer.setXfaPeer(dataNode);
m.setAliasNode(dataNode);
return m;
}
/**
* DataModel knows how to merge a duplicate model into an existing one
* during postLoad processing.
* @exclude from published api.
*/
public boolean getAllowAdd() {
return true;
}
/**
* @param name the name to be tested. This String must be interned.
* @exclude from published api.
*/
@FindBugsSuppress(code="ES")
public boolean isRootName(String name) {
return (name == XFA.DATA) || (name == STRS.DATASETS);
}
/**
* @param parent
* @param uri
* @param localName This String must be interned.
* @exclude from published api.
*/
@FindBugsSuppress(code="ES")
protected boolean isRootNode(AppModel parent, String uri, String localName) {
// Accept anything, unless the parent node is "xfa", in which
// case accept only the datasets node.
if (!parent.getAllowThirdPartyXml()) {
// only accept "datasets" under the "xfa" node
return localName == STRS.DATASETS;
}
// accept anything else
return true;
}
/**
* @exclude from published api.
*/
@FindBugsSuppress(code="ES")
protected Model newModel(AppModel parent, Node prevSibling, String uri, String localName,
String qName, Attributes a) {
// JAVAPORT_DATA - We may be creating a duplicate DataModel, but it will get
// merged into any existing one during postLoad processing.
DataModel dataModel = new DataModel(parent, prevSibling);
// Create an XML peer for the DataModel.
// This peer may only be temporary since during loading, the DataModel
// may need to rearrange peers as it loads the XML.
// To make things a little easier, we can detect whether the element we
// are creating represents an xfa:datasets element or some third-party
// node, and create the appropriate class of peer.
// We create the peer as an orphan - the SaxHandler will look after
// wiring it into the XFA document.
Element dataModelPeer;
if (uri.equals(STRS.XFADATANS_CURRENT) && localName.equals(STRS.DATASETS)) {
dataModelPeer = new ModelPeer(null, null, uri, localName, qName, a, dataModel);
}
else {
dataModelPeer = new Element(null, null, uri, localName, qName, a, XFA.INVALID_ELEMENT, "");
dataModelPeer.setDocument(dataModel.getOwnerDocument());
}
dataModel.setXmlPeer(dataModelPeer);
if (mAttributesOption.isSet()) {
// don't specify the value if getMatchingIndex() == 0 ("delegate")
if (mAttributesOption.getMatchingIndex() == 1) // "ignore"
dataModel.setAttributesAreValues(false);
else if (mAttributesOption.getMatchingIndex() == 2) // "preserve"
dataModel.setAttributesAreValues(true);
}
if (mRecordOption.isSet()) {
int recordLevel = 1;
String recordName = null;
if (mRecordOption.getMatchingIndex() == 0)
recordLevel = mRecordOption.getInteger();
else
// string
recordName = mRecordOption.getString();
dataModel.setRecordOptions(recordLevel, recordName);
}
if (mRangeOption.isSet()) {
String sRange = mRangeOption.getString();
dataModel.setRangeOptions(sRange);
}
if (mStartNodeOption.isSet()) {
// The format of mStartNodeSOMString was verified when the option
// was set via setOption.
// Parse out the SOM string by removing "xfasom(" and trailing ")".
int nLength = mStartNodeOption.getString().length();
dataModel.setStartNodeSOMString(mStartNodeOption.getString().substring(7, nLength - 1));
}
if (mExcludeNSOption.isSet()) {
dataModel.setExcludeNSList(mExcludeNSOption.getString());
}
if (mDataWindowOption.isSet()) {
dataModel.setDataWindowParameters(mnDataWindowRecordsBefore, mnDataWindowRecordsAfter);
}
if (mTransformations != null && mTransformations.size() > 0) {
// ?? remove
// mTransformations.setAttributesAreValues(attributesAreValues());
dataModel.setTransformations(mTransformations);
}
return dataModel;
}
/**
* Sets a data loading option.
* @param optionName the name of the option
* @param optionValue the value of the option
* @param bCritical if true
, then any future attempts to set this option
* on this DataModelFactory
are rejected.
*/
public void setOption(String optionName, String optionValue, boolean bCritical) {
// JavaPort: This method becomes part of the published API in XFA4J since it is
// used in piCosDocument::setDataLoadOptions, which Gibson code emulates.
// The set of supported options and their domains should be documented.
final Option optionArray[] = new Option[] {
mAttributesOption, // 0
mRecordOption, // 1
mStartNodeOption, // 2
mExcludeNSOption, // 3
mDataWindowOption, // 4
mRangeOption, // 5
mTransformOption, // 6
null
};
// We now support either "datasets_" or "data_" as a prefix for our options.
// We can only specify one package name to XFAOption::setOptionByArray, which
// must match the prefix in the option name IF THERE IS ONE. So what we do
// is check the prefix ourselves, and remove it.
String name = optionName;
int nPackageSeparatorOffset = optionName.indexOf('_');
if (nPackageSeparatorOffset != -1) {
if (nPackageSeparatorOffset == 0)
throw new ExFull(ResId.OptionWrongPackageException, optionName);
// package specified; verify that it's the right one
String packageName = optionName.substring(0, nPackageSeparatorOffset);
if (!isRootName(packageName.intern()))
// wrong package
throw new ExFull(ResId.OptionWrongPackageException, optionName);
// package is OK; remove it from the option name
name = optionName.substring(nPackageSeparatorOffset + 1);
}
int nOption = Option.setOptionByArray("", optionArray, name,
optionValue, bCritical);
if (nOption == 2) { // mStartNodeOption
// Validate string passed to mStartNodeOption. Currently, it must be a SOM
// expression in the form xfasom(som expression).
String sStartNodeString = mStartNodeOption.getString(); // for convenience
if (!sStartNodeString.startsWith("xfasom(")
|| !sStartNodeString.endsWith(")")) {
MsgFormatPos oMessage = new MsgFormatPos(ResId.InvalidOptionValueException);
oMessage.format(mStartNodeOption.getName());
oMessage.format(sStartNodeString);
throw new ExFull(oMessage);
}
}
else if (nOption == 4) { // mDataWindowOption
// Validate string passed to mDataWindowOption. It's either "number" or
// "number,number"
String sWindowString = mDataWindowOption.getString(); // for convenience
int before = 0;
int after = 0;
int iteration = 1;
boolean bValid = false;
String[] tokens = sWindowString.split(",");
for (int i = 0; i < tokens.length; i++) {
String sToken = tokens[i];
int num;
try {
num = Integer.parseInt(sToken);
} catch (NumberFormatException e) {
bValid = false;
break;
}
if (iteration == 1) {
bValid = true;
before = num;
after = num;
}
else if (iteration == 2) {
after = num;
}
else {
bValid = false; // too many numbers
break;
}
iteration++;
}
if (!bValid) {
MsgFormatPos oMessage = new MsgFormatPos(
ResId.InvalidOptionValueException);
oMessage.format(mDataWindowOption.getName());
oMessage.format(sWindowString);
throw new ExFull(oMessage);
}
mnDataWindowRecordsBefore = before;
mnDataWindowRecordsAfter = after;
}
else if (nOption == 6) { // mTransformOption
if (mTransformations == null)
mTransformations = new DataTransformations();
mTransformations.add(mTransformOption.getString());
}
}
public void reset(){
if (mTransformations == null) mTransformations.reset();
}
}