package com.bagri.core.server.api.impl; import static javax.xml.xquery.XQItemType.*; import java.math.BigDecimal; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.bagri.core.api.BagriException; import com.bagri.core.model.Data; import com.bagri.core.model.Element; import com.bagri.core.model.NodeKind; import com.bagri.core.model.Null; import com.bagri.core.model.Occurrence; import com.bagri.core.model.Path; import com.bagri.core.server.api.ModelManagement; /** * A common implementation part for any future parser. * * @author Denis Sukhoroslov * */ public abstract class ContentParserBase { protected final Logger logger = LoggerFactory.getLogger(getClass()); protected ModelManagement model; /** * * @param model the model management component. Used to search/add model paths. */ protected ContentParserBase(ModelManagement model) { this.model = model; } /** * initializes parser components before parsing document * * @return the parsing context */ protected ParserContext initContext() { return new ParserContext(); } protected class ParserContext { private String root = null; private TreeNode<Data> tree; private TreeNode<Data> top; public void addDocument(String root) throws BagriException { this.root = root; Data data = new Data(root); Path path = model.translatePath(root, "/", NodeKind.document, 0, XQBASETYPE_UNTYPED, Occurrence.onlyOne); Element start = new Element(); data.setData(path, start); tree = new TreeNode<>(data); top = tree; } public Data addData(String name) { Data data = new Data(name); top.addChild(data); return data; } public Data addData(String name, NodeKind kind, Object value, int dataType, Occurrence occurence) throws BagriException { Data data = addData(name); setData(kind, value, dataType, occurence); return data; } public void addElement() throws BagriException { TreeNode<Data> node = getLastNamedNode(); if (node == null) { // element in array addData(""); node = top.getLastNode(); } Occurrence occurrence = isInArray() ? Occurrence.zeroOrMany : Occurrence.zeroOrOne; setData(NodeKind.element, null, XQBASETYPE_ANYTYPE, occurrence); top = node; } public void addArray() throws BagriException { TreeNode<Data> node = getLastNamedNode(); if (node == null) { // array in document addData(""); // ?? node = top.getLastNode(); } setData(NodeKind.array, null, XQBASETYPE_ANYTYPE, Occurrence.zeroOrOne); top = node; } public void addValue() throws BagriException { // set special null value.. setData(Null._null, XQBASETYPE_ANYATOMICTYPE); } public void addValue(boolean value) throws BagriException { setData(Boolean.valueOf(value), XQBASETYPE_BOOLEAN); } public void addValue(BigDecimal value) throws BagriException { setData(value, XQBASETYPE_DECIMAL); } public void addValue(long value) throws BagriException { setData(Long.valueOf(value), XQBASETYPE_LONG); } public void addValue(String value) throws BagriException { setData(value, XQBASETYPE_STRING); } public void endElement() throws BagriException { Data current = top.getData(); if (current != null && current.getElement() != null && current.getParentPathId() > 0) { Path parent = model.getPath(current.getParentPathId()); if (parent != null && parent.getPostId() < current.getPostId()) { parent.setPostId(current.getPostId()); model.updatePath(parent); } } top = top.getParent(); } public List<Data> getDataList() { List<Data> list = new ArrayList<>(); if (tree != null) { tree.fillData(list); } return list; } public String getDocRoot() { return root; } public Data getTopData() { if (top == null) { return null; } return top.getData(); } protected TreeNode<Data> getLastNamedNode() { TreeNode<Data> node = top.getLastNode(); if (node == null) { return null; } Data last = node.getData(); if (last.getDataPath() == null) { return node; } return null; } protected boolean isInArray() { return top.getData().getNodeKind() == NodeKind.array; } protected boolean isTopEmpty() { return top.getLastNode() == null; } protected void setData(Object value, int dataType) throws BagriException { NodeKind kind; Occurrence occurrence; if (isInArray()) { kind = NodeKind.text; occurrence = Occurrence.zeroOrMany; TreeNode<Data> node = getLastNamedNode(); if (node == null) { // text in array addData(""); } } else { kind = NodeKind.attribute; occurrence = Occurrence.zeroOrOne; } setData(kind, value, dataType, occurrence); } protected void setData(NodeKind kind, Object value, int dataType, Occurrence occurrence) throws BagriException { TreeNode<Data> node = top.getLastNode(); Data current = node.getData(); setData(current, top.getData(), kind, value, dataType, occurrence); } protected void setData(Data current, Data parent, NodeKind kind, Object value, int dataType, Occurrence occurrence) throws BagriException { logger.trace("setData.enter; current: {}; kind: {}; value: {}; parent: {}", current, kind, value, parent); String path = parent.getPath(); if (!path.endsWith("/")) { path += "/"; } path += current.getDataName(); Path xPath = model.translatePath(root, path, kind, parent.getPathId(), dataType, occurrence); if (parent.getPostId() < xPath.getPathId()) { Path pPath = parent.getDataPath(); pPath.setPostId(xPath.getPathId()); model.updatePath(pPath); } int[] position = parent.getPosition(); position = Arrays.copyOf(position, position.length + 1); position[position.length - 1] = parent.addLastChild(); Element xElt = new Element(position, value); //getAtomicValue(xPath.getDataType(), value)); current.setData(xPath, xElt); logger.trace("setData.exit; updated data: {}", current); } } }