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

com.adobe.xfa.agent.Agent Maven / Gradle / Ivy

There is a newer version: 2024.11.18751.20241128T090041Z-241100
Show 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.agent;


import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URL;
import java.util.List;
import java.util.StringTokenizer;

import com.adobe.xfa.AppModel;
import com.adobe.xfa.Attribute;
import com.adobe.xfa.ArrayNodeList;
import com.adobe.xfa.Document;
import com.adobe.xfa.Element;
import com.adobe.xfa.LogMessage;
import com.adobe.xfa.LogMessenger;
import com.adobe.xfa.Model;
import com.adobe.xfa.ModelFactory;
import com.adobe.xfa.Node;
import com.adobe.xfa.NodeList;
import com.adobe.xfa.Packet;
import com.adobe.xfa.STRS;
import com.adobe.xfa.XFA;
import com.adobe.xfa.XSLTranslator;
import com.adobe.xfa.configuration.ConfigurationModel;
import com.adobe.xfa.configuration.ConfigurationModelFactory;
import com.adobe.xfa.configuration.ConfigurationValue;
import com.adobe.xfa.configuration.ConfigurationSchema;
import com.adobe.xfa.connectionset.ConnectionSetModel;
import com.adobe.xfa.data.DataModel;
import com.adobe.xfa.data.DataModelFactory;
import com.adobe.xfa.service.storage.XMLStorage;
import com.adobe.xfa.service.storage.PacketHandler;
import com.adobe.xfa.template.TemplateModel;
import com.adobe.xfa.ut.ExFull;
import com.adobe.xfa.ut.FindBugsSuppress;
import com.adobe.xfa.ut.MsgFormatPos;
import com.adobe.xfa.ut.ResId;
import com.adobe.xfa.ut.BooleanHolder;
import com.adobe.xfa.ut.StringUtils;
import com.adobe.xfa.ut.trace.Trace;


/**
 * A base class to represent XFA agents.  Derived classes would
 * embody significant XFA form processor capabilities.
 *  
 * @exclude from published api.
 *  
 */
public abstract class Agent implements PacketHandler {


	/**
 	 * Completion code for success.
	 */
	public static final int SUCCESS = 0;
	/**
 	 * Completion code for failure.
	 */
	public static final int FAIL = 1;
	/**
 	 * Completion code for success with warning.
	 */
	public static final int SUCCESS_WITH_WARNINGS = 2;
	/**
 	 * Completion code for success with information.
	 */
	public static final int SUCCESS_WITH_INFORMATION = 3;

	/*
	 * Model Types
	 */
	/**
 	 * @exclude from published api.
	 */
	protected static final int UNKNOWN = 0;
	/**
 	 * @exclude from published api.
	 */
	protected static final int CONFIG = 1;
	/**
 	 * @exclude from published api.
	 */
	protected static final int DATA = 2;
	/**
 	 * @exclude from published api.
	 */
	protected static final int TEMPLATE = 3;
	/**
 	 * @exclude from published api.
	 */
	protected static final int XDC = 4;
	/**
 	 * @exclude from published api.
	 */
	protected static final int SOURCESET = 5;
	/**
 	 * @exclude from published api.
	 */
	protected static final int CONNECTIONSET = 6;
	/**
 	 * @exclude from published api.
	 */
	protected static final int XDP = 7;
	/**
 	 * @exclude from published api.
	 */
	protected static final int LOCALESET = 8;
	/**
 	 * @exclude from published api.
	 */
	protected static final int XSL = 9;

	private boolean mbXDPLoadedConfig = false;
	private boolean mbXDPLoadedConnectionSet = false;
	private boolean mbXDPLoadedData = false;
	//private boolean mbXDPLoadedLocaleSet = false;
	private boolean mbXDPLoadedSourceSet = false;
	private boolean mbXDPLoadedTemplate = false;
 	private boolean mbXDPLoadedXDC =  false;
	//private boolean mbXDPLoadedXSL = false;

	private boolean mbIsDataIncremental = false;

	private AppModel moAppModel = null;

	private ConfigurationModelFactory moConfigFactory = null;

	private DataModelFactory moDataFactory = null;

	private final LogMessenger moMessenger = new LogMessenger();
	
	// Javaport: TODO: Ensure that these streams get closed (e.g., when an exception is thrown)
	private InputStream moConfigurationStream = null;

	private InputStream moXDPStream = null;

	private String msPacketList = null;

	private static final Trace goGeneralTrace
						= new Trace("general", ResId.GeneralTraceHelp);

	/**
	 * Instantiates an agent.
	 */
	public Agent() {
		//mbXDPLoadedConfig = false;
		//mbXDPLoadedConnectionSet = false;
		//mbXDPLoadedData = false;
		//mbXDPLoadedLocaleSet = false;
		//mbXDPLoadedSourceSet = false;
		//mbXDPLoadedTemplate = false;
		//mbXDPLoadedXDC =  false;
		//mbXDPLoadedXSL = false;
		reset();
	}

	/**
 	 * @exclude from published api.
	 */
	protected void reset() {
		moAppModel = new AppModel(moMessenger);
		moDataFactory = new DataModelFactory();
		moAppModel.addFactory(moDataFactory);
		moConfigFactory = new ConfigurationModelFactory();
		moAppModel.addFactory(moConfigFactory);
		setPacketList("");
	}

	/**
	 * Activates tracing based on configuration file settings
	 */
	void activateTracing() {
	}

