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

org.xdef.impl.ChkNode Maven / Gradle / Ivy

There is a newer version: 42.2.13
Show newest version
package org.xdef.impl;

import java.io.File;
import java.io.InputStream;
import java.io.PrintStream;
import java.io.Writer;
import java.math.BigDecimal;
import java.net.InetAddress;
import java.net.URL;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Currency;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import javax.xml.xpath.XPathFunctionResolver;
import javax.xml.xpath.XPathVariableResolver;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.xdef.XDContainer;
import org.xdef.XDDocument;
import org.xdef.XDInput;
import org.xdef.XDOutput;
import org.xdef.XDParseResult;
import org.xdef.XDParser;
import org.xdef.XDPool;
import org.xdef.XDResultSet;
import org.xdef.XDValue;
import org.xdef.XDValueAbstract;
import static org.xdef.XDValueID.XD_BIGINTEGER;
import static org.xdef.XDValueID.XD_BOOLEAN;
import static org.xdef.XDValueID.XD_CONTAINER;
import static org.xdef.XDValueID.XD_DATETIME;
import static org.xdef.XDValueID.XD_DECIMAL;
import static org.xdef.XDValueID.XD_DOUBLE;
import static org.xdef.XDValueID.XD_DURATION;
import static org.xdef.XDValueID.XD_ELEMENT;
import static org.xdef.XDValueID.XD_LONG;
import static org.xdef.XDValueID.XD_PARSER;
import static org.xdef.XDValueID.XD_STRING;
import org.xdef.impl.code.CodeUniqueset;
import org.xdef.impl.code.DefBigInteger;
import org.xdef.impl.code.DefBoolean;
import org.xdef.impl.code.DefContainer;
import org.xdef.impl.code.DefCurrency;
import org.xdef.impl.code.DefDate;
import org.xdef.impl.code.DefDecimal;
import org.xdef.impl.code.DefDouble;
import org.xdef.impl.code.DefDuration;
import org.xdef.impl.code.DefElement;
import org.xdef.impl.code.DefGPSPosition;
import org.xdef.impl.code.DefIPAddr;
import org.xdef.impl.code.DefInStream;
import org.xdef.impl.code.DefLocale;
import org.xdef.impl.code.DefLong;
import org.xdef.impl.code.DefNull;
import org.xdef.impl.code.DefOutStream;
import org.xdef.impl.code.DefPrice;
import org.xdef.impl.code.DefString;
import org.xdef.impl.xml.KNamespace;
import org.xdef.model.XMData;
import org.xdef.model.XMDefinition;
import org.xdef.model.XMElement;
import org.xdef.model.XMNode;
import org.xdef.model.XMVariableTable;
import org.xdef.msg.XDEF;
import org.xdef.proc.XXNode;
import org.xdef.sys.ArrayReporter;
import org.xdef.sys.GPSPosition;
import org.xdef.sys.Price;
import org.xdef.sys.Report;
import org.xdef.sys.ReportWriter;
import org.xdef.sys.SDatetime;
import org.xdef.sys.SDuration;
import org.xdef.sys.SPosition;
import org.xdef.sys.SReporter;
import org.xdef.sys.SRuntimeException;
import org.xdef.xml.KXmlUtils;
import org.xdef.xon.XonNames;
import static org.xdef.xon.XonNames.X_ARRAY;
import static org.xdef.xon.XonNames.X_MAP;
import org.xdef.xon.XonUtils;
import static org.xdef.xon.XonNames.X_VALUE;

/** The abstract class for checking objects.
 * @author Vaclav Trojan
 */
public abstract class ChkNode extends XDValueAbstract implements XXNode {

	/** The name of element model. */
	final String _name;
	/** Root check Document. */
	final ChkDocument _rootChkDocument;
	/** The parent check node. */
	final ChkNode _parent;
	/** The level of element model. */
	final int _level;
	/** Actual element model. */
	XElement _xElement;
	/** Actual w3c.dom.Node. */
	Node _node;
	/** Actual w3c.dom.Element. */
	Element _element;
	/** Actual Node position of the node as XPath expression string. */
	String _xPos;
	/** Variable block */
	XDValue[] _variables;
	/** user object. */
	Object _userObject;
	/** Element used as source reference in compose mode. */
	Element _sourceElem;
	/** Iterator used in compose mode. */
	XDResultSet _iterator;
	/** Script code processor */
	XCodeProcessor _scp;
	/** Result of type parser. */
	XDParseResult _parseResult;
	/** List of objects to be managed before dispose. */
	private List _finalList;
	/** Actual number of errors.*/
	int _errCount;

	/** Create the new instance of ChkNode.
	 * @param name The name of node.
	 * @param parent The parent node.
	 */
	ChkNode(final String name, final ChkNode parent) {
//		_xElement=null; _node=null; _element=null;_xPos=null; //Java makes it!
//		_variables=null; _userObject=null; _sourceElem=null; //Java makes it!
//		_iterator= null; _scp=null; //Java makes it!
		_name = name;
		_parent = parent;
		if (parent == null) {//root ChkDocument
			_rootChkDocument = (ChkDocument) this;
			_level = -1;
		} else {
			_rootChkDocument = parent._rootChkDocument;
			_scp = _rootChkDocument._scp; //accelerate
			_userObject = parent._userObject; //propagate user object
			_level = parent._level + 1;
		}
	}

