changeset 6399:10fe6758dfb0

Datacage: Introduced <dc:container-context>. It is an analogon to <dc:context> to fetch the data from a collection. Usage: <dc:container-context container="myContainer"> <dc:properties> <dc:property name="a"/> <dc:property name="b" alias="c"/> </dc:properties> <dc:for-each><!-- as usual --></dc:for-each> </dc:container-context> Iterates over the collection stored on stack with the name 'myContainer' and fetched for each item via getA() and getB() the values to be stored under 'a' and 'c'. dc:has-result() & Co work as expected.
author Sascha L. Teichmann <teichmann@intevation.de>
date Fri, 21 Jun 2013 20:02:15 +0200
parents 13ecaf6c0f20
children 25230bc3137c
files artifacts/src/main/java/org/dive4elements/river/artifacts/datacage/templating/Builder.java
diffstat 1 files changed, 137 insertions(+), 4 deletions(-) [+]
line wrap: on
line diff
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/datacage/templating/Builder.java	Fri Jun 21 18:09:53 2013 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/datacage/templating/Builder.java	Fri Jun 21 20:02:15 2013 +0200
@@ -12,6 +12,8 @@
 
 import org.dive4elements.river.utils.Pair;
 
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
 import java.sql.Connection;
 import java.sql.SQLException;
 
@@ -164,6 +166,14 @@
          * macros but not doing evaluation (e.g. of <dc:if>s).
          */
         private Node findStatementNode(NodeList nodes) {
+            return findSelectNode(nodes, "statement");
+        }
+
+        private Node findPropertiesNode(NodeList nodes) {
+            return findSelectNode(nodes, "properties");
+        }
+
+        private Node findSelectNode(NodeList nodes, String selectName) {
             int S = nodes.getLength();
 
             // Check direct children and take special care of macros.
@@ -172,7 +182,7 @@
                 String ns;
                 // Regular statement node.
                 if (node.getNodeType() == Node.ELEMENT_NODE
-                && node.getLocalName().equals("statement")
+                && node.getLocalName().equals(selectName)
                 && (ns = node.getNamespaceURI()) != null
                 && ns.equals(DC_NAMESPACE_URI)) {
                     return node;
@@ -185,7 +195,7 @@
 
                     String macroName = ((Element)node).getAttribute("name");
                     Node inMacroNode =
-                        findStatementNode(getMacroChildren(macroName));
+                        findSelectNode(getMacroChildren(macroName), selectName);
                     if (inMacroNode != null) {
                         return inMacroNode;
                     }
@@ -196,6 +206,127 @@
             return null;
         }
 
+        private String[][] extractProperties(Element propertiesNode) {
+            ArrayList<String[]> props = new ArrayList<String[]>();
+            NodeList list = propertiesNode.getElementsByTagNameNS(
+                DC_NAMESPACE_URI, "property");
+            for (int i = 0, L = list.getLength(); i < L; ++i) {
+                Element property = (Element)list.item(i);
+                String name = property.getAttribute("name");
+                if (name.isEmpty()) {
+                    log.warn("dc:property without name");
+                    continue;
+                }
+                String alias = property.getAttribute("alias");
+                if (alias.isEmpty()) {
+                    alias = name;
+                }
+                props.add(new String [] { name, alias });
+            }
+            return props.toArray(new String[props.size()][]);
+        }
+
+        /**
+         * Handle a dc:context node.
+         */
+        protected void containerContext(Node parent, Element current)
+        throws SQLException
+        {
+            log.debug("dc:container-context");
+
+            String container = expand(current.getAttribute("container"));
+
+            if (container.isEmpty()) {
+                log.warn("dc:container-context: no 'container' attribute found");
+                return;
+            }
+
+            NodeList subs = current.getChildNodes();
+            Node propertiesNode = findPropertiesNode(subs);
+
+            if (propertiesNode == null) {
+                log.warn("dc:container-context: cannot find properties.");
+                return;
+            }
+
+            String [][] properties = extractProperties((Element)propertiesNode);
+
+            if (properties.length == 0) {
+                log.warn("dc:properties: No properties defined.");
+            }
+
+            Object [] result = new Object[1];
+            if (!frames.getStore(container, result)) {
+                log.warn("dc:container-context: cannot find container.");
+                return;
+            }
+            Object c = result[0];
+            if (c instanceof Object []) {
+                c = Arrays.asList((Object [])c);
+            }
+            if (!(c instanceof Collection)) {
+                log.warn("dc:container-context: container is not a collection.");
+                return;
+            }
+
+            String [] columnNames = new String[properties.length];
+            for (int i = 0; i < columnNames.length; ++i) {
+                columnNames[i] = properties[i][1];
+            }
+
+            ResultData rd = new ResultData(columnNames);
+
+            for (Object obj: (Collection<?>)c) {
+                Object [] row = new Object[properties.length];
+                for (int i = 0; i < properties.length; ++i) {
+                    row[i] = getProperty(obj, properties[i][0]);
+                }
+                rd.add(row);
+            }
+
+            // only descent if there are results
+            if (!rd.isEmpty()) {
+                // A bit of a fake because the data is not from a
+                // real connection.
+                NamedConnection connection = connectionsStack.isEmpty()
+                    ? connections.get(0)
+                    : connectionsStack.peek().getA();
+
+                connectionsStack.push(
+                    new Pair<NamedConnection, ResultData>(connection, rd));
+                try {
+                    for (int i = 0, S = subs.getLength(); i < S; ++i) {
+                        build(parent, subs.item(i));
+                    }
+                }
+                finally {
+                    connectionsStack.pop();
+                }
+            }
+        }
+
+        /** Poor man's bean access. */
+        private Object getProperty(Object obj, String name) {
+            String mname =
+                "get" + Character.toUpperCase(name.charAt(0))
+                + name.substring(1);
+
+            try {
+                Method meth = obj.getClass().getMethod(mname);
+                return meth.invoke(obj);
+            }
+            catch (InvocationTargetException ite) {
+                log.warn(ite);
+            }
+            catch (IllegalAccessException iae) {
+                log.warn(iae);
+            }
+            catch (NoSuchMethodException nsme) {
+                log.warn(nsme);
+            }
+            return null;
+        }
+
         /**
          * Handle a dc:context node.
          */
@@ -206,7 +337,6 @@
 
             NodeList subs = current.getChildNodes();
             Node stmntNode = findStatementNode(subs);
-            int S = subs.getLength();
 
             if (stmntNode == null) {
                 log.warn("dc:context: cannot find statement");
@@ -250,7 +380,7 @@
                 connectionsStack.push(
                     new Pair<NamedConnection, ResultData>(connection, rd));
                 try {
-                    for (int i = 0; i < S; ++i) {
+                    for (int i = 0, S = subs.getLength(); i < S; ++i) {
                         build(parent, subs.item(i));
                     }
                 }
@@ -973,6 +1103,9 @@
                     else if ("context".equals(localName)) {
                         context(parent, curr);
                     }
+                    else if ("container-context".equals(localName)) {
+                        containerContext(parent, curr);
+                    }
                     else if ("if".equals(localName)) {
                         ifClause(parent, curr);
                     }

http://dive4elements.wald.intevation.org