	/**
 	 * @exclude from published api.
	 */
	protected void checkXDPOptions(BooleanHolder oSaveAsXDP,
								   BooleanHolder oIsMergedXDP, 
								   BooleanHolder oEmbedRenderedOutput) {
		Node oContextNode = getContextNode();
		oSaveAsXDP.value = false;
		oIsMergedXDP.value = false;
		//
		// native 
		//
		String sOutputType = "native";
		Node oResolvedNode = null;
		if (oContextNode != null)
			oResolvedNode = oContextNode.resolveNode("output.type");
		if (oResolvedNode instanceof ConfigurationValue) {
			ConfigurationValue oConfigurationValue
									= (ConfigurationValue) oResolvedNode;
			sOutputType = oConfigurationValue.getValue().toString();
			if (sOutputType.equalsIgnoreCase("xdp")) {
				oSaveAsXDP.value = true;
			}
			else if (sOutputType.equalsIgnoreCase("mergedXDP")) {
				oSaveAsXDP.value = true;
				oIsMergedXDP.value = true;
			}
		}
		oEmbedRenderedOutput.value = false;
		if (sOutputType.equalsIgnoreCase("xdp")) {
			//
			//
			//   1 
			//   *
			//
			//
			oResolvedNode
						= oContextNode.resolveNode("xdp.embedRenderedOutput");
			if (oResolvedNode instanceof ConfigurationValue) {
				ConfigurationValue oConfigurationValue
									= (ConfigurationValue) oResolvedNode;
				String sEmbed = oConfigurationValue.getValue().toString();
				if (sEmbed.equalsIgnoreCase("1")) {
					oEmbedRenderedOutput.value = true;
				}
			}
		}
	}

	/**
	 * An XFA PacketHandler to filter out empty nodes and/or
	 * user-specified nodes in an XDP file.
	 * This method gets called for each packet in an XDP that is being loaded.
	 *
 	 * @exclude from published api.
	 */
	public void filterPackets(Node oPacket, Object data) {
		//
		// Check for XFAPackets based on our factories.
		// We don't touch packets we don't know about.
		//
		Element oPacketNode = null;
		if (oPacket instanceof Element)
			oPacketNode = (Element) oPacket;
		if (oPacketNode != null) {
			String sLocalName = oPacketNode.getLocalName();
			String sPackets = getPacketList();
			//
			// exclude all packets listed if list starts with "-"
			//
			boolean bExclude = sPackets.startsWith("-");
			//
			// If a packet list was specified, remove any unwanted packets.
			//
			if (sPackets.length() != 0 && ! sPackets.equals("*")) {
				boolean bInList = sPackets.contains(sLocalName);
				if ((bInList && bExclude) || (! bInList && ! bExclude)) {
					oPacketNode.getXMLParent().removeChild(oPacketNode);
					return;
				}
			}
			//
			// packet is to be loaded,  check if it corresponds to a model
			//
			AppModel oApp = getAppModel();
			List factories = oApp.factories();
			for (int i = 0; i < factories.size(); i++) {
				ModelFactory oFactory = factories.get(i);
				//
				// root of an XFA Model, 
				// must call isRootName becasue isRootNode for XFA-Data
				// will always return true
				//
				if (oFactory.isRootName(sLocalName)) {
					// Remove empty models.
					if (oPacketNode.getFirstXMLChild() == null) {
						oPacketNode.getXMLParent().removeChild(oPacketNode);
						//
						// prevent further processing -- oPacketNode is gone!
						//
						return;
					}
					else if (oFactory instanceof ConfigurationModelFactory) {
						// load config model
						// load starting at dom peer
						//
					// JavaPort: we don't have an XFA DOM to load in Java.
					//	oApp.loadNode(oApp, oPacketNode, new Generator("", ""));
						//
						// set the data loading options
						//
						setDataLoadOptions(null);
						//
						// Update the messenger with any messages from
						// the config DOM.  These can be set to mask out
						// or map messageID severities appropriately.
						//
						LogMessenger oMessenger = getMessenger();
						if (oMessenger != null) {
							oMessenger.updateMessaging(
								ConfigurationModel.getConfigurationModel(oApp,
																	false));
						}
						//
						// Activate trace configuration settings
						//
						activateTracing();
						//
						// We have loaded config, now remove it.
						//
					// JavaPort: we can't remove config from our XML DOM!
					//	Element oParent = oPacketNode.getParent();
					//	if (oParent != null)
					//		oParent.removeChild(oPacketNode);
						return;
					}
					//
					// Special data packets, make sure you set the data
					// options prior to loading.
					//
					else if (oFactory instanceof DataModelFactory) {
						setDataLoadOptions(null);
					}		
					break;
				}
			}
		}
	}

	/**
     * Convenience method to get the XFAApp model.
     * @return an XFA App model.
	 *
 	 * @exclude from published api.
     */
    protected AppModel getAppModel() {
		return moAppModel;
	}

	/**
 	 * @exclude from published api.
	 */
	protected int getCompletionStatus(LogMessenger oMessenger) {
		int cc = SUCCESS;
		int eSeverity = (oMessenger == null) ? LogMessage.MSG_FATAL_ERROR
												: oMessenger.getSeverity();
		switch (eSeverity) {
		case LogMessage.MSG_INFORMATION:
			cc = SUCCESS_WITH_INFORMATION;
			break;
		case LogMessage.MSG_WARNING:
		case LogMessage.MSG_VALIDATION_WARNING:
		case LogMessage.MSG_VALIDATION_ERROR:
			cc = SUCCESS_WITH_WARNINGS;
			break;
		case LogMessage.MSG_FATAL_ERROR:
			cc = FAIL;
		}
		return cc;
	}

	/**
	 * Gets the agent's configuration model.
	 *
 	 * @exclude from published api.
	 */
	protected ConfigurationModel getConfigModel() {
	    return ConfigurationModel.getConfigurationModel(getAppModel(), false);
	}

	/**
	 * Gets the agent's connectionset model.
	 *
 	 * @exclude from published api.
	 */
	protected ConnectionSetModel getConnectionSetModel() {
	    return ConnectionSetModel.getConnectionSetModel(getAppModel(), false);
	}

	/**
     * Retrieve the configuration schema tag name where the config options
     * are stored for this agent.
	 *
 	 * @exclude from published api.
     */
    public abstract String getConfigSchemaName();

	/**
 	 * return the context node represented by sContext.  Create the
	 * config model if it doesn't exist.
	 *
 	 * @exclude from published api.
	 */
	protected Node getContextNode() {
		ConfigurationModel oConfigModel = getConfigModel();
		//
		// If there was no default xci file supplied and no
		// xci files specified on the command line then
		// create an empty XFA-Configuration DOM.
		//
		if (oConfigModel == null) {
			oConfigModel
				= ConfigurationModel.getConfigurationModel(getAppModel(),
																		true);
		}
		//
		// Get node specified by SOM expression.
		// Searching will start at this node.
		//
		return oConfigModel.getCommonNode(getConfigSchemaName());
	}