	/** Add the object to final list.
	 * @param x the object to be added.
	 */
	final void addToFinalList(final XDValue x) {
		if (_finalList == null) {
			_finalList = new ArrayList<>();
		}
		_finalList.add(x);
	}

	/** Get list of object to be managed before dispose.*/
	final List getFinalList() {return _finalList;}

	@Override
	/** Get name of the X-model.
	 * @return The name of node.
	 */
	public final String getXXName() {return _name;}

	@Override
	/** Get namespace URI of the X-model.
	 * @return namespace URI of node or null.
	 */
	public String getXXNSURI() {
		return (_xElement == null) ? null : _xElement.getNSUri();
	}

	@Override
	/** get User object.
	 * @return The user object.
	 */
	public final Object getUserObject() {return _userObject;}

	@Override
	/** set User object.
	 * @param obj The user object.
	 */
	public final void setUserObject(final Object obj) {_userObject = obj;}

	@Override
	/** Set named user object.
	 * @param id identifier of the object.
	 * @param obj user object.
	 * @return previous value of the object or null.
	 */
	public final Object setUserObject(final String id, final Object obj) {
		return _scp.setUserObject(id, obj);
	}

	@Override
	/** Remove named user object.
	 * @param id identifier of the object.
	 * @return value of the object or null.
	 */
	public Object removeUserObject(final String id) {
		return _scp.removeUserObject(id);
	}

	@Override
	/** Get named user object.
	 * @param id identifier of the object.
	 * @return value of the object or null.
	 */
	public final Object getUserObject(final String id) {
		return _scp.getUserObject(id);
	}

	@Override
	/** Return parent node.
	 * @return The parent node.
	 */
	public final XXNode getParent() {return _parent;}

	/** Get nesting level the check node (model). The level of ChkDocument
	 * is -1.
	 * @return The node level.
	 */
	public final int getLevel() {return _level;}

	/** get StdOut.
	 * @return XDOutput object used as standard output stream.
	 */
	public final XDOutput getStdOut() {return _scp.getStdOut();}

	/** get StdErr.
	 * @return XDOutput object used as standard error stream.
	 */
	public final XDOutput getStdErr() {return _scp.getStdErr();}

	/** get StdIn.
	 * @return XDOutput object used as standard input stream.
	 */
	public final XDInput getStdIn() {return _scp.getStdIn();}

	/** Set standard output stream.
	 * @param out PrintStream object.
	 */
	public final void setStdOut(final PrintStream out) {
		setStdOut(new DefOutStream(out));
	}

	/** Set standard output stream.
	 * @param out PrintStream object.
	 */
	public void setStdOut(Writer out) {setStdOut(new DefOutStream(out));}

	/** Set standard output stream.
	 * @param out XDOutput object.
	 */
	public final void setStdOut(final XDOutput out) {_scp.setStdOut(out);}

	/** Set standard input stream.
	 * @param in InputStream object.
	 */
	public final void setStdIn(final InputStream in) {
		setStdIn(new DefInStream(in, false));
	}

	/** Set standard input stream.
	 * @param in XDInputStream object.
	 */
	public final void setStdIn(final XDInput in) {_scp.setStdIn(in);}

	/** Get default table with references IDS (used internally in the
	 * processor of XScript).
	 * @return default table with references IDS or null.
	 */
	public final CodeUniqueset getIdRefTable() {return _scp.getIdRefTable();}

	/** Set source element as context for create mode.
	 * @param sourceElem source element to be set (create mode).
	 */
	public final void setCreateContext(final Element sourceElem) {
		_sourceElem = sourceElem;
	}

	/** Get actual source context for create mode.
	 * @return source context or null if not available.
	 */
	public final Object getCreateContext() {return _sourceElem;}

	final void debugXPos(final char action) {
		if (_scp.isDebugMode()) {
			if (_scp.getDebugger().hasXPos(action + _xPos)) {
				_scp.getDebugger().debug(this, null, -1, -1, null, null,
					getXDPool().getDebugInfo(), null, (byte) 0);
			}
		}
	}

	@Override
	/** Get actual source context for create mode.
	 * @return source context or null if not available.
	 */
	public final XDValue getXDContext() {
		if (_sourceElem != null) {
			return new DefElement(_sourceElem);
		}
		return null;
	}

	@Override
	/** Set value from argument as context for create mode.
	 * @param xdc context to be set (create mode).
	 */
	public final void setXDContext(final XDContainer xdc) {
		if (xdc != null && xdc.getXDItemsNumber() == 1 &&
			xdc.getXDItem(0).getItemId() == XD_ELEMENT) {
			_sourceElem = xdc.getXDItem(0).getElement();
			return;
		}
		_sourceElem = xdc == null ? null : xdc.toElement(null, "_");
	}

	@Override
	/** Set source element as context for create mode.
	 * @param xdc context to be set (create mode).
	 */
	public final void setXDContext(final XDResultSet xdc) {_iterator = xdc;}

	@Override
	/** Set source element as context for create mode.
	 * @param node XML node (Element or a Node). If this argument is not an
	 * Element then it represents Document element of owner document.
	 */
	public final void setXDContext(final Node node) {
		if (node == null) {
			_sourceElem = null;
		} else if (node.getNodeType() == Node.ELEMENT_NODE) {
			_sourceElem = (Element) node;
		} else if (node.getNodeType() == Node.DOCUMENT_NODE) {
			_sourceElem = ((Document) node).getDocumentElement();
		} else {
			_sourceElem = node.getOwnerDocument().getDocumentElement();
		}
	}

	@Override
	/** Set XON/JSON data as context for create mode.
	 * @param data the XON/JSON data. It can be either pathname or URL.
	 * @throws SRuntimeException if data is incorrect or if model is not found.
	 */
	public final void setXONContext(final String data)
		throws SRuntimeException {
		setXDContext(XonUtils.xonToXmlW(data));
	}

	@Override
	/** Set XON/JSON data as context for create mode.
	 * @param data the XON/JSON data. It can be either XON/JSON object or
	 * File, URL or InputStream with XON/JSON data* or XDResultSet
	 * or XML data to be converted to XON/JSON.
	 * @throws SRuntimeException if data is incorrect or if model is not found.
	 */
	public final void setXONContext(final Object data) throws SRuntimeException{
		Element e = null;
		if (data == null || data instanceof Map || data instanceof List
			|| data instanceof String || data instanceof Number
			|| data instanceof Boolean) {
			e = XonUtils.xonToXmlW(data);
		} else if (data instanceof File || data instanceof URL
			|| data instanceof InputStream || data instanceof String) {
			e = XonUtils.xonToXmlW( data);
		} else if (data instanceof Document) {
			e = ((Document) data).getDocumentElement();
		} else if (data instanceof Element){
			e = (Element) data;
		} else if (data instanceof XDResultSet) {
			_iterator = (XDResultSet) data;
			return;
		}
		if (e == null) {
			throw new SRuntimeException(XDEF.XDEF318); //Incorrect XON/JSON data
		}
		setXDContext(e);
	}

	@Override
	/** Set source element as context for create mode.
	 * @param source string with pathname, URL or source of XML node.
	 */
	public final void setXDContext(final String source) {
		setXDContext(KXmlUtils.parseXml(source));
	}

	@Override
	/** Get names of variables.
	 * @return array of names of variables.
	 */
	public final String[] getVariableNames() {
		XMVariableTable t=_rootChkDocument._xdef.getXDPool().getVariableTable();
		return  t.getVariableNames();
	}

	@Override
	/** Get XDDocument.
	 * @return XDDocument.
	 */
	public final XDDocument getXDDocument() {return _rootChkDocument;}

	@Override
	/** Get XDPool.
	 * @return XDPool.
	 */
	public final XDPool getXDPool() {
		return _rootChkDocument.getXMDefinition().getXDPool();
	}

	@Override
	/** Get value of variable from XMDefinition.
	 * @param name name of variable.
	 * @return XDValue object or null.
	 */
	public final XDValue getVariable(final String name) {
		return _scp.getVariable(name);
	}

	/** Find variable for setVariable (it Can't be final).
	 * @param name name of variable.
	 * @return suitable variable.
	 */
	private XVariable findVariable(final String name) {
		XPool xp = (XPool) _rootChkDocument._xdef.getXDPool();
		XVariable xv = xp.getVariable(name);
		if (xv == null) {
			xv = _rootChkDocument._xdef.findVariable(name);
		}
		if (xv != null) {
			if (xv.isFinal() && _scp.getVariable(name) != null) {
				//Variable '&{0}' is 'final'; the value can't be assigned
				throw new SRuntimeException(XDEF.XDEF562, name);
			}
			return xv;
		}
		//Variable '&{0}' doesn't exist
		throw new SRuntimeException(XDEF.XDEF563, name);
	}

	@Override
	/** Set variable.
	 * @param name name name of variable.
	 * @param value value to be set to the variable.
	 */
	public final void setVariable(final String name, final Object value) {
		if (value instanceof XDValue) {
			setVariable(name, (XDValue) value);
			return;
		}
		XVariable xv = findVariable(name);
		if (value == null) {
			_scp.setVariable(xv, DefNull.genNullValue(xv.getType()));
			return;
		}
		switch (xv.getType()) {
			case XD_CONTAINER:
				_scp.setVariable(xv, new DefContainer(value));
				return;
			case XD_DATETIME: {
				if (value instanceof SDatetime) {
					_scp.setVariable(xv, new DefDate((SDatetime) value));
					return;
				}
				if (value instanceof Calendar) {
					_scp.setVariable(xv, new DefDate((Calendar) value));
					return;
				}
				if (value instanceof String) {
					_scp.setVariable(xv, new DefDate((String) value));
					return;
				}
				break;
			}
			case XD_DURATION: {
				if (value instanceof String) {
					_scp.setVariable(xv, new DefDuration((String) value));
					return;
				}
				if (value instanceof SDuration) {
					_scp.setVariable(xv, new DefDuration((SDuration) value));
					return;
				}
				break;
			}
			case XD_ELEMENT: {
				Element e;
				if (value instanceof Node) {
					Node node = (Node) value;
					switch (node.getNodeType()) {
						case Node.DOCUMENT_NODE:
							e = ((Document)node).getDocumentElement();
							break;
						case Node.ELEMENT_NODE:
							e = (Element)node;
							break;
						default:
						//Value is not compatible with type of variable '&{0}'
						throw new SRuntimeException(XDEF.XDEF564, name);
					}
				} else if (value instanceof XDValue) {
					setVariable(name, (XDValue) value);
					return;
				} else if (value instanceof String) {
					e = KXmlUtils.parseXml((String) value).getDocumentElement();
				} else if (value instanceof File) {
					e = KXmlUtils.parseXml((File) value).getDocumentElement();
				} else if (value instanceof URL) {
					e = KXmlUtils.parseXml((URL) value).getDocumentElement();
				} else if (value instanceof InputStream) {
					e = KXmlUtils.parseXml(
						(InputStream) value).getDocumentElement();
				} else {
					//Value is not compatible with the type of variable '&{0}'
					throw new SRuntimeException(XDEF.XDEF564, name);
				}
				_scp.setVariable(xv, new DefElement(e));
				return;
			}
		}
		if (value instanceof String) {
			setVariable(name, (String) value);
		} else if (value instanceof Long) {
			setVariable(name, (Long) value);
		} else if (value instanceof Integer) {
			setVariable(name, ((Integer) value).longValue());
		} else if (value instanceof Double) {setVariable(name, (Double) value);
		} else if (value instanceof Float) {
			setVariable(name, ((Float) value).doubleValue());
		} else if (value instanceof Boolean) {
			setVariable(name, ((Boolean) value).booleanValue());
		} else if (value instanceof BigDecimal) {
			setVariable(name, ((BigDecimal) value));
		} else if (value instanceof Locale) {
			setVariable(name, (new DefLocale((Locale) value)));
		} else if (value instanceof GPSPosition) {
			setVariable(name, (new DefGPSPosition((GPSPosition) value)));
		} else if (value instanceof Price) {
			setVariable(name, (new DefPrice((Price) value)));
		} else if (value instanceof InetAddress) {
			setVariable(name, (new DefIPAddr((InetAddress) value)));
		} else if (value instanceof Currency) {
			setVariable(name,
				new DefCurrency(((Currency) value).getCurrencyCode()));
		} else {
			//Value is not compatible with the type of variable '&{0}'
			throw new SRuntimeException(XDEF.XDEF564, name);
		}
	}

	@Override
	/** Set variable.
	 * @param name name name of variable.
	 * @param value value to be set to the variable.
	 */
	public final void setVariable(final String name, final long value) {
		XVariable xv = findVariable(name);
		switch (xv.getType()) {
			case XD_DOUBLE:
				_scp.setVariable(xv, new DefDouble(value));
				return;
			case XD_LONG:
				_scp.setVariable(xv, new DefLong(value));
				return;
			case XD_DECIMAL:
				_scp.setVariable(xv, new DefDecimal(value));
				return;
			case XD_BIGINTEGER:
				_scp.setVariable(xv, new DefBigInteger(value));
				return;
			case XD_STRING:
				_scp.setVariable(xv, new DefString(String.valueOf(value)));
				return;
		}
		//Value is not compatible with the type of variable '&{0}'
		throw new SRuntimeException(XDEF.XDEF564, name);
	}

	@Override
	/** Set variable.
	 * @param name name name of variable.
	 * @param value value to be set to the variable.
	 */
	public final void setVariable(final String name, final double value) {
		XVariable xv = findVariable(name);
		switch (xv.getType()) {
			case XD_DOUBLE:
				_scp.setVariable(xv, new DefDouble(value));
				return;
			case XD_STRING:
				_scp.setVariable(xv, new DefString(String.valueOf(value)));
				return;
			case XD_DECIMAL:
				_scp.setVariable(xv, new DefDecimal(String.valueOf(value)));
				return;
		}
		//Value is not compatible with the type of variable '&{0}'
		throw new SRuntimeException(XDEF.XDEF564, name);
	}

	@Override
	/** Set variable.
	 * @param name name name of variable.
	 * @param value value to be set to the variable.
	 */
	public final void setVariable(final String name, final boolean value) {
		XVariable xv = findVariable(name);
		switch (xv.getType()) {
			case XD_BOOLEAN:
				_scp.setVariable(xv, new DefBoolean(value));
				return;
			case XD_STRING:
				_scp.setVariable(xv, new DefString(String.valueOf(value)));
				return;
		}
		//Value is not compatible with the type of variable '&{0}'
		throw new SRuntimeException(XDEF.XDEF564, name);
	}

	/** Set variable.
	 * @param name name name of variable.
	 * @param value XDValue to be set.
	 */
	private void setVariable(final String name, final XDValue value) {
		XVariable xv = findVariable(name);
		if (xv.getType() == value.getItemId()) {
			_scp.setVariable(xv, value);
		} else {
			switch (xv.getType()) {
				case XD_CONTAINER:
					_scp.setVariable(xv, new DefContainer(value));
					return;
				case XD_STRING:
					setVariable(name, value.toString());
					return;
				case XD_DOUBLE:
					if (value.getItemId() == XD_LONG) {
						setVariable(name, value.doubleValue());
						return;
					}
					break;
				case XD_LONG:
					if (value.getItemId() == XD_DOUBLE) {
						setVariable(name, value.longValue());
						return;
					}
					break;
				case XD_BOOLEAN:
					if (value.getItemId() == XD_STRING) {
						_scp.setVariable(xv, new DefBoolean(value.toString()));
						return;
					}
					break;
				case XD_PARSER:
					_scp.setVariable(xv, (XDParser) value);
					return;
			}
			//Value is not compatible with the type of variable '&{0}'
			throw new SRuntimeException(XDEF.XDEF564, name);
		}
	}

	/** Set variable.
	 * @param name name name of variable.
	 * @param value DefValue to be set.
	 */
	private void setVariable(final String name, final String value) {
		XVariable xv = findVariable(name);
		switch (xv.getType()) {
			case XD_STRING:
			case XD_CONTAINER:
				_scp.setVariable(xv, new DefString(value));
				return;
			case XD_BOOLEAN:
				_scp.setVariable(xv, new DefBoolean(value));
				return;
			case XD_DOUBLE:
				_scp.setVariable(xv, new DefDouble(value));
				return;
			case XD_LONG:
				_scp.setVariable(xv, new DefLong(value));
				return;
			case XD_DECIMAL:
				_scp.setVariable(xv, new DefDecimal(value));
				return;
			case XD_BIGINTEGER:
				_scp.setVariable(xv, new DefBigInteger(value));
				return;
			case XD_ELEMENT:
				_scp.setVariable(xv, new DefElement(
					KXmlUtils.parseXml(value).getDocumentElement()));
				return;
		}
		//Value is not compatible with the type of variable '&{0}'
		throw new SRuntimeException(XDEF.XDEF564, name);
	}

	/** Set variable.
	 * @param name name name of variable.
	 * @param value value to be set to the variable.
	 */
	private void setVariable(final String name, final BigDecimal value) {
		XVariable xv = findVariable(name);
		switch (xv.getType()) {
			case XD_LONG:
				_scp.setVariable(xv, new DefLong(value.longValue()));
				return;
			case XD_DOUBLE:
				_scp.setVariable(xv, new DefDouble(value.doubleValue()));
				return;
			case XD_DECIMAL:
				_scp.setVariable(xv, new DefDecimal(value));
				return;
			case XD_STRING:
				_scp.setVariable(xv, new DefString(value.toString()));
				return;
		}
		//Value is not compatible with the type of variable '&{0}'
		throw new SRuntimeException(XDEF.XDEF564, name);
	}

	/** Store model variable.
	 * @param name name of variable.
	 * @param val value to be stored.
	 */
	abstract void storeModelVariable(final String name, final XDValue val);

	/** Store  model variable.
	 * @param name name of variable.
	 * @return loaded value.
	 */
	abstract XDValue loadModelVariable(final String name);

	@Override
	public abstract KNamespace getXXNamespaceContext();

	@Override
	public final XPathFunctionResolver getXXFunctionResolver() {
		return _scp._functionResolver;
	}

	@Override
	public final XPathVariableResolver getXXVariableResolver() {
		return _scp._variableResolver;
	}

////////////////////////////////////////////////////////////////////////////////
// Methods to retrieve values from checked tree.
////////////////////////////////////////////////////////////////////////////////

	/** Get document with root element.
	 * @return The Document object.
	 */
	public final Document getDocument() {return _rootChkDocument._doc;}

	/** Get document element.
	 * @return root element of the document.
	 */
	public final Element getDocumentElement() {
		return _rootChkDocument._element;
	}

	/** Increase reference counter by one.
	 * @return The increased reference number.
	 */
	abstract int incRefNum();

	/** Get occurrence of actual node
	 * @return The reference number.
	 */
	abstract int getOccurrence();

	/** Decrease reference counter by one.
	 * @return The increased reference number.
	 */
	abstract int decRefNum();

	/** Get reference counter of actual definition
	 * @return The reference number.
	 */
	abstract int getRefNum();
	/** Get ChkElement assigned to this node.
	 * @return ChkElement assigned to this node.
	 */
	abstract ChkElement getChkElement();

	/** Get Element value assigned to this node.
	 * @return Element value assigned to this node.
	 */
	public abstract Element getElemValue();

	@Override
	/** Get actual element.
	 * @return The element.
	 */
	public final Element getElement() {return _element;}

	/** Assign Element value to this node.
	 * @param elem Element value to be assigned to this node.
	 */
	abstract void setElemValue(Element elem);

	@Override
	/** Get position of the node as a XPath expression string.
	 * @return position of the node as a XPath expression string.
	 */
	public final String getXPos() {return _xPos;}

	@Override
	/** Get source position.
	 * @return source position or null if position is not available.
	 */
	public SPosition getSPosition() {return _rootChkDocument._reporter;}

	/** Set position of the node as XPath expression.
	 * @param xPath string with position of the node as XPath expression.
	 */
	final void setXPos(final String xPath) {_xPos = xPath;}

	@Override
	public final String stringValue() {return "XXNode " + getXXName();}

////////////////////////////////////////////////////////////////////////////////
// Methods for reporting
////////////////////////////////////////////////////////////////////////////////

	@Override
	/** Get report writer assigned to the report generator.
	 * @return The report writer.
	 */
	public final ReportWriter getReportWriter() {
		return _rootChkDocument._reporter.getReportWriter();
	}

	@Override
	/** Copy temporary reports to global reporter.
	 * @return true if and only if temporary reporter contained errors before
	 * it was cleared.
	 */
	public final boolean copyTemporaryReports() {
		Report rep;
		while ((rep = _scp.getTemporaryReporter().getReport()) != null) {
			putReport(rep);
		}
		boolean result = _scp.getTemporaryReporter().errors();
		_scp.getTemporaryReporter().clear();
		return result;
	}

	@Override
	/** Clear temporary reporter. */
	public final void clearTemporaryReporter() {
		_scp.getTemporaryReporter().clear();
	}

	@Override
	/** Put message to temporary reporter.
	 * @param report report to be added to the temporary reporter.
	 */
	public final void putTemporaryReport(Report report) {
		ensurePosInfo(report);
		_scp.getTemporaryReporter().putReport(report);
	}

	@Override
	/** Remove report from temporary reporter.
	 * @param rep report to be removed.
	 * @return true if report was found and removed.
	 */
	public final boolean removeTemporaryReport(final Report rep) {
		return _scp.getTemporaryReporter().removeReport(rep);
	}

	@Override
	/** Get temporary reporter.
	 * @return ArrayReporter used as temporary reporter.
	 */
	public final ArrayReporter getTemporaryReporter() {
		return _scp.getTemporaryReporter();
	}

	@Override
	/** Check if temporary reporter has errors.
	 * @return true if temporary reporter has errors.
	 */
	public final boolean chkTemporaryErrors() {
		return _scp.getTemporaryReporter().errors();
	}

	@Override
	/** Set new temporary reporter.
	 * @param reporter new temporary reporter.
	 * @return ArrayReporter old temporary reporter.
	 */
	public final ArrayReporter setTemporaryReporter(ArrayReporter reporter) {
		ArrayReporter result = _scp.getTemporaryReporter();
		_scp.setTemporaryReporter(reporter);
		return result;
	}

	@Override
	/** Get SReporter of XDDocument.
	 * @return SReporter of XDDocument..
	 */
	public final SReporter getReporter() {return _rootChkDocument._reporter;}

	@Override
	/** Check if errors, fatal errors, light errors or warnings were reported.
	 * @return true if errors, fatal errors, light errors
	 * or warnings were reported.
	 */
	public boolean errorWarnings() {
		return _rootChkDocument._reporter.errorWarnings();
	}

	@Override
	/** Check if errors, fatal errors or light errors were reported.
	 * @return true if errors, fatal errors or light errors were
	 * reported.
	 */
	public boolean errors() {return _rootChkDocument._reporter.errors();}

	@Override
	/** Put fatal error message with modification parameters.
	 * @param id The message id.
	 * @param msg The message text.
	 * @param mod Message modification parameters.
	 */
	public final void fatal(final String id,
		final String msg,
		final Object... mod) {
		putReport(Report.fatal(id, msg, mod));
	}

	@Override
	/** Put error message with modification parameters.
	 * @param id The message id.
	 * @param msg The message text.
	 * @param mod Message modification parameters.
	 */
	public final void error(final String id,
		final String msg,
		final Object... mod) {
		putReport(Report.error(id, msg, mod));
	}

	@Override
	/** Put warning message with modification parameters.
	 * @param id The message id.
	 * @param msg The message text.
	 * @param mod Message modification parameters.
	 */
	public final void warning(final String id,
		final String msg,
		final Object... mod) {
		putReport(Report.warning(id, msg, mod));
	}

	@Override
	/** Put fatal error message with modification parameters.
	 * @param id registered report id.
	 * @param mod Message modification parameters.
	 */
	public final void fatal(final long id, final Object... mod) {
		putReport(Report.fatal(id, mod));
	}

	@Override
	/** Put error message with modification parameters.
	 * @param id registered report id.
	 * @param mod Message modification parameters.
	 */
	public void error(final long id, final Object... mod) {
		putReport(Report.error(id, mod));
	}

	@Override
	/** Put warning message with modification parameters.
	 * @param id registered report id.
	 * @param mod Message modification parameters.
	 */
	public void warning(final long id, final Object... mod) {
		putReport(Report.warning(id, mod));
	}

	@Override
	/** Put report.
	 * @param report The report.
	 */
	public final void putReport(final Report report) {
		ensurePosInfo(report);
		_rootChkDocument._reporter.putReport(report);
	}

	@Override
	/** Get XMDefinition.
	 * @return X-definition of this document.
	 */
	public final XMDefinition getXMDefinition() {return _rootChkDocument._xdef;}

	@Override
	/** Get model of the processed object.
	 * @return model of the processed object (XMElement).
	 */
	public final XMElement getXMElement() {return _xElement;}

	@Override
	/** Get XDPosition of the processed element.
	 * @return XDPosition of the processed element.
	 */
	public final String getXDPosition() {
		String result = _xElement == null ? null : _xElement.getXDPosition();
		return result == null ? "" : result;
	}

////////////////////////////////////////////////////////////////////////////////
// Interface of XXNode.
////////////////////////////////////////////////////////////////////////////////

	@Override
	/** Get array of XXNodes or null.
	 * @return array of XXNodes or null.
	 */
	abstract public XXNode[] getChildXXNodes();

	// can't be final this method is overriden!
	abstract List getChkChildNodes();

	@Override
	/** Get parsed result of an attribute or text node.
	 * @return parsed result of an attribute or text node.
	 */
	public XDParseResult getParseResult() {return _parseResult;}

	@Override
	/** Get XON mode.
	 * @return XON mode or zero.
	 */
	public byte getXonMode() {return _xElement == null ? 0 : _xElement._xon;}

////////////////////////////////////////////////////////////////////////////////
// Message reporting
////////////////////////////////////////////////////////////////////////////////

	public final void ensurePosInfo(final Report report) {
		String mod = report.getModification();
		if (mod == null) {
			mod = getPosMod(getXDPosition(), getXPos());
		} else {
			String[] pos = getPosInfo(getXDPosition(), getXPos());
			if (pos[0] != null && !mod.contains("&{xdpos}")) {
				mod += "&{xdpos}" + pos[0];
			}
			if (pos[1] != null && !mod.contains("&{xpath}")) {
				mod += "&{xpath}" + pos[1];
			}
			SPosition sp;
			if (!mod.contains("&{line}") && (sp = getSPosition()) != null
				&& sp.getLineNumber() > 0) {
				mod += "&{line}" + sp.getLineNumber();
				int ndx = mod.indexOf("&{column}");
				if (ndx >= 0) {
					int i = mod.indexOf('&', ndx + 1);
					mod = i > 0 ? mod.substring(ndx, i) : mod.substring(ndx);
				}
				mod += "&{column}" + sp.getColumnNumber();
				if ((ndx = mod.indexOf("&{sysId}")) >= 0) {
					int i = mod.indexOf('&', ndx + 1);
					mod = i > 0 ? mod.substring(ndx, i) : mod.substring(ndx);
				}
				if (sp.getSysId() != null && !sp.getSysId().isEmpty()) {
					mod += "&{sysId}" + sp.getSysId();
				}
			}
		}
		if (!mod.equals(report.getModification())) {
			report.setModification(mod);
		}
	}

	/** Get name of item object element.
	 * @param xnode XMNode with value.
	 * @return name of element or empty string.
	 */
	private static String getItemName(final XMNode xnode) {
		XMData key = ((XMElement)xnode).getAttr(XonNames.X_KEYATTR);
		if (key != null) {
			XDValue keyVal = key.getFixedValue();
			if (keyVal != null) {
				return ".['"+keyVal.toString() + "']";
			}
		}
		return "";
	}

	/** Get X-position and XPath information. If it is XON/JSON, then create
	 * modified XON/JSON path.
	 * @param xpos X-position of model.
	 * @param xpath XPath of data (may be null).
	 * @return array with two items - the first one is X-position and the
	 * second one is XPath.
	 */
	final String[] getPosInfo(final String xpos, final String xpath) {
		String[] result = new String[]{xpos, xpath};
		if (xpos == null) {
			return result;
		}
		int ndx, ndx1, ndy, ndy1;
		if ((ndx = xpos.indexOf('#')) < 0 || xpos.indexOf('/') < 0) {
			return result;
		}
		XMDefinition xd = getXDPool().getXMDefinition(xpos.substring(0, ndx));
		if ((ndx1 = xpos.indexOf('/')) < 0) {
			return result;
		}
		XMElement base = xd.getModel(null, xpos.substring(ndx + 1, ndx1));
		if (base == null) {
			return result;
		}
		XMNode[] xnodes = base.getChildNodeModels();
		if (xnodes == null || base.getXonMode() == 0) {
			return result;
		}
		ndx = ndx1 + 1;
		if ((ndx1 = xpos.indexOf('/', ndx)) < 0) {
			ndx1 = xpos.length();
		}
		String xdpath =  xpos.substring(0, ndx) + '$';
		String jpath;
		if (xpath == null) {
			jpath = "";
			ndy1 = ndy = 0;
		} else {
			jpath = "$";
			ndy = xpath.indexOf('/') + 1;
			ndy1 = xpath.indexOf('/', ndy);
			if (ndy1 < 0) {
				ndy1 = xpath.length();
			}
		}
		boolean wasArray = false;
		String arrayInfo1 = "";
		String arrayInfo2 = "";
		while (ndx1 >= 0 && (ndy1 >= 0 || xpath == null)) {
			String s = xpos.substring(ndx, ndx1);
			int m = s.indexOf(':');
			if (m >= 0) {
				s = s.substring(m + 1);
			}
			m = 0;
			if (s.endsWith("]")) {
				int i = s.indexOf('[');
				if (i > 0) {
					m = Integer.parseInt(s.substring(i + 1, s.length() -1));
					if (m > 0) {
						m--;
					}
				}
			}
			String t = xpath!=null ? xpath.substring(ndy, ndy1) : "";
			int n = t.indexOf(':');
			if (n >= 0) {
				t = t.substring(n + 1);
			}
			n = 0;
			if (t.endsWith("]")) {
				int i = t.indexOf('[');
				if (i > 0) {
					n = Integer.parseInt(t.substring(i + 1, t.length() -1));
					if (n > 0) {
						n--;
					}
				}
			}
			if (wasArray) {
				arrayInfo1 = "[" + m + "]";
				arrayInfo2 = !t.isEmpty() ? "[" + n + "]" : "";
				wasArray = false;
			}
			if (s.startsWith(X_ARRAY)) {
				XMNode[] ynodes = xnodes;
				xnodes = null;
				for (int i=0, j=0; i < ynodes.length; i++) {
					XMNode x = ynodes[i];
					if (X_ARRAY.equals(x.getLocalName())) {
						if (j == m) { // model found
							xdpath += getItemName(x) + arrayInfo1;
							jpath += !t.isEmpty() ?getItemName(x)+arrayInfo2:"";
							arrayInfo1 = arrayInfo2 = "";
							xnodes = ((XMElement)x).getChildNodeModels();
							wasArray = true;
							break;
						}
						j++;
					}
				}
				if (xnodes==null) {
					return result;
				}
			} else if (s.startsWith(X_MAP)) {
				XMNode[] ynodes = xnodes;
				xnodes = null;
				for (int i=0, j=0; i < ynodes.length; i++) {
					XMNode x = ynodes[i];
					if (X_MAP.equals(x.getLocalName())) {
						if (j == m) { // model found
							xdpath += getItemName(x) + arrayInfo1;
							jpath += !t.isEmpty() ?getItemName(x)+arrayInfo2 :"";
							wasArray = false;
							arrayInfo1 = arrayInfo2 = "";
							xnodes = ((XMElement)x).getChildNodeModels();
							break;
						}
						j++;
					}
				}
				if (xnodes==null) {
					return result;
				}
			} else if (s.startsWith(X_VALUE)) {
				XMNode[] ynodes = xnodes;
				for (int i=0, j=0; i < ynodes.length; i++) {
					XMNode xn = ynodes[i];
					if (X_VALUE.equals(xn.getLocalName())) {
						if (j == m) { // model found
							xdpath += getItemName(xn) + arrayInfo1;
							jpath += !t.isEmpty()
								? getItemName(xn) + arrayInfo2 : "";
							return new String[]{xdpath, xpath!=null?jpath:null};
						}
						j++;
					}
				}
				return result;
			}
			ndx = ndx1 + 1;
			if (ndx >= xpos.length()) {
				break;
			}
			if ((ndx1 = xpos.indexOf('/', ndx)) < 0) {
				ndx1 = xpos.length();
			}
			if (!s.startsWith("$") && xpath != null) {
				ndy = ndy1 + 1;
				if (ndy >= xpath.length()) {
					break;
				}
				if ((ndy1 = xpath.indexOf('/', ndy)) < 0) {
					ndy1 = xpath.length();
				}
			}
		}
		return new String[]{xdpath, xpath!=null?jpath:null};
	}

	/** Get XPosition, XPath and source position for modification information
	 * in message reporting.
	 * @param xpos string with X-position.
	 * @param xpath XPath of data (may be null).
	 * @return modification information (convert to XON format if XON).
	 */
	final String getPosMod(final String xpos, final String xpath) {
		String[] x = getPosInfo(xpos, xpath);
		String result = "";
		if (x[0] != null) {
			result += "&{xdpos}" + x[0];
		}
		if (x[1] != null) {
			result += "&{xpath}" + x[1];
		}
		SPosition t = getSPosition();
		if (t != null) {
			if (t.getLineNumber() > 0) {
				result += "&{line}" + t.getLineNumber();
				result += "&{column}" + t.getColumnNumber();
			}
			if (t.getSysId() != null && !t.getSysId().isEmpty()) {
				result += "&{sysId}" + t.getSysId();
			}
		}
		return result;
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy