com.adobe.xfa.configuration.ConfigurationModel Maven / Gradle / Ivy
Show all versions of aem-sdk-api Show documentation
/*
* 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.configuration;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.xml.sax.Attributes;
import com.adobe.xfa.AppModel;
import com.adobe.xfa.Attribute;
import com.adobe.xfa.ChildReln;
import com.adobe.xfa.ChildRelnInfo;
import com.adobe.xfa.Element;
import com.adobe.xfa.LogMessage;
import com.adobe.xfa.Model;
import com.adobe.xfa.Node;
import com.adobe.xfa.NodeList;
import com.adobe.xfa.Obj;
import com.adobe.xfa.SOMParser;
import com.adobe.xfa.STRS;
import com.adobe.xfa.Schema;
import com.adobe.xfa.StringAttr;
import com.adobe.xfa.TextNode;
import com.adobe.xfa.XFA;
import com.adobe.xfa.SOMParser.SomResultInfo;
import com.adobe.xfa.template.TemplateModel;
import com.adobe.xfa.ut.BooleanHolder;
import com.adobe.xfa.ut.ExFull;
import com.adobe.xfa.ut.MsgFormat;
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.FindBugsSuppress;
import com.adobe.xfa.ut.StringUtils;
/**
* A class to model the collection of all XFA nodes that make
* up form config.
*
* @author Ian Benedict Carreon
* @author Mike Tardif (ported to Java)
*/
public final class ConfigurationModel extends Model {
private static final ConfigurationSchema gConfigurationSchema
= new ConfigurationSchema();
/**
* @see Model#createNode(int, Element, String, String, boolean)
*
* @exclude from published api.
*/
public Node createNode(int eTag, Element parent, String aName, String aNS, boolean bDoVersionCheck) {
assert (aName != null);
assert (aNS != null);
// check what type of node to create.
if (eTag == XFA.TEXTNODETAG) {
Element oRet = getSchema().getInstance(eTag, this, parent, null, bDoVersionCheck);
// set the default value for the node
if (parent instanceof ConfigurationValue) {
Element grandParent = parent.getXFAParent();
if (grandParent != null) {
Attribute sValue = getSchema().defaultAttribute(parent.getClassTag(), grandParent.getClassTag());
oRet.setAttribute(sValue, XFA.VALUETAG);
}
}
return oRet;
}
else if (eTag == XFA.CONFIGURATIONKEYTAG) {
return new ConfigurationKey(parent, null);
}
else if (eTag == XFA.CONFIGURATIONVALUETAG) {
return new ConfigurationValue(parent, null);
}
Element oRet = getSchema().getInstance(eTag, this, parent, null, bDoVersionCheck);
if (oRet.isValidAttr(XFA.NAMETAG, false, null)) {
oRet.setName(aName);
}
return oRet;
}
/**
* @exclude from published api.
*/
public String getHeadNS() {
return configurationNS();
}
/**
* @exclude from published api.
*/
protected static Schema getModelSchema() {
return gConfigurationSchema;
}
/**
* Gets the configuration model held within an XFA DOM hierarchy.
*
* @param appModel the application model.
*
* @param bCreateIfNotFound when set, create a model if necessary.
*
* @return the configuration model or null if none found.
*/
public static ConfigurationModel getConfigurationModel(AppModel appModel,
boolean bCreateIfNotFound /* = false */) {
ConfigurationModel configModel = (ConfigurationModel)Model.getNamedModel(appModel, XFA.CONFIG);
if (bCreateIfNotFound && configModel == null) {
ConfigurationModelFactory factory = new ConfigurationModelFactory();
configModel = (ConfigurationModel) factory.createDOM((Element)appModel.getXmlPeer());
configModel.setDocument(appModel.getDocument());
appModel.notifyPeers(Peer.CHILD_ADDED, XFA.CONFIG, configModel);
}
return configModel;
}
/**
* Namespace
* @return The configuration namespace URI string
*
* @exclude from published api.
*/
public static String configurationNS() {
return STRS.XFACONFIGURATIONNS_CURRENT;
}
/**
* Default Constructor.
*
* @exclude from published api.
*/
public ConfigurationModel(Element parent, Node prevSibling) {
super(parent, prevSibling, configurationNS(), XFA.CONFIG, XFA.CONFIG,
STRS.DOLLARCONFIG, XFA.CONFIGTAG, XFA.CONFIG, getModelSchema());
}
/**
* @see Model#getBaseNS()
*
* @exclude from published api.
*/
public String getBaseNS() {
return STRS.XFACONFIGURATIONNS;
}
/**
* @see Model#postLoad()
*
* @exclude from published api.
*/
protected void postLoad() {
postLoadFixUp(this);
//
// Check if there is a previous ConfigurationModel in the AppModel
// (one that is not equal to this ConfigurationModel). If an earlier
// one exists, we need to merge this one into it and delete this one.
//
ConfigurationModel oPrevConfigurationModel = null;
AppModel appModel = getAppModel();
if (appModel != null) {
Node child = appModel.getFirstXFAChild();
while (child != null) {
if (child != this && child instanceof ConfigurationModel) {
oPrevConfigurationModel = ((ConfigurationModel) child);
break;
}
child = child.getNextXFASibling();
}
}
if (oPrevConfigurationModel != null) {
oPrevConfigurationModel.mergeModel(this);
appModel.removeChild(this);
}
}
/**
* @see Model#isVersionCompatible(int, int)
*
* @exclude from published api.
*/
public boolean isVersionCompatible(int nVersion, int nTargetVersion) {
if (nVersion <= Schema.XFAVERSION_25)
nVersion = Schema.XFAVERSION_25;
if (nTargetVersion <= Schema.XFAVERSION_25)
nTargetVersion = Schema.XFAVERSION_25;
return super.isVersionCompatible(nVersion, nTargetVersion);
}
/**
* @see Element#getNS()
*
* @exclude from published api.
*/
public String getNS() {
int nVersion = getCurrentVersion();
//
// Check if there is a template in the AppModel. If so
// then we want to set the version of the configuration
// based on the template.
//
AppModel appModel = getAppModel();
if (appModel != null) {
for (Node child = appModel.getFirstXFAChild(); child != null; child = child.getNextXFASibling()) {
if (child instanceof TemplateModel) {
nVersion = ((TemplateModel)child).getCurrentVersion();
break;
}
}
}
// if we have a version set use it.
if (nVersion > 0) {
// config version tracks template version for 2.8, 2.9 and 3.0 but is limited to 3.0 for template==3.1
if (nVersion > Schema.XFAVERSION_30)
nVersion = Schema.XFAVERSION_30;
// bumped to 2.6 for Acrobat 8.1
else if (nVersion > Schema.XFAVERSION_25 && nVersion < Schema.XFAVERSION_28)
nVersion = Schema.XFAVERSION_26;
// the ns stayed the same between 1.0 and 2.5
else if (nVersion <= Schema.XFAVERSION_25)
nVersion = Schema.XFAVERSION_10;
double dVersion = ((double) nVersion) / 10.0;
String sNSBuf = getBaseNS() + Numeric.doubleToString(dVersion, 1, false) + '/';
return sNSBuf.intern();
}
return super.getNS();
}
/**
* Gets the value of a configuration value node.
*
* If the node doesn't exist, the default value will be returned.
*
* @param sSOM A SOM expression specifying the configuration value node.
* @param isDefault a scalar which is set to true if the node
* exists, and false if the node does not exist and
* the value returned is a default value.
* @return the retrieved attribute.
*/
public Attribute getConfigValue(String sSOM, BooleanHolder isDefault) {
//
// Set value to empty string by default
//
isDefault.value = false;
Node oContextNode = getContext();
assert (oContextNode != null);
List oLHSResult = new ArrayList();
SOMParser oParser = new SOMParser(null);
oParser.resolve(oContextNode, sSOM, oLHSResult);
//
// Hurl if more than one element returned.
//
if (oLHSResult.size() > 1)
throw new ExFull(ResId.SOMTypeException);
else if (oLHSResult.size() == 1) {
//
// If propertyName is not empty, then it's a reference
// to a property as opposed to a node.
//
SOMParser.SomResultInfo oSRI = oLHSResult.get(0);
if (!StringUtils.isEmpty(oSRI.propertyName)) {
// Assume it's a string property since we really have no idea.
isDefault.value = true;
return new StringAttr(oSRI.propertyName, oSRI.value.getString());
}
// Not a property reference. It must be a reference to an
// XFAConfigurationValue node.
if (! (oSRI.object instanceof ConfigurationValue))
throw new ExFull(new MsgFormat(ResId.InvalidCommandlineOption,
sSOM));
ConfigurationValue oConfigValue = (ConfigurationValue) oSRI.object;
Attribute oValue = oConfigValue.getValue(isDefault);
isDefault.value = ! isDefault.value;
return oValue;
}
//
// SOM expression not found in config - get default value.
// tag name = class name
//
Node oParent = oContextNode;
//
// Walk down until we don't have any more xfa nodes.
//
String sChild = null;
int nOffset = -1;
String sTag = sSOM;
while ((nOffset = sTag.indexOf('.')) >= 0) {
sChild = sTag.substring(0, nOffset);
Node oNode = oParent.resolveNode(sChild);
if (oNode == null)
break;
oParent = oNode;
sTag = sTag.substring(nOffset + 1);
}
//
// Ensure we are in the config dom.
//
if (! (oParent instanceof ConfigurationKey))
return new StringAttr("","");
Schema oSchema = getSchema();
//
// We now know we are under an unvalidated section
// so return default config value.
//
if (oParent.isSameClass(XFA.CONFIGURATIONKEY)) {
int eTag = XFA.getTag(sChild.intern());
return oSchema.defaultAttribute(eTag, XFA.CONFIGURATIONVALUETAG);
}
//
// Walk down the virual tree.
//
int eParent = oParent.getClassTag();
while ((nOffset = sTag.indexOf('.')) >= 0) {
sChild = sTag.substring(0, nOffset);
//
// Trim off any [..]
//
int nFoundAt = sChild.indexOf('[');
if (nFoundAt >= 0)
sChild = sChild.substring(0, nFoundAt);
ChildRelnInfo oReln = null;
int eChild = XFA.getTag(sChild.intern());
if (eChild >= 0)
oReln = oSchema.getNodeSchema(eParent).getChildRelnInfo(eChild);
//
// If null then check if configkey is valid.
//
if (oReln == null) {
oReln = oSchema.getNodeSchema(eParent).getChildRelnInfo(XFA.CONFIGURATIONKEYTAG);
if (oReln == null)
return new StringAttr("","");
eParent = XFA.CONFIGURATIONKEYTAG;
break;
}
eParent = eChild;
sTag = sTag.substring(nOffset + 1);
}
//
// Trim off any [..]
//
int nFoundAt = sTag.indexOf('[');
if (nFoundAt >= 0)
sTag = sTag.substring(0, nFoundAt);
int eTag = XFA.getTag(sTag.intern());
ChildRelnInfo oReln = null;
if (eTag >= 0)
oReln = oSchema.getNodeSchema(eParent).getChildRelnInfo(eTag);
//
// If null then check if configkey is valid.
//
if (oReln == null) {
if (oSchema.getNodeSchema(eParent).getChildRelnInfo(XFA.CONFIGURATIONKEYTAG).getRelationship() == null)
return new StringAttr("","");
}
return getSchema().defaultAttribute(eTag, eParent);
}
/**
* Gets the value of a configuration value node.
*
* If the node doesn't exist, the default value will be returned.
*
* @param sSOM A SOM expression specifying the configuration value node.
* @param sValue The retrieved value.
* @return true if the node exists, and false if the node does not exist
* and the value returned is a default value.
*/
public boolean getConfigValue(String sSOM, StringBuilder sValue) {
BooleanHolder oRetBool = new BooleanHolder();
Attribute oValue = getConfigValue(sSOM, oRetBool);
if (oValue != null)
sValue.append(oValue);
return oRetBool.value;
}
/**
* @exclude from published api.
*/
public int getHeadVersion() {
return Schema.XFAVERSION_CONFIGURATIONHEAD;
}
/**
* Retrieve the common ConfigurationKey node. For a particular schema root.
* The schema root must have the common property child.
*
* @param sSchemaName The name of the root of the schema.
* @return The common ConfigurationKey, null if common is not a valid
* property of the root node.
*
* @exclude from published api.
*/
public Element getCommonNode(String sSchemaName) {
Element oRoot = null;
if (sSchemaName != null) {
for (Node child = getFirstXFAChild(); child != null; child = child.getNextXFASibling()) {
if (child instanceof Element) {
Element element = (Element)child;
if (element.getName().equals(sSchemaName)) {
oRoot = element;
}
}
}
sSchemaName = sSchemaName.intern();
}
int eTag = XFA.getTag(sSchemaName);
if (oRoot != null) {
if (! oRoot.isValidElement(XFA.COMMONTAG, false))
return null;
}
else if (eTag >= 0 && isValidElement(eTag, false) && eTag != XFA.AGENTTAG) {
// assume all valid children have a property called common
oRoot = createElement(eTag, getName());
}
else { // create agent
oRoot = createElement(XFA.AGENTTAG, sSchemaName);
}
return oRoot.getElement(XFA.COMMONTAG, 0);
}
/**
* Creates a unique path of nodes using a SOM expression starting from
* the root node.
*
* Remark that the SOM expression must start with "config". For example
* "config.present.common"
*
* @param sSOMExpression a string representing a SOM expression
* @param bLeafIsKey if true, then the leaf node in the SOM expressio
* will be a key, else a value.
* @return a node which is the last entity in the SOM expression.
*/
Node createNodePath(String sSOMExpression,
boolean bLeafIsKey /* = false */) {
throw new ExFull(ResId.UNSUPPORTED_OPERATION, "ConfigurationModel#createNodePath");
//TODO SOMParser.SomResultInfo oResult
// = resolveNodeCreate(sSOMExpression, CREATEACTION, bKey);
// Node oNode = oResult.object;
// if (oNode != null || !StringUtils.isEmpty(oResult.propertyName))
// return null;
// return oNode;
}
/**
* Create an element based on the parameters provided by the SAX handler.
*
* @param uri namespace for this element.
* @param localName local name for this element.
* @param qName qualified name for this element.
* @param attributes structure containing attribute definitions.
* @return a new Element created according to our schema.
*
* @exclude from published api.
*/
public Element createElement(Element parent, Node prevSibling, String uri,
String localName, String qName,
Attributes attributes, int lineNumber,
String fileName) {
Element oElement = super.createElement(parent, prevSibling, uri,
localName, qName, attributes,
lineNumber, fileName);
int eClassTag = oElement.getElementClass();
if (eClassTag != XFA.INVALID_ELEMENT) {
//
// Hide all password elements.
//
if (eClassTag == XFA.USERPASSWORDTAG)
oElement.isHidden(true);
else if (eClassTag == XFA.MASTERPASSWORDTAG)
oElement.isHidden(true);
}
return oElement;
}
/**
* @exclude from published api.
*/
public void mergeModel(ConfigurationModel oModel) {
// This XFA-Configuration model is locked from any changes.
if(getLocked())
return;
mergeNode(this, oModel);
}
/**
* Remap a given tag to a new value. This gives a model a chance to remap a tag
* to a new value after it's determined that the original wasn't valid in the current
* context. This implementation simply returns XFA.CONFIGURATIONKEYTAG. It should
* be clever enough to determine either KEY or VALUE in the same way that
* XFAConfigurationModelImpl::getNodeType does on the C++ side, but that's not possible
* here due to the single DOM. Post-load fix-ups should recategorize this KEY to a VALUE
* when necessary.
*
* @param eTag the original input tag.
*
* @return the new remapped tag.
*
* @exclude from published api.
*/
public int remapTag(int eTag) {
return XFA.CONFIGURATIONKEYTAG;
}
// logic for merging configuration nodes
@FindBugsSuppress(code="ES")
private void mergeNode(Node oDestNode, Node oSrcNode) {
assert(oDestNode.getName() == oSrcNode.getName());
// Check lock tag. We don't bother calling isLocked because that looks up the
// tree to check inheritance. Since we're recursing from the top down, and we
// stop at the first locked node, that's overkill.
if (oDestNode.getLocked()) {
//
// Issue a warning; XFA-Configuration node is not modifiable.
//
ExFull oErr = new ExFull(ResId.InvalidOverrideOperationException, oDestNode.getName());
addErrorList(oErr, LogMessage.MSG_WARNING, this);
return;
}
try
{
if (oDestNode instanceof ConfigurationValue && oSrcNode instanceof ConfigurationValue) {
((ConfigurationValue) oDestNode).setValue(((ConfigurationValue) oSrcNode).getValue());
if (oDestNode instanceof ConfigurationUri) {
assert(oSrcNode instanceof ConfigurationUri);
((ConfigurationUri) oDestNode).setConfigLocation(((ConfigurationUri) oSrcNode).getConfigLocation());
}
copyAttributes((Element)oDestNode, (Element)oSrcNode);
return;
}
Node oParent = oSrcNode;
for (Node oTemp = oSrcNode.getFirstXFAChild(); oTemp != null; oTemp = oTemp.getNextXFASibling()) {
if (!(oTemp instanceof Element))
continue;
Element oSrcChild = (Element) oTemp;
boolean bMerge = false; // false: recursively merge oDestChild, oSrcChild;
// true: just append a copy of oSrcChild to oDestNode
String sSrcChildName = oSrcChild.getName();
Node oDestChild = oDestNode.locateChildByName(sSrcChildName, 0);
if (oDestChild != null)
bMerge = true;
// Get the child relationship of oSrcChild with its parent (oSrcNode).
ChildReln oChildReln = ((Element) oParent).getChildReln(oSrcChild.getClassTag());
if (oChildReln != null) {
int eOccurs = oChildReln.getOccurrence();
if (eOccurs == ChildReln.zeroOrMore) {
if ( ! ((Element) oSrcChild).isValidAttr(XFA.NAMETAG, false, null)) {
if (oSrcChild.getName() == XFA.EQUATE) {
NodeList oDestChildren = oDestNode.getNodes();
// If a node with a duplicate "from" attribute is found, just copy the attributes
// of oSrcChild over that node. If not found, append oSrcChild.
Element oDuplicateFromNode = equateFindDuplicateFrom(oDestChildren, oSrcChild);
if (oDuplicateFromNode != null) {
copyAttributes(oDuplicateFromNode, oSrcChild);
continue; // handled
}
}
bMerge = false; // for zeroOrMore nodes, just append copy of node
}
}
}
if (bMerge) {
mergeNode(oDestChild, oSrcChild);
copyAttributes((Element) oDestChild, oSrcChild);
oDestChild.makeNonDefault(false);
}
else {
oSrcChild.clone((Element) oDestNode);
}
}
} catch (ExFull oEx) {
// An illegal value was encountered. Log a warning and continue with the rest.
addErrorList(oEx, LogMessage.MSG_WARNING, this);
}
}
private void copyAttributes(Element oDestNode, Element oSrcNode) {
if (oDestNode.getLocked())
return;
//
// Replace all the attributes
//
int nSize = oSrcNode.getNumAttrs();
String sAttrVal;
for (int i = 0; i < nSize; i++)
{
Attribute domAttr = oSrcNode.getAttr(i);
String aAttr = domAttr.getLocalName();
boolean bHandled = loadSpecialAttribute(domAttr, aAttr, oDestNode, false);
if (!bHandled) {
int eTag = XFA.getAttributeTag(aAttr);
if (eTag != -1 && oDestNode.isValidAttr(eTag, true, null)) {
sAttrVal = domAttr.getAttrValue();
Attribute oProperty = new StringAttr(aAttr, sAttrVal);
oDestNode.setAttribute(oProperty, eTag);
}
}
}
}
// Special case when node is tag
// Searches oDestChildren for a node whose "from" property is a
// duplicate of the "from" property in oSrcChild. If found, returns
// that node, else returns a NULL node.
private Element equateFindDuplicateFrom(NodeList oDestChildren, Element oSrcChild) {
Attribute oNodeAttr = oSrcChild.getAttribute(XFA.FROMTAG);
String sNodeAttr = oNodeAttr.toString();
int i = 0;
while (i < oDestChildren.length()) {
Obj oTemp = oDestChildren.item(i);
if (!(oTemp instanceof Element))
continue;
Element oDestChild = (Element) oTemp;
Attribute oAttr = oDestChild.getAttribute(XFA.FROMTAG);
String sAttr = oAttr.toString();
if (sAttr.equals(sNodeAttr))
return oDestChild;
i++;
}
return null; // no duplicate "from" found
}
/**
* postLoadFixUp is called from postLoad(). It traverses the entire config
* DOM and replaces ConfigurationKeys that have no children, have or a
* single #text child, with ConfigurationValues. This is to match the C++
* implementation, which has the luxury of looking at the XML DOM tree to
* determine whether there are children or not, in order to decide whether
* to create a Key or Value.
*
* @param node the Node to be fixed up.
*/
private void postLoadFixUp(Node node) {
if (loadSpecialNode(node.getXFAParent(), node, false))
return;
// If a ConfigurationKey has no children or a single #text child, it should have been a ConfigurationValue,
// so replace it after the fact.
if (node.getClassTag() == XFA.CONFIGURATIONKEYTAG) {
if (node.getFirstXMLChild() == null) {
Element parent = node.getXFAParent();
Element cv = new ConfigurationValue(parent, node, XFA.CONFIGURATIONVALUETAG, node.getName());
parent.removeChild(node);
node = cv; // Replace node with the new ConfigurationValue and fall through.
}
else {
Node child = node.getFirstXMLChild();
if (child instanceof TextNode && child.getNextXMLSibling() == null) {
Element parent = node.getXFAParent();
Element cv = new ConfigurationValue(parent, node, XFA.CONFIGURATIONVALUETAG, node.getName());
cv.appendChild(child);
parent.removeChild(node);
node = cv; // Replace node with the new ConfigurationValue and fall through.
}
}
}
if (node instanceof ConfigurationValue) {
// Verify that loaded values are valid by calling getValue(). If not valid,
// issue a warning and set the ConfigurationValue to the default value.
try {
((ConfigurationValue)node).getValue();
} catch (ExFull e) {
String sOldValue = "";
Node textNode = node.getFirstXFAChild();
if (textNode instanceof TextNode)
sOldValue = ((TextNode)textNode).getValue();
String sNewValue = "";
Element parent = node.getXFAParent();
if (parent != null) {
Attribute newValue = getSchema().defaultAttribute(node.getClassTag(), parent.getClassTag());
((ConfigurationValue)node).setValue(newValue);
sNewValue = newValue.toString();
}
// "Invalid value '%1' specified for element '%2'. Default value of '%3' will be used."
MsgFormatPos message = new MsgFormatPos(ResId.FoundBadElementValueException);
message.format(sOldValue);
message.format(node.getName());
message.format(sNewValue);
ExFull err = new ExFull(message);
addErrorList(err, LogMessage.MSG_WARNING, this);
}
}
if (node instanceof Element) {
Element element = (Element)node;
final int nAttributes = element.getNumAttrs();
for (int i = 0; i < nAttributes; i++) {
Attribute attr = element.getAttr(i);
/* boolean bHandled = */ loadSpecialAttribute(attr, attr.getLocalName(), element, false);
}
}
// Check for locked nodes.
Element parent = node.getXFAParent();
if (parent != null && parent.getLocked())
node.setLocked(true);
else if (node instanceof Element) {
Element e = (Element)node;
Attribute locked = e.getAttribute(XFA.LOCKTAG, true, false);
if (locked != null && locked.getAttrValue().equals("1"))
e.setLocked(true);
}
// Recursively apply fix to children.
Node child = node.getFirstXMLChild();
while (child != null) {
Node next = child.getNextXMLSibling();
postLoadFixUp(child);
child = next;
}
}
/**
* @see com.adobe.xfa.Model#publish(com.adobe.xfa.Model.Publisher)
* @exclude from published api.
*/
public boolean publish(Publisher publisher) {
// call static, recursive version
Map fileRefCache = new HashMap();
publishNode(publisher, this, fileRefCache);
return super.publish(publisher);
}
// static, recursive version of publish()
private static void publishNode(Publisher publisher, Node node, Map fileRefCache) {
if (node.isSameClass(XFA.URITAG)) {
if (node.getXFAParent().isSameClass(XFA.XSLTAG) || node.getXFAParent().isSameClass(XFA.OUTPUTXSLTAG)) {
if (node.getXFAChildCount() == 1) {
TextNode textNode = (TextNode)node.getFirstXFAChild();
String sFileRef = textNode.getValue();
String sNewFileRef = fileRefCache.get(sFileRef);
if (StringUtils.isEmpty(sNewFileRef)) {
// call publisher's virtual method updateExternalRef() to get a new value
sNewFileRef = publisher.updateExternalRef(node, XFA.TEXTNODETAG, sNewFileRef);
fileRefCache.put(sFileRef, sNewFileRef);
}
if (!sFileRef.equals(sNewFileRef))
textNode.setValue(sNewFileRef, true, false);
}
}
}
for (Node child = node.getFirstXFAChild(); child != null; child = child.getNextXFASibling()) {
publishNode(publisher, child, fileRefCache);
}
}
/**
* @see Node#canCreateChild(boolean, String)
*
* @exclude from published api.
*/
protected boolean canCreateChild(boolean bIsLeaf, String aName) {
return true;
}
/**
* @see Node#createChild(boolean, String)
*
* @exclude from published api.
*/
@FindBugsSuppress(code="ES")
protected Node createChild(boolean bIsLeaf, String aName) {
Node oNode;
int eClassTag = XFA.getTag(aName);
if (eClassTag >= 0 && isValidElement(eClassTag, false))
oNode = getModel().createElement(this, null, null, aName, aName, null, 0, null);
else if (bIsLeaf)
oNode = getModel().createElement(XFA.CONFIGURATIONVALUETAG, aName);
else
oNode = getModel().createElement(XFA.CONFIGURATIONKEYTAG, aName);
return oNode;
}
}