Mercurial > dive4elements > river
view flys-artifacts/src/main/java/de/intevation/flys/artifacts/datacage/templating/Builder.java @ 1009:fc5fca0c33b3
Datacage: Set the name of the collections at initial scan, too.
flys-artifacts/trunk@2454 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author | Sascha L. Teichmann <sascha.teichmann@intevation.de> |
---|---|
date | Tue, 02 Aug 2011 14:09:01 +0000 |
parents | b81626b10cb7 |
children | aca3b46160cb |
line wrap: on
line source
package de.intevation.flys.artifacts.datacage.templating; import java.util.regex.Pattern; import java.util.regex.Matcher; import java.util.ArrayList; import java.util.List; import java.util.HashMap; import java.util.Map; import org.w3c.dom.Document; import org.w3c.dom.NodeList; import org.w3c.dom.Node; import org.w3c.dom.Element; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathFactory; import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathConstants; import java.sql.SQLException; import java.sql.Connection; import de.intevation.artifacts.common.utils.XMLUtils; import org.apache.log4j.Logger; public class Builder { private static Logger log = Logger.getLogger(Builder.class); public static final Pattern STRIP_LINE_INDENT = Pattern.compile("\\s*\\r?\\n\\s*"); public static final String DC_NAMESPACE_URI = "http://www.intevation.org/2011/Datacage"; private static final Document EVAL_DOCUMENT = XMLUtils.newDocument(); private static final XPathFactory XPATH_FACTORY = XPathFactory.newInstance(); protected Document template; protected Map<String, CompiledStatement> compiledStatements; public class BuildHelper { protected Node output; protected Document owner; protected StackFrames frames; protected Connection connection; protected Map<String, CompiledStatement.Instance> statements; public BuildHelper( Node output, Connection connection, Map<String, Object> parameters ) { this.output = output; this.connection = connection; frames = new StackFrames(parameters); statements = new HashMap<String, CompiledStatement.Instance>(); owner = getOwnerDocument(output); } public void build() throws SQLException { try { synchronized (template) { for (Node current: rootsToList()) { build(output, current); } } } finally { closeStatements(); } } protected void closeStatements() { for (CompiledStatement.Instance csi: statements.values()) { csi.close(); } statements.clear(); } protected void context(Node parent, Element current) throws SQLException { NodeList elements = current.getElementsByTagNameNS( DC_NAMESPACE_URI, "elements"); if (elements.getLength() < 1) { log.warn("no elements found -> ignore"); return; } NodeList subs = elements.item(0).getChildNodes(); int S = subs.getLength(); if (S < 1) { log.warn("elements is empty -> ignore"); return; } NodeList stmntNode = current.getElementsByTagNameNS( DC_NAMESPACE_URI, "statement"); if (stmntNode.getLength() < 1) { log.warn("dc:context: too less statements"); return; } String stmntText = stmntNode.item(0).getTextContent(); CompiledStatement.Instance csi = statements.get(stmntText); if (csi == null) { CompiledStatement cs = compiledStatements.get(stmntText); csi = cs.new Instance(); statements.put(stmntText, csi); } ResultData rd = csi.execute(connection, frames); String [] columns = rd.getColumnLabels(); for (Object [] row: rd.getRows()) { frames.enter(); try { frames.put(columns, row); for (int i = 0; i < S; ++i) { build(parent, subs.item(i)); } } finally { frames.leave(); } } } protected void element(Node parent, Element current) throws SQLException { String attr = expand(current.getAttribute("name")); if (log.isDebugEnabled()) { log.debug("dc:element -> '" + attr + "'"); } if (attr.length() == 0) { log.warn("no name attribute found"); return; } Element element = owner.createElement(attr); NodeList children = current.getChildNodes(); for (int i = 0, N = children.getLength(); i < N; ++i) { build(element, children.item(i)); } parent.appendChild(element); } protected void text(Node parent, Element current) throws SQLException { log.debug("dc:text"); String value = expand(current.getTextContent()); parent.appendChild(owner.createTextNode(value)); } protected void attribute(Node parent, Element current) { if (parent.getNodeType() != Node.ELEMENT_NODE) { log.warn("need element here"); return; } String name = expand(current.getAttribute("name")); String value = expand(current.getAttribute("value")); Element element = (Element)parent; element.setAttribute(name, value); } protected void callMacro(Node parent, Element current) throws SQLException { String name = current.getAttribute("name"); if (name.length() == 0) { log.warn("missing 'name' attribute in 'call-macro'"); return; } NodeList macros = template.getElementsByTagNameNS( DC_NAMESPACE_URI, "macro"); for (int i = 0, N = macros.getLength(); i < N; ++i) { Element macro = (Element)macros.item(i); if (name.equals(macro.getAttribute("name"))) { NodeList subs = macro.getChildNodes(); for (int j = 0, M = subs.getLength(); j < M; ++j) { build(parent, subs.item(j)); } return; } } log.warn("no macro '" + name + "' found."); } protected void ifClause(Node parent, Element current) throws SQLException { String test = current.getAttribute("test"); if (test.length() == 0) { log.warn("missing 'test' attribute in 'if'"); return; } Boolean result = evaluateXPath(test); if (result != null && result.booleanValue()) { NodeList subs = current.getChildNodes(); for (int i = 0, N = subs.getLength(); i < N; ++i) { build(parent, subs.item(i)); } } } protected void choose(Node parent, Element current) throws SQLException { Node branch = null; NodeList children = current.getChildNodes(); for (int i = 0, N = children.getLength(); i < N; ++i) { Node child = children.item(i); String ns = child.getNamespaceURI(); if (ns == null || !ns.equals(DC_NAMESPACE_URI) || child.getNodeType() != Node.ELEMENT_NODE ) { continue; } String name = child.getLocalName(); if ("when".equals(name)) { Element when = (Element)child; String test = when.getAttribute("test"); if (test.length() == 0) { log.warn("no 'test' attribute found for when"); continue; } Boolean result = evaluateXPath(test); if (result != null && result.booleanValue()) { branch = child; break; } continue; } else if ("otherwise".equals(name)) { branch = child; // No break here. } } if (branch != null) { NodeList subs = branch.getChildNodes(); for (int i = 0, N = subs.getLength(); i < N; ++i) { build(parent, subs.item(i)); } } } protected Boolean evaluateXPath(String expr) { if (log.isDebugEnabled()) { log.debug("evaluate: '" + expr + "'"); } try { XPath xpath = XPATH_FACTORY.newXPath(); xpath.setXPathVariableResolver(frames); xpath.setXPathFunctionResolver(FunctionResolver.FUNCTIONS); Object result = xpath.evaluate( expr, EVAL_DOCUMENT, XPathConstants.BOOLEAN); return result instanceof Boolean ? (Boolean)result : null; } catch (XPathExpressionException xfce) { log.error(xfce); } return null; } protected void convert(Node parent, Element current) { String variable = expand(current.getAttribute("var")); String type = expand(current.getAttribute("type")); if (frames.containsKey(variable)) { Object object = TypeConverter.convert( frames.get(variable), type); frames.put(variable, object); } } protected String expand(String s) { Matcher m = CompiledStatement.VAR.matcher(s); StringBuffer sb = new StringBuffer(); while (m.find()) { String key = m.group(1); Object value = frames.get(key); m.appendReplacement(sb, value != null ? value.toString() : ""); } m.appendTail(sb); return sb.toString(); } protected void build(Node parent, Node current) throws SQLException { String ns = current.getNamespaceURI(); if (ns != null && ns.equals(DC_NAMESPACE_URI)) { if (current.getNodeType() != Node.ELEMENT_NODE) { log.warn("need elements here"); } else { String localName = current.getLocalName(); if ("attribute".equals(localName)) { attribute(parent, (Element)current); } else if ("context".equals(localName)) { context(parent, (Element)current); } else if ("if".equals(localName)) { ifClause(parent, (Element)current); } else if ("choose".equals(localName)) { choose(parent, (Element)current); } else if ("call-macro".equals(localName)) { callMacro(parent, (Element)current); } else if ("macro".equals(localName)) { // simply ignore the definition. } else if ("element".equals(localName)) { element(parent, (Element)current); } else if ("text".equals(localName)) { text(parent, (Element)current); } else if ("convert".equals(localName)) { convert(parent, (Element)current); } else { log.warn("unknown '" + localName + "' -> ignore"); } } return; } if (current.getNodeType() == Node.TEXT_NODE) { String txt = current.getNodeValue(); if (txt != null && txt.trim().length() == 0) { return; } } Node copy = owner.importNode(current, false); NodeList children = current.getChildNodes(); for (int i = 0, N = children.getLength(); i < N; ++i) { build(copy, children.item(i)); } parent.appendChild(copy); } } // class BuildHelper public Builder() { compiledStatements = new HashMap<String, CompiledStatement>(); } public Builder(Document template) { this(); this.template = template; compileStatements(); } protected void compileStatements() { NodeList nodes = template.getElementsByTagNameNS( DC_NAMESPACE_URI, "statement"); for (int i = 0, N = nodes.getLength(); i < N; ++i) { Element stmntElement = (Element)nodes.item(i); String stmnt = trimStatement(stmntElement.getTextContent()); if (stmnt == null || stmnt.length() == 0) { throw new IllegalArgumentException("found empty statement"); } CompiledStatement cs = new CompiledStatement(stmnt); // for faster lookup store a shortend string into the template stmnt = "s" + i; stmntElement.setTextContent(stmnt); compiledStatements.put(stmnt, cs); } } protected List<Node> rootsToList() { NodeList roots = template.getElementsByTagNameNS( DC_NAMESPACE_URI, "template"); List<Node> elements = new ArrayList<Node>(); for (int i = 0, N = roots.getLength(); i < N; ++i) { NodeList rootChildren = roots.item(i).getChildNodes(); for (int j = 0, M = rootChildren.getLength(); j < M; ++j) { Node child = rootChildren.item(j); if (child.getNodeType() == Node.ELEMENT_NODE) { elements.add(child); } } } return elements; } protected static final String trimStatement(String stmnt) { if (stmnt == null) return null; //XXX: Maybe a bit to radical for multiline strings? return STRIP_LINE_INDENT.matcher(stmnt.trim()).replaceAll(" "); } protected static Document getOwnerDocument(Node node) { Document document = node.getOwnerDocument(); return document != null ? document : (Document)node; } public void build( Connection connection, Node output, Map<String, Object> parameters ) throws SQLException { BuildHelper helper = new BuildHelper(output, connection, parameters); helper.build(); } } // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :