comparison artifacts/src/main/java/org/dive4elements/river/artifacts/datacage/templating/Builder.java @ 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 a02d27da17ca
children da1d1df9ab23
comparison
equal deleted inserted replaced
6398:13ecaf6c0f20 6399:10fe6758dfb0
10 10
11 import org.dive4elements.artifacts.common.utils.XMLUtils; 11 import org.dive4elements.artifacts.common.utils.XMLUtils;
12 12
13 import org.dive4elements.river.utils.Pair; 13 import org.dive4elements.river.utils.Pair;
14 14
15 import java.lang.reflect.InvocationTargetException;
16 import java.lang.reflect.Method;
15 import java.sql.Connection; 17 import java.sql.Connection;
16 import java.sql.SQLException; 18 import java.sql.SQLException;
17 19
18 import java.util.ArrayDeque; 20 import java.util.ArrayDeque;
19 import java.util.ArrayList; 21 import java.util.ArrayList;
162 /** 164 /**
163 * Return first statement node in NodeList, respecting 165 * Return first statement node in NodeList, respecting
164 * macros but not doing evaluation (e.g. of <dc:if>s). 166 * macros but not doing evaluation (e.g. of <dc:if>s).
165 */ 167 */
166 private Node findStatementNode(NodeList nodes) { 168 private Node findStatementNode(NodeList nodes) {
169 return findSelectNode(nodes, "statement");
170 }
171
172 private Node findPropertiesNode(NodeList nodes) {
173 return findSelectNode(nodes, "properties");
174 }
175
176 private Node findSelectNode(NodeList nodes, String selectName) {
167 int S = nodes.getLength(); 177 int S = nodes.getLength();
168 178
169 // Check direct children and take special care of macros. 179 // Check direct children and take special care of macros.
170 for (int i = 0; i < S; ++i) { 180 for (int i = 0; i < S; ++i) {
171 Node node = nodes.item(i); 181 Node node = nodes.item(i);
172 String ns; 182 String ns;
173 // Regular statement node. 183 // Regular statement node.
174 if (node.getNodeType() == Node.ELEMENT_NODE 184 if (node.getNodeType() == Node.ELEMENT_NODE
175 && node.getLocalName().equals("statement") 185 && node.getLocalName().equals(selectName)
176 && (ns = node.getNamespaceURI()) != null 186 && (ns = node.getNamespaceURI()) != null
177 && ns.equals(DC_NAMESPACE_URI)) { 187 && ns.equals(DC_NAMESPACE_URI)) {
178 return node; 188 return node;
179 } 189 }
180 // Macro node. Descend. 190 // Macro node. Descend.
183 && (ns = node.getNamespaceURI()) != null 193 && (ns = node.getNamespaceURI()) != null
184 && ns.equals(DC_NAMESPACE_URI)) { 194 && ns.equals(DC_NAMESPACE_URI)) {
185 195
186 String macroName = ((Element)node).getAttribute("name"); 196 String macroName = ((Element)node).getAttribute("name");
187 Node inMacroNode = 197 Node inMacroNode =
188 findStatementNode(getMacroChildren(macroName)); 198 findSelectNode(getMacroChildren(macroName), selectName);
189 if (inMacroNode != null) { 199 if (inMacroNode != null) {
190 return inMacroNode; 200 return inMacroNode;
191 } 201 }
192 } 202 }
193 203
194 } 204 }
195 205
206 return null;
207 }
208
209 private String[][] extractProperties(Element propertiesNode) {
210 ArrayList<String[]> props = new ArrayList<String[]>();
211 NodeList list = propertiesNode.getElementsByTagNameNS(
212 DC_NAMESPACE_URI, "property");
213 for (int i = 0, L = list.getLength(); i < L; ++i) {
214 Element property = (Element)list.item(i);
215 String name = property.getAttribute("name");
216 if (name.isEmpty()) {
217 log.warn("dc:property without name");
218 continue;
219 }
220 String alias = property.getAttribute("alias");
221 if (alias.isEmpty()) {
222 alias = name;
223 }
224 props.add(new String [] { name, alias });
225 }
226 return props.toArray(new String[props.size()][]);
227 }
228
229 /**
230 * Handle a dc:context node.
231 */
232 protected void containerContext(Node parent, Element current)
233 throws SQLException
234 {
235 log.debug("dc:container-context");
236
237 String container = expand(current.getAttribute("container"));
238
239 if (container.isEmpty()) {
240 log.warn("dc:container-context: no 'container' attribute found");
241 return;
242 }
243
244 NodeList subs = current.getChildNodes();
245 Node propertiesNode = findPropertiesNode(subs);
246
247 if (propertiesNode == null) {
248 log.warn("dc:container-context: cannot find properties.");
249 return;
250 }
251
252 String [][] properties = extractProperties((Element)propertiesNode);
253
254 if (properties.length == 0) {
255 log.warn("dc:properties: No properties defined.");
256 }
257
258 Object [] result = new Object[1];
259 if (!frames.getStore(container, result)) {
260 log.warn("dc:container-context: cannot find container.");
261 return;
262 }
263 Object c = result[0];
264 if (c instanceof Object []) {
265 c = Arrays.asList((Object [])c);
266 }
267 if (!(c instanceof Collection)) {
268 log.warn("dc:container-context: container is not a collection.");
269 return;
270 }
271
272 String [] columnNames = new String[properties.length];
273 for (int i = 0; i < columnNames.length; ++i) {
274 columnNames[i] = properties[i][1];
275 }
276
277 ResultData rd = new ResultData(columnNames);
278
279 for (Object obj: (Collection<?>)c) {
280 Object [] row = new Object[properties.length];
281 for (int i = 0; i < properties.length; ++i) {
282 row[i] = getProperty(obj, properties[i][0]);
283 }
284 rd.add(row);
285 }
286
287 // only descent if there are results
288 if (!rd.isEmpty()) {
289 // A bit of a fake because the data is not from a
290 // real connection.
291 NamedConnection connection = connectionsStack.isEmpty()
292 ? connections.get(0)
293 : connectionsStack.peek().getA();
294
295 connectionsStack.push(
296 new Pair<NamedConnection, ResultData>(connection, rd));
297 try {
298 for (int i = 0, S = subs.getLength(); i < S; ++i) {
299 build(parent, subs.item(i));
300 }
301 }
302 finally {
303 connectionsStack.pop();
304 }
305 }
306 }
307
308 /** Poor man's bean access. */
309 private Object getProperty(Object obj, String name) {
310 String mname =
311 "get" + Character.toUpperCase(name.charAt(0))
312 + name.substring(1);
313
314 try {
315 Method meth = obj.getClass().getMethod(mname);
316 return meth.invoke(obj);
317 }
318 catch (InvocationTargetException ite) {
319 log.warn(ite);
320 }
321 catch (IllegalAccessException iae) {
322 log.warn(iae);
323 }
324 catch (NoSuchMethodException nsme) {
325 log.warn(nsme);
326 }
196 return null; 327 return null;
197 } 328 }
198 329
199 /** 330 /**
200 * Handle a dc:context node. 331 * Handle a dc:context node.
204 { 335 {
205 log.debug("dc:context"); 336 log.debug("dc:context");
206 337
207 NodeList subs = current.getChildNodes(); 338 NodeList subs = current.getChildNodes();
208 Node stmntNode = findStatementNode(subs); 339 Node stmntNode = findStatementNode(subs);
209 int S = subs.getLength();
210 340
211 if (stmntNode == null) { 341 if (stmntNode == null) {
212 log.warn("dc:context: cannot find statement"); 342 log.warn("dc:context: cannot find statement");
213 return; 343 return;
214 } 344 }
248 // only descent if there are results 378 // only descent if there are results
249 if (!rd.isEmpty()) { 379 if (!rd.isEmpty()) {
250 connectionsStack.push( 380 connectionsStack.push(
251 new Pair<NamedConnection, ResultData>(connection, rd)); 381 new Pair<NamedConnection, ResultData>(connection, rd));
252 try { 382 try {
253 for (int i = 0; i < S; ++i) { 383 for (int i = 0, S = subs.getLength(); i < S; ++i) {
254 build(parent, subs.item(i)); 384 build(parent, subs.item(i));
255 } 385 }
256 } 386 }
257 finally { 387 finally {
258 connectionsStack.pop(); 388 connectionsStack.pop();
971 attribute(parent, curr); 1101 attribute(parent, curr);
972 } 1102 }
973 else if ("context".equals(localName)) { 1103 else if ("context".equals(localName)) {
974 context(parent, curr); 1104 context(parent, curr);
975 } 1105 }
1106 else if ("container-context".equals(localName)) {
1107 containerContext(parent, curr);
1108 }
976 else if ("if".equals(localName)) { 1109 else if ("if".equals(localName)) {
977 ifClause(parent, curr); 1110 ifClause(parent, curr);
978 } 1111 }
979 else if ("choose".equals(localName)) { 1112 else if ("choose".equals(localName)) {
980 choose(parent, curr); 1113 choose(parent, curr);

http://dive4elements.wald.intevation.org