	/**
	 * Accessor for the agents data model
	 *
 	 * @exclude from published api.
	 */
	protected DataModel getDataModel() {
		for (Node node = moAppModel.getFirstXFAChild(); node != null; node = node.getNextXFASibling()) {
			if (node.getClassName() == "dataModel") {
				return (DataModel)node;
			}
		}
		return null;
	}

	String getDefaultConfiguration(String sSchemaName) {
		ConfigurationSchema oSchema = new ConfigurationSchema();
		return oSchema.printConfigSchema(getConfigSchemaName(), "", false);
	}

	/**
 	 * @exclude from published api.
	 */
	protected LogMessenger getMessenger() {
		return moMessenger;
	}

	/**
	 * Get the list of XFA packets for the XDP.
	 *
 	 * @exclude from published api.
	 */
	public String getPacketList() {
		return msPacketList;
	}

	/**
	 * Gets the agent's template model.
	 *
 	 * @exclude from published api.
	 */
	protected TemplateModel getTemplateModel() {
		return TemplateModel.getTemplateModel(getAppModel(), false);
	}

	/**
 	 * @exclude from published api.
	 */
	protected String getXDCDest(boolean bReportError /* =true */) {
		// Get the destination, pdf, ps, pcl, etc.
		String sXDCDest = "";
		Node oContextNode = getContextNode();
		if (oContextNode != null) {
			Node resolvedNode = oContextNode.resolveNode("destination");
			if (resolvedNode instanceof ConfigurationValue) {
				ConfigurationValue oConfigurationValue
										= (ConfigurationValue) resolvedNode;
				sXDCDest = oConfigurationValue.getValue().toString();
			}
			if (bReportError && sXDCDest.length() == 0)
				throw new ExFull(ResId.DestinationNotSpecifiedError);
		}
		return sXDCDest;
	}

	/*
	 * Return the uri from the Config dome for a specific XFA Model.
	 */
	@FindBugsSuppress(code="SF")
	String getXFAModelConfigURI(int eType) {
		StringBuilder sConfigURI = new StringBuilder();
		switch (eType) {
		case XDC:			// For XDC it's .xdc.uri
			sConfigURI.append(getXDCDest(true));
			sConfigURI.append('.');
			/* fallthru */
		case DATA:			// For these models it's .uri
		case TEMPLATE:
		case SOURCESET:
		case CONNECTIONSET:
			sConfigURI.append(getXFAModelName(eType));
			sConfigURI.append('.');
			/* fallthru */
		case XDP:			// For XDP, uri tag is at the context node level.
			sConfigURI.append(XFA.URI);
			/* fallthru */
		case CONFIG:		// Doesn't make sense for Config.
			/* fallthru */
		}
		return sConfigURI.toString();
	}

	int getXFAModelMessageFileNotFound(int eType) {
		switch(eType) {
		case CONFIG:
			return ResId.ConfigFileNotFound;
		case XDC:
			return ResId.XDCFileNotFound;
		case TEMPLATE:
			return ResId.TemplateFileNotFound;
		case SOURCESET:
			return ResId.SourceSetFileNotFound;
		case CONNECTIONSET:
			return ResId.ConnectionSetFileNotFound;
		case XDP:
			return ResId.XDPFileNotFound;
		case DATA:
		default:
			return ResId.DataFileNotFound;
		}
	}

	int getXFAModelMessageFileNotSpecified(int eType) {
		switch(eType) {
		case XDC:
			return ResId.XDCFileNotSpecified;
		case DATA:
			return ResId.DataFileNotSpecified;
		case TEMPLATE:
			return ResId.TemplateFileNotSpecified;
		case SOURCESET:
			return ResId.SourceSetFileNotSpecified;
		case CONNECTIONSET:
			return ResId.ConnectionSetFileNotSpecified;
		case XDP:
			return ResId.XDPFileNotSpecified;
		case CONFIG:
		default:
			return ResId.ConfigFileNotSpecified;
		}
	}

	/*
	 * Return the name of a specific XFA Model.
	 * @return an interned string containing the model name.
	 */
	String getXFAModelName(int eType) {
		switch (eType) {
		case CONFIG:
			return XFA.CONFIG;
		case XDC:
			return XFA.XDC;
		case DATA:
			return XFA.DATA;
		case TEMPLATE:
			return XFA.TEMPLATE;
		case SOURCESET:
			return XFA.SOURCESET;
		case CONNECTIONSET:
			return XFA.CONNECTIONSET;
		case LOCALESET:
			return XFA.LOCALESET;
		case XSL:
			return XFA.XSL;
		default:
			return null;
		}
	}

	/*
	 * Return the input stream for a specific XFA Model.
	 */
	InputStream getXFAModelStream(int eType) {
		switch (eType) {
		case CONFIG:
			return moConfigurationStream;
		case XDP:
			return moXDPStream;
		default:
			return null;
		}
	}

	/*
	 * Return the type of a specific XFA Model.
	 */
	int getXFAModelType(String sModelName) {
		if (sModelName.equals(XFA.CONFIG))
			return CONFIG;
		else if (sModelName.equals(XFA.XDC))
			return XDC;
		else if (sModelName.equals(XFA.DATA))
			return DATA;
		else if (sModelName.equals(STRS.DATASETS))
			return DATA;
		else if (sModelName.equals(XFA.TEMPLATE))
			return TEMPLATE;
		else if (sModelName.equals(XFA.SOURCESET))
			return SOURCESET;
		else if (sModelName.equals(XFA.CONNECTIONSET))
			return CONNECTIONSET;
		else if (sModelName.equals(XFA.LOCALESET))
			return LOCALESET;
		else if (sModelName.equals(XFA.XSL))
			return XSL;
		else
			return UNKNOWN;
	}

	boolean getXFAPacketLoaded(int eType) {
		switch (eType) {
		case XDC:
			return mbXDPLoadedXDC;
		case CONFIG:
			return mbXDPLoadedConfig;
		case TEMPLATE:
			return mbXDPLoadedTemplate;
		case DATA:
			return mbXDPLoadedData;
		case SOURCESET:
			return mbXDPLoadedSourceSet;
		case CONNECTIONSET:
			return mbXDPLoadedConnectionSet;
		case XDP:
		default:
			return false;
		}
	}

	/*
	 * Get any XSL specific info from the config DOM if specified.
	 */
	void getXSLOptions(String sModelName,
						StringBuilder sLoadOptions, StringBuilder sDebugXSL) {
		//
		// Get any XSL specific info from the config DOM if specified.
		//
		Node oContextNode = getContextNode();
		if (oContextNode != null) {
			//
			// Retrieve the XSL Script if any.  It a script was specified, then
			// put it in the name=value format so that it is handled properly
			// by the loader as a load option.
			//
			Node resolvedNode = oContextNode.resolveNode(sModelName + ".xsl.uri");
			if (resolvedNode instanceof ConfigurationValue) {
				ConfigurationValue oConfigurationValue = (ConfigurationValue) resolvedNode;
				String sValue = oConfigurationValue.getValue().toString();
				if (!StringUtils.isEmpty(sValue))
					sLoadOptions.append(" XSL=\"").append(sValue).append('\"');
			}
			//
			// Retrieve the debug uri where to write the output XML after the XSL
			// script has been issued.  If only the debug path was given, and no
			// XSL was given, the debug file will still be created, but will not
			// contain any useful information.
			//
			resolvedNode = oContextNode.resolveNode(sModelName + ".xsl.debug.uri");
			if (resolvedNode instanceof ConfigurationValue) {
				ConfigurationValue oConfigurationValue = (ConfigurationValue) resolvedNode;
				String sValue = oConfigurationValue.getValue().toString();
				if (sValue.length() != 0)
					sDebugXSL.append(sValue);
			}
		}
	}

	/*
	 * Verify that the model type specified has been loaded.
	 */
	boolean isPacketLoaded(int eType, boolean bRemove /* =false */) {
		if (isXFAModelLoaded(eType, bRemove)) {
			setXFAPacketLoaded(eType, ! bRemove);
			return true;
		}
		setXFAPacketLoaded(eType, false);
		return false;
	}

	/*
	 * Verify that the model(s) specified have been loaded.
	 */
	boolean isPacketLoaded(String oPacketList, boolean bRemove /* =false */) {
		//
		// Loop through each of the packets in the packet list
		//
		if (oPacketList != null) {
			if (oPacketList.length() == 0 || oPacketList.equals("*"))
				return true;
			if (oPacketList.charAt(0) == '-')
				return true;
			StringTokenizer sTemp = new StringTokenizer(oPacketList);
			while (sTemp.hasMoreTokens()) {
				String sToken = sTemp.nextToken();
				int eType = getXFAModelType(sToken);
				if (! isPacketLoaded(eType, bRemove)) {
					if (! bRemove)
						return false;
				}
			}
		}
		return true;
	}

	/*
	 * Determine if the specified XFA Model exists in the XDP, note that the
	 * model has to be loaded from the XDP to determine this.
	 */
	boolean isXFAModelInXDP(int eType, boolean bMergeConfig /* =false */) {
		if (moXDPStream == null) {
			Node oContextNode = getContextNode();
			if (oContextNode != null) {
				Node resolvedNode = oContextNode.resolveNode(XFA.URI);
				if (resolvedNode instanceof ConfigurationValue) {
					// Use the source specified in the config model.
					ConfigurationValue oConfigurationValue
									= (ConfigurationValue) resolvedNode;
					String sConfigSourceFile
							= oConfigurationValue.getValue().toString();
					if (!StringUtils.isEmpty(sConfigSourceFile))
						setXFAInput(XDP, sConfigSourceFile);
				}
			}
		}
		if (moXDPStream != null) {
			XMLStorage oXMLStorage = new XMLStorage();
			//
			// Return if we've already loaded the packet.
			//
			if (getXFAPacketLoaded(eType))
				return true;
			//
			// remove old config from the appmodel,
			// this way if the xdp contains a config section
			// it will not over write the settings passed via command line
			// or config options.
			ConfigurationModel oOldConfig = null;
			if (bMergeConfig) {
				oOldConfig = getConfigModel();
				oOldConfig.remove();
			}
			//
			// Load the packet from the XDP.
			//
			AppModel oApp = getAppModel();
			if (eType == DATA) {
				setDataLoadOptions(oXMLStorage);
				String sLoadOptions = "Model=\"" + STRS.DATASETS + '\"';
				oXMLStorage.loadModel(oApp, moXDPStream, sLoadOptions, null);
			}
			else {
				setPacketList(getXFAModelName(eType));
				oApp.setPacketList(getPacketList());
				oXMLStorage.loadXDP(oApp, moXDPStream, null, null, true);
			}
			//
			// Merge the old config on top of the one found in the xdp
			//
			if (bMergeConfig) {
				ConfigurationModel oNewConfig
					= ConfigurationModel.getConfigurationModel(oApp, true);
				oNewConfig.mergeModel(oOldConfig);	
			}
			//
			// Verify that the packet got loaded properly.
			//
			if (isPacketLoaded(eType, false))
				return true;
		}
		return false;
	}

	/*
	 * isXFAModelLoaded - Verify that the model model has been loaded.
	 */
	@FindBugsSuppress(code="ES")
	boolean isXFAModelLoaded(int eType, boolean bRemove /* =false */) {
		String aExpectedModelName = null;
		if (eType == DATA)
			aExpectedModelName = STRS.DATASETS;
		else
			aExpectedModelName = getXFAModelName(eType);
		
		for (Node oChild = getAppModel().getFirstXFAChild(); oChild != null; oChild = oChild.getNextXFASibling()) {
			if (oChild.getName() == aExpectedModelName) {
				if (bRemove) {
					oChild.remove();
					return true;
				}
				
				if (oChild.getFirstXFAChild() != null) {
					// Data is special case, we need to look one
					// extra level for the data node.
					if (eType == DATA) {
						if (oChild.getFirstXFAChild().getFirstXFAChild() == null)
							break;
					}
					return true;
				}
			}
		}
		return false;
	}

	boolean isXFAModelRequired(int eType) {
		switch (eType) {
		case XDC:
		case CONFIG:
		case TEMPLATE:
			return true;
		case DATA:
		case SOURCESET:
		case CONNECTIONSET:
		case XDP:
		default:
			return false;
		}
	}

    /**
	 * Load a stream of XFA Model contents into the app model.
	 *
 	 * @exclude from published api.
	 */
	protected boolean loadXFAModel(InputStream is,
										String oPacketList,
											boolean bReload) {
		//
		// Have to resolve general loadXDP issues such as how to specify
		// an XSL for each specific model.
		//
		XMLStorage oXMLStorage = new XMLStorage();
		//
		// Set the packetlist to filter on.
		//
		if (oPacketList != null) {
			setPacketList(oPacketList);
			getAppModel().setPacketList(oPacketList);
			if (bReload)
				isPacketLoaded(oPacketList, true);
		}
		//
		// mark current position in case we need to rewind.
		//
		if (is.markSupported())
			is.mark(Integer.MAX_VALUE);
		//
		// Attempt to load the XFA Model(s).
		//
		if (! oXMLStorage.loadXDP(getAppModel(), is, null, null, true)) {
			// not in xdp format,  so try loading it as data if allowed
			if (oPacketList == null
			|| oPacketList.length() == 0
			|| oPacketList.equals("*")
			|| oPacketList.contains(STRS.DATASETS)) {
				StringBuilder sLoadOptions = new StringBuilder();
				sLoadOptions.append("Model=\"");
				sLoadOptions.append(XFA.DATA);
				sLoadOptions.append('\"');
				//
				// Set XSL options from config, if present.
				//
				StringBuilder sDebugXSL = new StringBuilder();
				getXSLOptions(XFA.DATA, sLoadOptions, sDebugXSL);
				//
				// Set other config data loading options.
				//
				setDataLoadOptions(oXMLStorage);
				//
				// Trying rewinding the input source.
				//
				try {
					is.reset();
				} catch (IOException e) {
					return false;
				}
				//
				// Load into data model.
				//
				oXMLStorage.loadModel(getAppModel(), is,
												sLoadOptions.toString(),
														sDebugXSL.toString());
				if (getDataModel() == null)
					return false;
			}
		}
		//
		// Verify that the specified packets got loaded properly.
		//
		if (! isPacketLoaded(oPacketList, false))
			return false;
		return true;
	}

    /**
	 * Load the specified XFA Model type into the app model.
	 *
 	 * @exclude from published api.
	 */
	protected boolean loadXFAModel(int eType, boolean bReload /* = false */) {
		StringBuilder sSOMName = new StringBuilder();
		//
		// Verify that there is a valid input source...
		// note that this will load the model
		// from the XDP if that it the source.
		//
		InputStream oInputStream = resolveModelInput(eType, sSOMName);		
		if (oInputStream == null)
			return false;
		//
		// Output a trace message for the model.
		//
		outputTraceMessage(ResId.GeneralTraceLoadDom, getXFAModelName(eType));
		//
		// Load the data from the specified stream
		//
		XMLStorage oXMLStorage = new XMLStorage();
		if (bReload)
			isPacketLoaded(eType, true);
		//
		// If the model was not loaded from the xdp then load it.
		//
		if (! getXFAPacketLoaded(eType)) {
			// Set the load options to only load the specified model.
			String sExpectedModelName;
			if (eType == DATA)
				sExpectedModelName = STRS.DATASETS;
			else
				sExpectedModelName = getXFAModelName(eType);
			StringBuilder sLoadOptions = new StringBuilder();
			sLoadOptions.append("Model=\"");
			sLoadOptions.append(sExpectedModelName);
			sLoadOptions.append('\"');
			//
			// Get any XSL specific info from the config DOM if specified.
			//
			StringBuilder sDebugXSL = new StringBuilder();
			getXSLOptions(sSOMName.toString(), sLoadOptions, sDebugXSL);
			//
			// Special model-specific handling...
			// TODO: Move this behaviour elsewhere.
			//
			if (eType == TEMPLATE) {
				// Normalize the template stream
			// JavaPort: all that XMLNormalize does over and above what
			//	we already handle is decode base64 gzipped files.
			//	We aren't planning to support this legacy feature.
			//	XMLNormalize oNormalXML(oInputStream, false);
			//	oInputStream = oNormalXML.output();
			}
			else if (eType == DATA) {
				// Set Data load options for the data stream
				setDataLoadOptions(oXMLStorage);
			}
			//
			// Load the model.
			//
			oXMLStorage.loadModel(getAppModel(), oInputStream,
												sLoadOptions.toString(),
													sDebugXSL.toString());
			//
			// OK, the model is loaded.  There's no reason to hold onto
			// a file handle, so close it.  We will not touch
			// XDP files, as there is special processing done for XDP's
			// that contain PDF's.
			//
			if (eType == XDP) {
				if (moXDPStream != null) {
					try {
						moXDPStream.close();
					}
					catch (IOException e) {
					}
					moXDPStream = null;
				}
			}
			//
			// Ensure that the proper model got loaded...
			//
			if (isXFAModelLoaded(eType, false))
				return true;
			MsgFormatPos formatError
							= new MsgFormatPos(ResId.XFAAgentWrongFileType);
			formatError.format(getXFAModelName(eType));
			throw new ExFull(formatError);
		}
		return true;
	}

    void outputTraceMessage(int nResId, String sInput) {
		if (goGeneralTrace.isEnabled(1)) {
			MsgFormatPos oFormatPos = new MsgFormatPos(nResId);
			if (sInput.length() > 0) {
				oFormatPos.format(sInput);
			}
			goGeneralTrace.trace(1, oFormatPos);
		}
	}

	InputStream resolveModelInput(int eType, StringBuilder oSOMName) {
		//
		// Get the model input stream and SOM Name.
		//
		InputStream oInputStream = getXFAModelStream(eType);
		oSOMName.append(getXFAModelName(eType));
		//
		// Use the config file if the input stream is not already set.
		//
		if (oInputStream == null) {
			//
			// Check if we have an XFA model-specific file specified
			// in our config model first.
			//
			if (setConfigInputStream(eType))
				oInputStream = getXFAModelStream(eType);
			//
			// Now try the XDP if there was one specified.
			//
			if (oInputStream == null) {
				if (isXFAModelInXDP(eType, false)) {
					oInputStream = getXFAModelStream(XDP);
				}
			}
			if (oInputStream == null && isXFAModelRequired(eType)) {
				LogMessage oMessage = new LogMessage();
				MsgFormatPos formatError
					= new MsgFormatPos(getXFAModelMessageFileNotFound(eType));
				formatError.format(getXFAModelConfigURI(eType));
				oMessage.insertMessage(formatError,
											LogMessage.MSG_FATAL_ERROR, "");
				getMessenger().sendMessage(oMessage);
				return null;
			}
		}
		if (oInputStream != null) {
			if (isXFAModelRequired(eType)) {
				LogMessage oMessage = new LogMessage();
				MsgFormatPos formatError
					= new MsgFormatPos(getXFAModelMessageFileNotSpecified(eType));
				oMessage.insertMessage(formatError,
											LogMessage.MSG_FATAL_ERROR, "");
				getMessenger().sendMessage(oMessage);
			}
			return null;
		}
		return oInputStream;
	}

	/**
	 * Save the current XFADataModel instance to an output streamfile
	 * NOTE: same context node  as loadDataModel
	 */
	void saveDataModel(OutputStream oStream) {
		XMLStorage xml = new XMLStorage();
		// get the data model.
		Model oDataModel = getDataModel();
		Node oContextNode = getContextNode();
		if (oContextNode != null) {
			Node oResolvedNode
					= oContextNode.resolveNode("data.outputXSL.uri");
			if (oResolvedNode instanceof ConfigurationValue) {
				// grab the name of the output xsl script
				ConfigurationValue oConfigurationValue
									= (ConfigurationValue) oResolvedNode;
				String sFile = oConfigurationValue.getValue().toString();
				//
				// ensure the file exists
				//
				if (!StringUtils.isEmpty(sFile)) {
					File oFileID = new File(sFile);
					if (! oFileID.exists()) {
						throw new ExFull(new MsgFormatPos(ResId.XSLFileNotFound, sFile));
					}
					
					FileInputStream oXSLStream = null;
					try {
						//
						// Save data to temp file, then apply xsl 	
						//
						ByteArrayOutputStream oTempOutput = new ByteArrayOutputStream();
						xml.saveModelAs(oDataModel, oTempOutput, "");
						ByteArrayInputStream oTempInput = new ByteArrayInputStream(oTempOutput.toByteArray());
						//
						// Apply xsl on the stream.
						//
						oXSLStream = new FileInputStream(oFileID);
						XSLTranslator translator = new XSLTranslator(oXSLStream);
						//
						// translate specified stream into a the output file stream	
						//
						translator.process(oTempInput, oStream);
						return;  // done
					} catch (IOException e) {
						throw new ExFull(e);
					}
					finally {
						try {
							if (oXSLStream != null) oXSLStream.close();
						}
						catch (IOException ex) {
						}
					}
				}
			}
		}
		// save normaly
		xml.saveModelAs(oDataModel, oStream, "");
	}

	void saveSimpleXDP(String sPacketList, OutputStream oStream) {
		NodeList oNodesToSave = new ArrayNodeList();
		boolean bIncludeData = true;
		AppModel oAppModel = getAppModel();
		//			
		// get the models
		//			
		ConfigurationModel oConfigModel = getConfigModel();  //always
		TemplateModel oTemplateModel = getTemplateModel();	//always
	// JavaPort: not yet available.
	//	SourceSetModel oSSModel = getSourceSetModel();
		ConnectionSetModel oCSModel = getConnectionSetModel();
		//
		// Embed the config file.
		// get config ns
		String sConfigNS = ConfigurationModel.configurationNS();
		//	
		// create acrobat section
		// will set the validate attr
		//	
		Element oAcrobat = oConfigModel.createElement(oConfigModel, null,
										sConfigNS, XFA.ACROBAT, XFA.ACROBAT,
											null, 0, null);
		//
		// create common tag
		//
		Element oCommon = oConfigModel.createElement(oAcrobat, null,
											sConfigNS, XFA.COMMON, XFA.COMMON,
												null, 0, null);
		//
		// set the data options
		//
		Node oDataOptions = getContextNode().resolveNode("common.data");
		if (oDataOptions instanceof ConfigurationValue) {
			// Must be done before se modify config so we can set the xsl uri
			// for  all agents. If there is an input XSL file, embed it as well
			ConfigurationValue oConfigValue
				= (ConfigurationValue) oDataOptions.resolveNode("xsl.uri");
			if (oConfigValue != null && oConfigValue.getXFAChildCount() == 1) {
				String sXSLFile = oConfigValue.getValue().toString();
				File oXSLFileID = new File(sXSLFile);
				if (oXSLFileID.exists()) {
					FileInputStream oXSLStream = null;
					try {
						oXSLStream = new FileInputStream(oXSLFileID);
						Document oDoc = oAppModel.getDocument();
						Element oRoot  = oDoc.loadIntoDocument(oXSLStream);
						Node oChild  = oRoot.getFirstXMLChild();
						while (oChild != null) {
							if (oChild instanceof Element) {	
								//
								// add xsl packet to the xfa
								//
								Packet oDataInputXSL = new Packet(oAppModel, null);
								oDataInputXSL.setXmlPeer(oChild);
								
								//
								// set the id of the xsl
								//
								oDataInputXSL.setAttribute("XFADataInputXSL", "id");
								oNodesToSave.append(oDataInputXSL);
								break;
							}
							oChild = oChild.getNextXMLSibling();
						}
					} catch (IOException e) {
						throw new ExFull(e);
					}
					finally {
						try {
							if (oXSLStream != null) oXSLStream.close();
						}
						catch (IOException ex) {
						}
					}
				}
			}
			//
			// save the output xsl stream
			//
			oConfigValue = (ConfigurationValue)
									oDataOptions.resolveNode("outputXSL.uri");
			if (oConfigValue != null && oConfigValue.getXFAChildCount() == 1) {
				String sXSLFile = oConfigValue.getValue().toString();
				File oXSLFileID = new File(sXSLFile);
				if (oXSLFileID.exists()) {
					FileInputStream oXSLStream = null;
					try {
						oXSLStream = new FileInputStream(oXSLFileID);
						Document oDoc = oAppModel.getDocument();
						Element oRoot = oDoc.loadIntoDocument(oXSLStream);
						Node oChild  = oRoot.getFirstXMLChild();
						while (oChild != null) {
							if (oChild instanceof Element) {	
								//
								// add xsl packet to the xfa
								//
								Packet oDataOutputXSL
									= new Packet(oAppModel, oChild);
								//
								// set the id of the xsl
								//
								oDataOutputXSL.setAttribute("XFADataOutputXSL",
																		"id");
								oNodesToSave.append(oDataOutputXSL);
								break;
							}
							oChild = oChild.getNextXMLSibling();
						}
					} catch (IOException e) {
						throw new ExFull(e);
					}
					finally {
						try {
							if (oXSLStream != null) oXSLStream.close();
						}
						catch (IOException ex) {
						}
					}
				}
			}
			if (mbIsDataIncremental) {
				bIncludeData = false;
			}
			//
			// clone common section and append it to the acrobat section.
			//
			Node oClone
					= ((ConfigurationValue) oDataOptions).clone(null, true);
			oCommon.getNodes().append(oClone);
			oNodesToSave.append(oConfigModel);
		}
		//
		// set the template options
		//
		Node oTemplateOptions = getContextNode().resolveNode("common.template");
		if (oTemplateOptions instanceof ConfigurationValue) {
			// clone common section and append it to the acrobat section.
			Node oClone
					= ((ConfigurationValue) oTemplateOptions).clone(null, true);
			oCommon.getNodes().append(oClone);
		}
		//
		// embed the template
		//
		oNodesToSave.append(oTemplateModel);
		//
		// Add the sourceSet model (if there is one) to the PDF.
		//
		// JavaPort: no support for SourceSetModel
//		if (oSSModel != null) {
//			oNodesToSave.append(oSSModel);
//		}
		//
		// Add the connection Set model (if there is one) to the PDF.
		//
		if (oCSModel != null) {
			oNodesToSave.append(oCSModel);
		}
		if (bIncludeData) { // always have dataModel.
			DataModel oDataModel = getDataModel();
			if (oDataModel != null) {
				// Add the data file (if there was one) to the PDF.
				oNodesToSave.append(oDataModel);
			// JavaPort: TODO
			//	// Just to delineate this workaround, which should be
			//	// resolved more elegantly after alpha...
			//	// In XDP format, we need the entire data structure
			//	// (datasets/data/root) to be present and connected
			//	// to the same XML DOM document.  If we add
			//	// a peer to the root element, this structure will be
			//	// created automatically for us by xfadata.  If we
			//	// then remove the node this work is not undone.
			//	oDataModel.getAliasNode().getImpl().connectPeerToParent();
			//	// force recalc of record depth
			//	oDataModel.getDataWindow().getImpl().resetRecordDepth();
			}
		}
		//
		// Mark the encryption passwords as transient - they are never
		// to be saved out in the xfa stream!
		//
		Element oUser = null;
		Element oMaster = null;
		Node oPDFEncryption = oConfigModel.resolveNode("$config.present.pdf.encryption");
		if (oPDFEncryption instanceof Element) {
			if (((Element) oPDFEncryption).isPropertySpecified(XFA.USERPASSWORDTAG, true, 0)) {
				oUser = ((Element) oPDFEncryption).getElement(XFA.USERPASSWORDTAG, false, 0, false, false);
				oUser.isHidden(true);
			}
			if (((Element) oPDFEncryption).isPropertySpecified(XFA.MASTERPASSWORDTAG, true, 0)) {
				oMaster = ((Element) oPDFEncryption).getElement(XFA.MASTERPASSWORDTAG, false, 0, false, false);
				oMaster.isHidden(true);
			}
		}
		//
		// Allow fine control over which packets are saved.  Note that
		// we're resetting oNodesToSave if xdp.packets is specified, which
		// makes some of the above code a waste.  However it keeps this
		// feature much cleaner if we keep it here, and the waste is minimal.
		//
		String sPackets = sPacketList;
		if (sPackets.length() == 0) {
			Node oPackets = getContextNode().resolveNode("xdp.packets");
			if (oPackets instanceof ConfigurationValue) {
				ConfigurationValue oConfigurationValue
										= (ConfigurationValue) oPackets;
				sPackets = oConfigurationValue.getValue().toString();
			}
		}
		if (sPackets.length() != 0) {
			boolean bAllPackets = (sPackets.equals("*"));
			oNodesToSave = new ArrayNodeList();	// reset list
			for (Node oChild = oAppModel.getFirstXFAChild(); oChild != null; oChild = oChild.getNextXFASibling()) {
				//
				// See if the packet's name is in the list of packets to save.
				// Models are considered to be packets here, for consistency
				// with XDPTK.
				//
				if (bAllPackets) {
					oNodesToSave.append(oChild);
					continue;
				}
				String packetName = oChild.getName();
				StringTokenizer sPacketsCopy = new StringTokenizer(sPackets);
				while (sPacketsCopy.hasMoreTokens()) {
					String sToken = sPacketsCopy.nextToken();
					if (sToken.equals(packetName)) {
						oNodesToSave.append(oChild);
						break;
					}
				}
			}
		}
		//
		//Save the nodes
		//
		XMLStorage oStorage = new XMLStorage();
		oStorage.saveAggregate(null, oStream, oNodesToSave, "");
		//	
		// Re-enable the passwords (?)
		//	
		if (oUser != null)
			oUser.isHidden(false);
		if (oMaster != null)
			oMaster.isHidden(false);
	}

    boolean setConfigInputStream(int eType) {
		String sConfigURI = getXFAModelConfigURI(eType);
		Node oContextNode = getContextNode();
		if (oContextNode != null && !StringUtils.isEmpty(sConfigURI)) {
			Node resolvedNode = oContextNode.resolveNode(sConfigURI);
			if (resolvedNode instanceof ConfigurationValue) {
				// Use the source specified in the config model.
				ConfigurationValue oConfigurationValue
										= (ConfigurationValue) resolvedNode;
				String sConfigSourceFile
							= oConfigurationValue.getValue().toString();
				if (!StringUtils.isEmpty(sConfigSourceFile)) {
					setXFAInput(eType, sConfigSourceFile);
					return true;
				}
			}
		}
		return false;
	}

	/*
	 * Set data load options. 
	 * The section of the configuration file we are interested in:
	 *	
	 *	
	 *	
	 *		c:\dp\xfd\flatten.xml
	 *		
	 *		0 
	 *		
	 *		
	 *		
	 *			
	 *		
	 *		
	 *		
	 *		ignore 
	 *		
	 *	
	 *	
	 *	
	 */
	void setDataLoadOptions(XMLStorage oXMLStorage) {
		Node oContextNode = getContextNode();
		//	
		// set the options
		//	
		Node oResolvedNode = null;
		// Reset data loading options.
		// Watson# 2420783.  Appending to existing list of data transformation options had
		// a severe performance impact for heterogenous batches (where the data loading options
		// are applied each time a template is loaded [i.e. once per record]).  So now, the
		// call to reset() will clear this existing list rather than appending to it.
		moDataFactory.reset();
		if (oContextNode != null) {
			oResolvedNode = oContextNode.resolveNode("data");
			if (oResolvedNode != null) {
				if (oResolvedNode.getFirstXFAChild() == null)
					return;
				StringBuilder sExclNS = new StringBuilder();
				for (Node node = oResolvedNode.getFirstXFAChild(); node != null; node = node.getNextXFASibling()) {
					if (!(node instanceof Element))
						continue;
					Element child = (Element)node;
					String sName = child.getName();
					if (sName.equals("transform")) {
						//Transformation options are in the form
						//name1='value1' name2='value2' ....
						String sOptionName = "data_transform";
						StringBuilder sTransform = new StringBuilder();
						sTransform.append(XFA.REF);
						sTransform.append("=\'");
						sTransform.append(child.getAttribute(XFA.REFTAG).toString());
						sTransform.append('\'');
						for (ConfigurationValue oConfigVal = (ConfigurationValue)child.getFirstXFAChild(); child != null; child = (ConfigurationValue)child.getNextXFASibling()) {
							sTransform.append(' ');
							Attribute oValue = oConfigVal.getValue();
							sTransform.append(oConfigVal.getName());
							sTransform.append("=\'");
							sTransform.append(oValue.toString());
							sTransform.append('\'');
						}
						moDataFactory.setOption(sOptionName,
											sTransform.toString(), false);
					}
					else if (! child.isContainer()) {
						String sValue = "";
						if (child instanceof ConfigurationValue)
							sValue = ((ConfigurationValue) child).getValue().toString();
						if (sName.equals("uri")) {
							// we have already opened the data file
							continue; 
						}
						else if (sName.equals("excludeNS") && !StringUtils.isEmpty(sValue)) {
							//excludeNS is 0-N, so accummulate namespaces
							if (sExclNS.length() != 0)
								sExclNS.append(' ');
							sExclNS.append(sValue);
							moDataFactory.setOption("excludeNS",
													sExclNS.toString(), false);
						}
						else if (!StringUtils.isEmpty(sValue)) {
							if (sName.equals(XFA.ADJUSTDATA))
								continue;
							//should check if it's an acceptable option
							moDataFactory.setOption(sName, sValue, false);
						}
					}
				}
			}
		}
	}

	/**
	 * Set the DataModel instance that this agent will use when executing.
	 * Implementation is deferred for the time being.
	 */
	void setDataModel(Model oModel) {
	}

	/*
	 * Set the list of XFA packets for the XDP.
	 */
    void setPacketList(String sPacketList) {
		msPacketList = sPacketList;
	}

	/**
	 * Store the input source for the various XFA models.
	 *
 	 * @exclude from published api.
	 */
	protected void setXFAInput(int eModel, String sInputFile) {
		
		if (StringUtils.isEmpty(sInputFile))
			return;
		
		InputStream oStream = null;
		try {
			oStream = (new URL(sInputFile)).openStream();
		} catch (Exception e) {
			try {
				oStream = new FileInputStream(sInputFile);
			} catch (IOException f) {
			}
		}
		setXFAInput(eModel, oStream);
	}

	/**
	 * Store the input source for the various XFA models.
	 *
 	 * @exclude from published api.
	 */
	protected void setXFAInput(int eModel, InputStream oStream) {
		if (oStream != null) {
			switch (eModel) {
			case CONFIG:
				moConfigurationStream = oStream;
				break;
			case XDP:
				moXDPStream = oStream;
				break;
			}
		}
	}

	void setXFAPacketLoaded(int eType, boolean bLoaded) {
		switch (eType) {
		case XDC:
			mbXDPLoadedXDC = bLoaded;
			break;
		case CONFIG:
			mbXDPLoadedConfig = bLoaded;
			break;
		case TEMPLATE:
			mbXDPLoadedTemplate = bLoaded;
			break;
		case DATA:
			mbXDPLoadedData = bLoaded;
			break;
		case SOURCESET:
			mbXDPLoadedSourceSet = bLoaded;
			break;
		case CONNECTIONSET:
			mbXDPLoadedConnectionSet = bLoaded;
			break;
		case XSL:
			//mbXDPLoadedXSL = bLoaded;
			break;
		case LOCALESET:
			//mbXDPLoadedLocaleSet = bLoaded;
			break;
		case XDP:
		default:
			break;
		}
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy