All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.adobe.xfa.form.FormManifest Maven / Gradle / Ivy

There is a newer version: 2024.11.18751.20241128T090041Z-241100
Show newest version
/*
 * ADOBE CONFIDENTIAL
 *
 * Copyright 2008 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 java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import com.adobe.xfa.Element;
import com.adobe.xfa.EnumAttr;
import com.adobe.xfa.Manifest;
import com.adobe.xfa.Node;
import com.adobe.xfa.NodeList;
import com.adobe.xfa.NodeListFilter;
import com.adobe.xfa.Obj;
import com.adobe.xfa.ProtoableNode;
import com.adobe.xfa.XFA;
import com.adobe.xfa.data.DataNode;
import com.adobe.xfa.template.TemplateModel;
import com.adobe.xfa.template.containers.ExclGroup;
import com.adobe.xfa.template.containers.Field;
import com.adobe.xfa.ut.ExFull;
import com.adobe.xfa.ut.FindBugsSuppress;
import com.adobe.xfa.ut.MsgFormatPos;
import com.adobe.xfa.ut.Peer;
import com.adobe.xfa.ut.ResId;

/**
 * A runtime version of a Manifest. This class derives from Manifest and
 * is Form DOM/Node aware.
 *
 * @exclude from published api.
 */
public class FormManifest extends Manifest {

	FormManifest(Element parent, Node prevSibling) {
		super(parent, prevSibling);
	}
	
	/**
	 * @see Manifest#doExecValidate()
	 * @exclude from published api.
	 */
	@Override
    public boolean doExecValidate() {
        Boolean bValidateResult = Boolean.TRUE;
        
        // get the parent
        final Element parent = getXFAParent();
        assert parent != null;
        if (parent != null) {
        	
            // if the parent is  this is a PDF signature
            if (parent.getClassTag() == XFA.SIGNATURETAG)
                bValidateResult = processPDFSignatureManifest(validateFormNode, bValidateResult);
            // if the parent is  this is an XML signature
            else if (parent.getClassTag() == (XFA.SIGNDATATAG))
                bValidateResult = processXMLSignatureManifest(validateFormNode, bValidateResult);
            else
                throw new ExFull(ResId.InvalidManifestException);
        }

        return bValidateResult.booleanValue();
    }

    /**
     * @see Manifest#doExecCalculate()
     * @exclude from published api.
     */
	@Override
    public void doExecCalculate() {
        // get the parent
        final Element parent = getXFAParent();
        assert parent != null;
        if (parent != null) {
        	
            // if the parent is  this is a PDF signature
            if (parent.getClassTag() == XFA.SIGNATURETAG)
                processPDFSignatureManifest(calculateFormNode, null);
            // if the parent is  this is an XML signature
            else if (parent.getClassTag() == XFA.SIGNDATATAG)
                processXMLSignatureManifest(calculateFormNode, null);
            else
                throw new ExFull(ResId.InvalidManifestException);
        }
    }
    
    /**
     * @see Manifest#doExecInitialize()
     * @exclude from published api.
     */
	@Override
    public void doExecInitialize() {
        // get the parent
        Node parent = getXFAParent();
        assert parent != null;
        if (parent != null) {
        	
            // if the parent is  this is a PDF signature
            if (parent.getClassTag() == XFA.SIGNATURETAG)
                processPDFSignatureManifest(initializeFormNode, null);
            // if the parent is  this is an XML signature
            else if (parent.getClassTag() == XFA.SIGNDATATAG)
                processXMLSignatureManifest(initializeFormNode, null);
            else
                throw new ExFull(ResId.InvalidManifestException);
        }
    }
	
	// -------------------------------------------------------------------------
    
    /**
     * callers provide a callback action function and data param to do work with
     * as form nodes are extracted from the manifest.
     * 
     *  @exclude from published api.
     */
    protected interface IteratorAction {
    	T action(Node node, T data);
    }
    
    // -------------------------------------------------------------------------
        
    // PDF signature manifests
    protected  T processPDFSignatureManifest(IteratorAction iteratorAction, T data) {
        // get the @action attribute
        final int eAction = getEnum(XFA.ACTIONTAG);
        if (eAction == EnumAttr.MANIFESTACTION_INCLUDE)
            return templateNodesToFormNodesInclude(iteratorAction, data);
        else if (eAction == EnumAttr.MANIFESTACTION_EXCLUDE)
            return templateNodesToFormNodesExclude(iteratorAction, data);
        else if (eAction == EnumAttr.MANIFESTACTION_ALL)
            return templateNodesToFormNodesAll(iteratorAction, data);
        else
            throw new ExFull(ResId.InvalidManifestException);
    }
        
    @FindBugsSuppress(code="RCN")	// referencedNodes
    protected  T templateNodesToFormNodesInclude(IteratorAction iteratorAction, T data) {
        // get the referenced nodes
        final NodeList referencedNodes = doEvaluate();
        assert referencedNodes != null;
        if (referencedNodes == null)
            return null;
        
        // for each referenced node
        final int nNumReferencedNodes = referencedNodes.length();
        for (int nReferencedNodeIndex = 0; nReferencedNodeIndex < nNumReferencedNodes; nReferencedNodeIndex++) {
        	
            final Obj referencedNode = referencedNodes.item(nReferencedNodeIndex);
            assert referencedNode instanceof Node;
            if (referencedNode instanceof Node) {
            	
                // expand referenced nodes to include applicable children
                final ListexpandedNodes = expandResolvedNode((Node)referencedNode);
                // for each expanded node
                final int nNumExpandedNodes = expandedNodes.size();
                for (int nExpandedNodeIndex = 0; nExpandedNodeIndex < nNumExpandedNodes; nExpandedNodeIndex++) {
                	
                    final Node expandedNode = expandedNodes.get(nExpandedNodeIndex);
                    // extract the form nodes
                    data = templateNodeToFormNodes(iteratorAction, data, expandedNode);
                }
            }
        }
        
        return data;
    }
    
    protected  T templateNodesToFormNodesExclude(IteratorAction iteratorAction, T data) {
        // get the template model
        final TemplateModel template = TemplateModel.getTemplateModel(getAppModel(), false);
        assert template != null;
        if (template != null) {
        	
            // get a list of all the excluded nodes
            final List aExcludedFields = new ArrayList();
            templateNodeToTemplateNodes(populateFieldName, aExcludedFields);

            // iterate over all nodes filtering for those we want
            final ManifestExclusionFilter filter = new ManifestExclusionFilter(aExcludedFields);
            final List nodeList = filter.filterNodes(template);

            // iterate over nodes we want
            final int nLength = nodeList.size();
            for (int nIndex = 0; nIndex < nLength; nIndex++) {
                final Node node = nodeList.get(nIndex);
                // extract the form nodes
                data = templateNodeToFormNodes(iteratorAction, data, node);
            }
        }

        return data;
    }
    
    protected  T templateNodesToFormNodesAll(IteratorAction iteratorAction, T data) {
        // get the template model
        final TemplateModel template = TemplateModel.getTemplateModel(getAppModel(), false);
        assert template != null;
        if (template != null) {
        	
            // iterate over all nodes filtering for those we want
            final ManifestExclusionFilter filter = new ManifestExclusionFilter(null);
            final List nodeList = filter.filterNodes(template);

            // iterate over nodes we want
            final int nLength = nodeList.size();
            for (int nIndex = 0; nIndex < nLength; nIndex++) {
                final Node node = nodeList.get(nIndex);
                // extract the form nodes
                data = templateNodeToFormNodes(iteratorAction, data, node);
            }
        }

        return data;
    }
    
    @FindBugsSuppress(code="RCN")	// referencedNodes
    protected  T templateNodeToTemplateNodes(IteratorAction iteratorAction, T data) {
        // get the referenced nodes
        final NodeList referencedNodes = doEvaluate();
        assert referencedNodes != null;
        if (referencedNodes == null)
            return data;

        // for each referenced node
        final int nNumReferencedNodes = referencedNodes.length();
        for (int nReferencedNodeIndex = 0; nReferencedNodeIndex < nNumReferencedNodes; nReferencedNodeIndex++) {
        	
            final Obj referencedNode = referencedNodes.item(nReferencedNodeIndex);
            assert referencedNode instanceof Node;
            if (referencedNode instanceof Node) {
            	
                // expand referenced nodes to include applicable children
                final List expandedNodes = expandResolvedNode((Node)referencedNode);
                	
                // for each expanded node
                final int nNumExpandedNodes = expandedNodes.size();
                for (int nExpandedNodeIndex = 0; nExpandedNodeIndex < nNumExpandedNodes; nExpandedNodeIndex++) {
                	
                    final Node expandedNode = expandedNodes.get(nExpandedNodeIndex);
                    // call action function
                    data = iteratorAction.action(expandedNode, data);
                }
            }
        }
        
        return data;
    }
    
    protected  T templateNodeToFormNodes(IteratorAction iteratorAction, T data, Node templateNode) {
        assert templateNode != null && (isTemplateField(templateNode) || isTemplateExclGroup(templateNode));

        final ProtoableNode protoable = (ProtoableNode)templateNode;

        // turn template field into form fields
        int nProtoedIndex = 0;
        ProtoableNode protoed = protoable.getProtoed(nProtoedIndex);
        while (protoed != null) {
        	
            // Watson#1387325: ensure the protoed node is valid (has a model) before using it
            if (protoed.getModel() != null && 
                (protoed instanceof FormField || protoed instanceof FormExclGroup)) {
            	
                // call action function
                data = iteratorAction.action(protoed, data);
            }

            protoed = protoable.getProtoed(++nProtoedIndex);
        }

        return data;
    }
    
    protected List expandResolvedNode(Node item) {
        // collect the expanded nodes
        
        // consider the resolved node
        if (isTemplateField(item) || isTemplateExclGroup(item)) {
        	return Collections.singletonList(item);
        }
        else if (item instanceof Element) {
        	
            // consider each  or  descendent of the resolved node (using a filter)
            final ManifestExclusionFilter filter = new ManifestExclusionFilter(null);
            return filter.filterNodes(item, 0);
        }
        else {
        	return Collections.emptyList();
        }
    }
    
    protected static boolean isTemplateField(Node node) {
        return (node instanceof Field) && !(node instanceof FormField);
    }
    
    protected static boolean isTemplateExclGroup(Node node) {
    	return (node instanceof ExclGroup) && !(node instanceof FormExclGroup);
    }
    
    // XML signature manifests
    protected  T processXMLSignatureManifest(IteratorAction iteratorAction, T data) {
        // get the @action attribute
        final int eAction = getEnum(XFA.ACTIONTAG);
        if (eAction == EnumAttr.MANIFESTACTION_INCLUDE) {
        	
            // resolve references
            return dataNodesToFormNodesInclude(iteratorAction, data);
        }
        else if (eAction == EnumAttr.MANIFESTACTION_EXCLUDE || 
                 eAction == EnumAttr.MANIFESTACTION_ALL) {
        	
            // "%1 is an unsupported operation for the %2 object"
            final MsgFormatPos msg = new MsgFormatPos(ResId.UnsupportedOperationException);
            String sOpp = XFA.ACTION + "=\"" + EnumAttr.getString(eAction) + '"';
            msg.format(sOpp);
            msg.format(XFA.MANIFEST);
            throw new ExFull(msg);
        }
        else
            throw new ExFull(ResId.InvalidManifestException);
    }
    
    @FindBugsSuppress(code="RCN")	// referencedNodes
    protected  T dataNodesToFormNodesInclude(IteratorAction iteratorAction, T data) {
        // get the referenced nodes
        final NodeList referencedNodes = doEvaluate();
        assert referencedNodes != null;
                
        if (referencedNodes == null)
            return data;

        // for each referenced node
        final int nNumReferencedNodes = referencedNodes.length();
        for (int nReferencedNodeIndex = 0; nReferencedNodeIndex < nNumReferencedNodes; nReferencedNodeIndex++) {
        	
            final Obj referencedNode = referencedNodes.item(nReferencedNodeIndex);
            assert referencedNode instanceof Node;
            if (referencedNode instanceof Node) {
            	
                // extract form nodes from data nodes
                data = dataNodeToFormNodes(iteratorAction, data, (Node)referencedNode);
            }
        }

        return data;
    }
    
    protected  T dataNodeToFormNodes(IteratorAction iteratorAction, T data, Node dataNode) {
        assert dataNode instanceof DataNode;

         // ensure we have a data node
         if (dataNode instanceof DataNode) {
        	 
             // look through peers for a data listener
             int nPeerIndex = 0;
             Peer peer = dataNode.getPeer(nPeerIndex);
             while (peer != null) {
            	 
                 if (peer instanceof FormDataListener) {
                     // get the form node from the data listener
                     Node formNode = ((FormDataListener)peer).getFormNode();
                     if (formNode != null)	// call action function
                         data = iteratorAction.action(formNode, data);
                 }

                 peer = dataNode.getPeer(++nPeerIndex);
             }
         }

         return data;
     }
    
    // ------------------------------------------------------------------------
    // action functions
    
    protected static final IteratorAction validateFormNode = new IteratorAction() {
    
	    public Boolean action(Node item, Boolean data) {
	    	
		    Boolean validateResult = data;
		    assert validateResult != null;
		    if (validateResult != null) {
		    	
		        if (item instanceof FormSubform) {
		        	
		            final FormSubform formSubform = (FormSubform)item;
	
		            // if validateResult is already FALSE, don't change its value
		            if (validateResult.booleanValue())
		                validateResult = Boolean.valueOf(formSubform.execValidate());
		            else
		                formSubform.execValidate();
		        }	        
		        else if (item instanceof FormField) {
		            final FormField formField = (FormField)item;
	
		            // if validateResult is already FALSE, don't change its value
		            if (validateResult.booleanValue())
		                validateResult = Boolean.valueOf(formField.execValidate());
		            else
		                formField.execValidate();
		        }
		        else if (item instanceof FormExclGroup) {
		            final FormExclGroup exclGroup = (FormExclGroup)item;
	
		            // if validateResult is already FALSE, don't change its value
		            if (validateResult.booleanValue())
		                validateResult = Boolean.valueOf(exclGroup.execValidate());
		            else
		                exclGroup.execValidate();
		        }
		    }
	
		    return validateResult;
		}
    };
    
    protected static final IteratorAction calculateFormNode = new IteratorAction() {
    	
    	public Object action(Node item, Object data) {
	        
    		if (item instanceof FormSubform) {	        	
	            ((FormSubform)item).execEvent(XFA.CALCULATE);
	        }
	        else if (item instanceof FormField) {	        	
	            ((FormField)item).execEvent(XFA.CALCULATE);
	        }
	        else if (item instanceof FormExclGroup) {	        	
	            ((FormExclGroup)item).execEvent(XFA.CALCULATE);
	        }
	
	        return null;	// not used
	    }
    };

    protected static final IteratorAction initializeFormNode = new IteratorAction() {
	    	
    	public Object action(Node item, Object data) {
    		
	        if (item instanceof FormSubform) {
	            ((FormSubform)item).execEvent("initialize");
	        }
	        else if (item instanceof FormField) {
	        	((FormField)item).execEvent("initialize");
	        }
	        else if (item instanceof FormExclGroup) {
	            ((FormExclGroup)item).execEvent("initialize");
	        }
	
	        return null;	// not used
	    }
    };
    
    protected static final IteratorAction> populateFieldName = new IteratorAction>() {
    	
    	public List action(Node item, List aExcludedFields) {
    		
	        // get the template model
	        final TemplateModel template = TemplateModel.getTemplateModel(item.getModel().getAppModel(), false);
	        assert template != null;
	        if (template != null) {
	        	
	            assert aExcludedFields != null;
	            if (aExcludedFields != null) {
	            	
	                assert isTemplateField(item) || isTemplateExclGroup(item);
	                if (isTemplateField(item) || isTemplateExclGroup(item)) {
	                	
	                    // get the field's SOM expression
	                    String sSOMExpression = item.getSOMExpression(template, false);
	                    assert sSOMExpression.length() > 0;
	                    if (sSOMExpression.length() > 0) {
	                    	
	                        // append to list
	                        aExcludedFields.add(sSOMExpression);
	                    }
	                }
	            }
	        }
	
	        return null;	// not used
	    }
    };
    
    // ------------------------------------------------------------------------
    
    /**
     * @exclude from published api.
     */
    protected static class ManifestExclusionFilter extends NodeListFilter {
        
        private final List mExcludedFields;
        private Node mLastExclGroup;
    	
        public ManifestExclusionFilter(List excludedFields) {
        	mExcludedFields = excludedFields;
        }

        public boolean accept(Node node) {
            assert node != null;
            if (node != null) {
                
            	// ensure node is a template field or template exclGroup
                if (isTemplateField(node) || isTemplateExclGroup(node)) {
                	
                    mLastExclGroup = null;
                    
                    // if this node is a field, and its parent is the most recent exclGroup, skip it
                    if (isTemplateField(node)) {
                    	
                        if (node.getXFAParent() == mLastExclGroup)
                            return false;
                    }
                    else // if this node is an exclusion group, remember it for next time
                        mLastExclGroup = node;
                    
                    // is there an exclusion list?
                    if (mExcludedFields == null) {
                        // no exclusion list, so this node is accepted
                        return true;
                    }

                    // get field's SOM expression
                    final String sSOMExpression = node.getSOMExpression(node.getModel(), false);
                    return !mExcludedFields.contains(sSOMExpression);
                }
            }

            return false;
        }
    }
}