Mercurial > dive4elements > river
comparison flys-artifacts/src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java @ 3812:f788d2d901d6
merged flys-artifacts/pre2.6-2011-12-05
author | Thomas Arendsen Hein <thomas@intevation.de> |
---|---|
date | Fri, 28 Sep 2012 12:14:53 +0200 |
parents | 37a7b3841565 |
children | 3c3e81fca092 |
comparison
equal
deleted
inserted
replaced
3808:5fab0fe3c445 | 3812:f788d2d901d6 |
---|---|
1 package de.intevation.flys.collections; | |
2 | |
3 import java.io.IOException; | |
4 import java.io.OutputStream; | |
5 import java.util.ArrayList; | |
6 import java.util.Date; | |
7 import java.util.HashMap; | |
8 import java.util.List; | |
9 import java.util.Map; | |
10 | |
11 import javax.xml.xpath.XPathConstants; | |
12 | |
13 import org.apache.log4j.Logger; | |
14 | |
15 import org.w3c.dom.Document; | |
16 import org.w3c.dom.Element; | |
17 import org.w3c.dom.Node; | |
18 import org.w3c.dom.NodeList; | |
19 | |
20 import de.intevation.artifacts.Artifact; | |
21 import de.intevation.artifacts.ArtifactDatabase; | |
22 import de.intevation.artifacts.ArtifactDatabaseException; | |
23 import de.intevation.artifacts.ArtifactNamespaceContext; | |
24 import de.intevation.artifacts.CallContext; | |
25 import de.intevation.artifacts.CallMeta; | |
26 | |
27 import de.intevation.artifacts.common.utils.ClientProtocolUtils; | |
28 import de.intevation.artifacts.common.utils.XMLUtils; | |
29 | |
30 import de.intevation.artifactdatabase.Backend; | |
31 import de.intevation.artifactdatabase.Backend.PersistentArtifact; | |
32 import de.intevation.artifactdatabase.DefaultArtifactCollection; | |
33 import de.intevation.artifactdatabase.state.ArtifactAndFacet; | |
34 import de.intevation.artifactdatabase.state.StateEngine; | |
35 | |
36 import de.intevation.flys.artifacts.context.FLYSContext; | |
37 import de.intevation.flys.artifacts.FLYSArtifact; | |
38 import de.intevation.flys.artifacts.model.ManagedFacet; | |
39 import de.intevation.flys.artifacts.model.ManagedDomFacet; | |
40 import de.intevation.flys.exports.OutGenerator; | |
41 import de.intevation.flys.themes.Theme; | |
42 import de.intevation.flys.themes.ThemeFactory; | |
43 | |
44 import de.intevation.flys.utils.FLYSUtils; | |
45 | |
46 /** | |
47 * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> | |
48 */ | |
49 public class FLYSArtifactCollection extends DefaultArtifactCollection { | |
50 /** The logger used in this class. */ | |
51 private static Logger log = Logger.getLogger(FLYSArtifactCollection.class); | |
52 | |
53 /** Constant XPath that points to the outputmodes of an artifact. */ | |
54 public static final String XPATH_ARTIFACT_OUTPUTMODES = | |
55 "/art:result/art:outputmodes"; | |
56 | |
57 public static final String XPATH_ARTIFACT_STATE_DATA = | |
58 "/art:result/art:ui/art:static/art:state/art:data"; | |
59 | |
60 public static final String XPATH_COLLECTION_ITEMS = | |
61 "/art:result/art:artifact-collection/art:collection-item"; | |
62 | |
63 public static final String XPATH_OUT_NAME = "/art:action/@art:name"; | |
64 | |
65 public static final String XPATH_OUT_TYPE = "/art:action/@art:type"; | |
66 | |
67 /** Xpath to master artifacts uuid. */ | |
68 public static final String XPATH_MASTER_UUID = | |
69 "/art:artifact-collection/art:artifact/@art:uuid"; | |
70 | |
71 public static final String XPATH_LOADED_RECOMMENDATIONS = | |
72 "/art:attribute/art:loaded-recommendations"; | |
73 | |
74 | |
75 /** | |
76 * Return description Document for this collection. | |
77 */ | |
78 @Override | |
79 public Document describe(CallContext context) { | |
80 log.debug("FLYSArtifactCollection.describe: " + identifier); | |
81 | |
82 Document doc = XMLUtils.newDocument(); | |
83 | |
84 XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator( | |
85 doc, | |
86 ArtifactNamespaceContext.NAMESPACE_URI, | |
87 ArtifactNamespaceContext.NAMESPACE_PREFIX); | |
88 | |
89 Date creationTime = getCreationTime(); | |
90 String creation = creationTime != null | |
91 ? Long.toString(creationTime.getTime()) | |
92 : ""; | |
93 | |
94 Element collection = ec.create("artifact-collection"); | |
95 Element artifacts = ec.create("artifacts"); | |
96 | |
97 ec.addAttr(collection, "name", getName(), true); | |
98 ec.addAttr(collection, "uuid", identifier(), true); | |
99 ec.addAttr(collection, "creation", creation, true); | |
100 ec.addAttr(collection, "ttl", String.valueOf(getTTL()), true); | |
101 | |
102 collection.appendChild(artifacts); | |
103 doc.appendChild(collection); | |
104 | |
105 ArtifactDatabase db = context.getDatabase(); | |
106 Document oldAttrs = getAttribute(); | |
107 | |
108 try { | |
109 String[] aUUIDs = getArtifactUUIDs(context); | |
110 Node newAttr = mergeAttributes(db, context, oldAttrs, aUUIDs); | |
111 | |
112 collection.appendChild(doc.importNode(newAttr, true)); | |
113 | |
114 // Make it an empty array if null. | |
115 if (aUUIDs == null) { | |
116 aUUIDs = new String[] {}; | |
117 } | |
118 | |
119 for (String uuid: aUUIDs) { | |
120 try { | |
121 artifacts.appendChild( | |
122 buildArtifactNode(db, uuid, context, ec)); | |
123 } | |
124 catch (ArtifactDatabaseException dbe) { | |
125 log.warn(dbe, dbe); | |
126 } | |
127 } | |
128 } | |
129 catch (ArtifactDatabaseException ade) { | |
130 log.error(ade, ade); | |
131 | |
132 collection.appendChild( | |
133 doc.importNode(oldAttrs.getFirstChild(), true)); | |
134 } | |
135 | |
136 return doc; | |
137 } | |
138 | |
139 | |
140 /** | |
141 * Merge the current art:outputs nodes with the the outputs provided by the | |
142 * artifacts in the Collection. | |
143 * | |
144 * @param uuids Artifact uuids. | |
145 */ | |
146 protected Node mergeAttributes( | |
147 ArtifactDatabase db, | |
148 CallContext context, | |
149 Document oldAttrs, | |
150 String[] uuids) | |
151 { | |
152 Document doc = buildOutAttributes(db, context, oldAttrs, uuids); | |
153 Node newAttr = doc.getFirstChild(); | |
154 | |
155 newAttr = mergeLoadedRecommendations(oldAttrs, newAttr); | |
156 | |
157 try { | |
158 // Save the merged document into database. | |
159 db.setCollectionAttribute(identifier(), context.getMeta(), doc); | |
160 } | |
161 catch (ArtifactDatabaseException adb) { | |
162 log.error(adb, adb); | |
163 } | |
164 | |
165 return newAttr; | |
166 } | |
167 | |
168 | |
169 /** | |
170 * Merge the recommendations which have already been loaded from the old | |
171 * attribute document into the new attribute document. This is necessary, | |
172 * because mergeAttributes() only merges the art:outputs nodes - all | |
173 * other nodes are skiped. | |
174 */ | |
175 protected Node mergeLoadedRecommendations(Document oldAttrs, Node newAttrs){ | |
176 Element loadedRecoms = (Element) XMLUtils.xpath( | |
177 oldAttrs, | |
178 XPATH_LOADED_RECOMMENDATIONS, | |
179 XPathConstants.NODE, | |
180 ArtifactNamespaceContext.INSTANCE); | |
181 | |
182 if (loadedRecoms != null) { | |
183 Document doc = newAttrs.getOwnerDocument(); | |
184 newAttrs.appendChild(doc.importNode(loadedRecoms, true)); | |
185 } | |
186 | |
187 return newAttrs; | |
188 } | |
189 | |
190 | |
191 @Override | |
192 public void out( | |
193 String type, | |
194 Document format, | |
195 OutputStream out, | |
196 CallContext context) | |
197 throws IOException | |
198 { | |
199 log.info("FLYSArtifactCollection.out"); | |
200 | |
201 String name = XMLUtils.xpathString( | |
202 format, XPATH_OUT_NAME, ArtifactNamespaceContext.INSTANCE); | |
203 | |
204 String subtype = XMLUtils.xpathString( | |
205 format, XPATH_OUT_TYPE, ArtifactNamespaceContext.INSTANCE); | |
206 | |
207 log.info("-> Output name = " + name); | |
208 log.info("-> Output type = " + type); | |
209 log.info("-> Output subtype = " + subtype); | |
210 | |
211 OutGenerator generator = null; | |
212 if (type != null | |
213 && type.length() > 0 | |
214 && type.indexOf("chartinfo") > 0) | |
215 { | |
216 generator = getOutGenerator(context, type, subtype); | |
217 } | |
218 else { | |
219 generator = getOutGenerator(context, name, subtype); | |
220 } | |
221 | |
222 if (generator == null) { | |
223 log.error("There is no generator specified for output: " + name); | |
224 // TODO Throw an exception. | |
225 | |
226 return; | |
227 } | |
228 | |
229 generator.init(format, out, context); | |
230 | |
231 // Get master artifact. | |
232 FLYSArtifact master = getMasterArtifact(context); | |
233 if (master != null) { | |
234 log.debug("Will set master Artifact to uuid: " + master.identifier()); | |
235 generator.setMasterArtifact(master); | |
236 } | |
237 else { | |
238 log.warn("Could not set master artifact."); | |
239 } | |
240 | |
241 try { | |
242 Document attr = getAttribute(context, name); | |
243 doOut(generator, name, subtype, attr, context); | |
244 } | |
245 catch (ArtifactDatabaseException adbe) { | |
246 log.error(adbe, adbe); | |
247 } | |
248 } | |
249 | |
250 | |
251 /** | |
252 * Creates the concrete output. | |
253 * | |
254 * @param generator The OutGenerator that creates the output. | |
255 * @param outputName The name of the requested output. | |
256 * @param attributes The collection's attributes for this concrete output | |
257 * type. | |
258 * @param context The context object. | |
259 */ | |
260 protected void doOut( | |
261 OutGenerator generator, | |
262 String outName, | |
263 String facet, | |
264 Document attributes, | |
265 CallContext context) | |
266 throws IOException | |
267 { | |
268 log.info("FLYSArtifactCollection.doOut: " + outName); | |
269 | |
270 ThemeList themeList = new ThemeList(attributes); | |
271 | |
272 int size = themeList.size(); | |
273 log.debug("Output will contain " + size + " elements."); | |
274 | |
275 List<ArtifactAndFacet> dataProviders = | |
276 doBlackboardPass(themeList, context); | |
277 | |
278 try { | |
279 for (int i = 0; i < size; i++) { | |
280 ManagedFacet theme = themeList.get(i); | |
281 | |
282 if (theme == null) { | |
283 log.debug("Theme is empty - no output is generated."); | |
284 continue; | |
285 } | |
286 | |
287 String art = theme.getArtifact(); | |
288 String facetName = theme.getName(); | |
289 | |
290 if (log.isDebugEnabled()) { | |
291 log.debug("Do output for..."); | |
292 log.debug("... artifact: " + art); | |
293 log.debug("... facet: " + facetName); | |
294 } | |
295 | |
296 if (outName.equals("export") && !facetName.equals(facet)) { | |
297 continue; | |
298 } | |
299 | |
300 generator.doOut( | |
301 dataProviders.get(i), | |
302 getFacetThemeFromAttribute( | |
303 art, | |
304 outName, | |
305 facetName, | |
306 theme.getDescription(), | |
307 theme.getIndex(), | |
308 context), | |
309 theme.getActive() == 1); | |
310 } | |
311 } | |
312 catch (ArtifactDatabaseException ade) { | |
313 log.error(ade, ade); | |
314 } | |
315 | |
316 generator.generate(); | |
317 } | |
318 | |
319 | |
320 /** | |
321 * Show blackboard (context) to each facet and create a list of | |
322 * ArtifactAndFacets on the fly (with the same ordering as the passed | |
323 * ThemeList). | |
324 * @param themeList ThemeList to create a ArtifactAndFacetList along. | |
325 * @param contect The "Blackboard". | |
326 */ | |
327 protected List<ArtifactAndFacet> doBlackboardPass( | |
328 ThemeList themeList, CallContext context | |
329 ) { | |
330 ArrayList<ArtifactAndFacet> dataProviders = | |
331 new ArrayList<ArtifactAndFacet>(); | |
332 int size = themeList.size(); | |
333 | |
334 try { | |
335 // Collect all ArtifactAndFacets for blackboard pass. | |
336 for (int i = 0; i < size; i++) { | |
337 ManagedFacet theme = themeList.get(i); | |
338 String uuid = theme.getArtifact(); | |
339 Artifact artifact = getArtifact(uuid, context); | |
340 FLYSArtifact flys = (FLYSArtifact) artifact; | |
341 ArtifactAndFacet artifactAndFacet = new ArtifactAndFacet(artifact, | |
342 flys.getNativeFacet(theme)); | |
343 | |
344 // Show blackboard to facet. | |
345 artifactAndFacet.register(context); | |
346 | |
347 // Add to themes. | |
348 dataProviders.add(i, artifactAndFacet); | |
349 } | |
350 } | |
351 catch (ArtifactDatabaseException ade) { | |
352 log.error("ArtifactDatabaseException!", ade); | |
353 } | |
354 | |
355 return dataProviders; | |
356 } | |
357 | |
358 /** | |
359 * @return masterartifact or null if exception/not found. | |
360 */ | |
361 protected FLYSArtifact getMasterArtifact(CallContext context) | |
362 { | |
363 try { | |
364 ArtifactDatabase db = context.getDatabase(); | |
365 CallMeta callMeta = context.getMeta(); | |
366 Document document = db.getCollectionsMasterArtifact( | |
367 identifier(), callMeta); | |
368 | |
369 String masterUUID = XMLUtils.xpathString( | |
370 document, XPATH_MASTER_UUID, ArtifactNamespaceContext.INSTANCE); | |
371 FLYSArtifact masterArtifact = | |
372 (FLYSArtifact) getArtifact(masterUUID, context); | |
373 return masterArtifact; | |
374 } | |
375 catch (ArtifactDatabaseException ade) { | |
376 log.error(ade, ade); | |
377 } | |
378 return null; | |
379 } | |
380 | |
381 | |
382 /** | |
383 * Return merged output document. | |
384 * @param uuids List of artifact uuids. | |
385 */ | |
386 protected Document buildOutAttributes( | |
387 ArtifactDatabase db, | |
388 CallContext context, | |
389 Document oldAttr, | |
390 String[] uuids) | |
391 { | |
392 Document doc = XMLUtils.newDocument(); | |
393 | |
394 FLYSContext flysContext = FLYSUtils.getFlysContext(context); | |
395 StateEngine engine = (StateEngine) flysContext.get( | |
396 FLYSContext.STATE_ENGINE_KEY); | |
397 | |
398 FLYSArtifact masterArtifact = getMasterArtifact(context); | |
399 | |
400 XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator( | |
401 doc, | |
402 ArtifactNamespaceContext.NAMESPACE_URI, | |
403 ArtifactNamespaceContext.NAMESPACE_PREFIX); | |
404 | |
405 AttributeParser aParser = new AttributeParser(); | |
406 OutputParser oParser = new OutputParser(db, context); | |
407 | |
408 if (uuids != null) { | |
409 for (String uuid: uuids) { | |
410 try { | |
411 oParser.parse(uuid); | |
412 } | |
413 catch (ArtifactDatabaseException ade) { | |
414 log.warn(ade, ade); | |
415 } | |
416 } | |
417 } | |
418 | |
419 aParser.parse(oldAttr); | |
420 | |
421 return new AttributeWriter( | |
422 db, | |
423 aParser.getOuts(), | |
424 aParser.getFacets(), | |
425 oParser.getOuts(), | |
426 oParser.getFacets(), | |
427 engine.getCompatibleFacets(masterArtifact.getStateHistoryIds()) | |
428 ).write(); | |
429 } | |
430 | |
431 | |
432 /** | |
433 * Returns the "attribute" (part of description document) for a specific | |
434 * output type. | |
435 * | |
436 * @param output The name of the desired output type. | |
437 * | |
438 * @return the attribute for the desired output type. | |
439 */ | |
440 protected Document getAttribute(CallContext context, String output) | |
441 throws ArtifactDatabaseException | |
442 { | |
443 Document attr = buildOutAttributes( | |
444 context.getDatabase(), | |
445 context, | |
446 getAttribute(), | |
447 getArtifactUUIDs(context)); | |
448 | |
449 Node out = (Node) XMLUtils.xpath( | |
450 attr, | |
451 "art:attribute/art:outputs/art:output[@name='" + output + "']", | |
452 XPathConstants.NODE, | |
453 ArtifactNamespaceContext.INSTANCE); | |
454 | |
455 | |
456 if (out != null) { | |
457 Document o = XMLUtils.newDocument(); | |
458 | |
459 o.appendChild(o.importNode(out, true)); | |
460 | |
461 return o; | |
462 } | |
463 | |
464 return null; | |
465 } | |
466 | |
467 | |
468 /** | |
469 * This method returns the list of artifact UUIDs that this collections | |
470 * contains. | |
471 * | |
472 * @param context The CallContext that is necessary to get information about | |
473 * the ArtifactDatabase. | |
474 * | |
475 * @return a list of uuids. | |
476 */ | |
477 protected String[] getArtifactUUIDs(CallContext context) | |
478 throws ArtifactDatabaseException | |
479 { | |
480 log.debug("FLYSArtifactCollection.getArtifactUUIDs"); | |
481 | |
482 ArtifactDatabase db = context.getDatabase(); | |
483 CallMeta meta = context.getMeta(); | |
484 | |
485 Document itemList = db.listCollectionArtifacts(identifier(), meta); | |
486 NodeList items = (NodeList) XMLUtils.xpath( | |
487 itemList, | |
488 XPATH_COLLECTION_ITEMS, | |
489 XPathConstants.NODESET, | |
490 ArtifactNamespaceContext.INSTANCE); | |
491 | |
492 if (items == null || items.getLength() == 0) { | |
493 log.debug("No artifacts found in this collection."); | |
494 return null; | |
495 } | |
496 | |
497 int num = items.getLength(); | |
498 | |
499 List<String> uuids = new ArrayList<String>(num); | |
500 | |
501 for (int i = 0; i < num; i++) { | |
502 String uuid = XMLUtils.xpathString( | |
503 items.item(i), | |
504 "@art:uuid", | |
505 ArtifactNamespaceContext.INSTANCE); | |
506 | |
507 if (uuid != null && uuid.trim().length() != 0) { | |
508 uuids.add(uuid); | |
509 } | |
510 } | |
511 | |
512 return (String[]) uuids.toArray(new String[uuids.size()]); | |
513 } | |
514 | |
515 | |
516 /** | |
517 * Returns a concrete Artifact of this collection specified by its uuid. | |
518 * | |
519 * @param uuid The Artifact's uuid. | |
520 * @param context The CallContext. | |
521 * | |
522 * @return an Artifact. | |
523 */ | |
524 protected Artifact getArtifact(String uuid, CallContext context) | |
525 throws ArtifactDatabaseException | |
526 { | |
527 log.debug("FLYSArtifactCollection.getArtifact"); | |
528 | |
529 Backend backend = Backend.getInstance(); | |
530 PersistentArtifact persistent = backend.getArtifact(uuid); | |
531 | |
532 return persistent != null ? persistent.getArtifact() : null; | |
533 } | |
534 | |
535 | |
536 /** | |
537 * Returns the attribute that belongs to an artifact and facet stored in | |
538 * this collection. | |
539 * | |
540 * @param uuid The Artifact's uuid. | |
541 * @param outname The name of the requested output. | |
542 * @param facet The name of the requested facet. | |
543 * @param context The CallContext. | |
544 * | |
545 * @return an attribute in form of a document. | |
546 */ | |
547 protected Document getFacetThemeFromAttribute( | |
548 String uuid, | |
549 String outName, | |
550 String facet, | |
551 String pattern, | |
552 int index, | |
553 CallContext context) | |
554 throws ArtifactDatabaseException | |
555 { | |
556 log.debug("FLYSArtifactCollection.getFacetThemeFromAttribute"); | |
557 | |
558 ArtifactDatabase db = context.getDatabase(); | |
559 CallMeta meta = context.getMeta(); | |
560 | |
561 FLYSContext flysContext = context instanceof FLYSContext | |
562 ? (FLYSContext) context | |
563 : (FLYSContext) context.globalContext(); | |
564 | |
565 Document attr = db.getCollectionItemAttribute(identifier(), uuid, meta); | |
566 | |
567 if (attr == null) { | |
568 attr = initItemAttribute(uuid, facet, pattern, index, outName, context); | |
569 | |
570 if (attr == null) { | |
571 return null; | |
572 } | |
573 } | |
574 | |
575 log.debug("Search attribute of collection item: " + uuid); | |
576 | |
577 Node tmp = (Node) XMLUtils.xpath( | |
578 attr, | |
579 "/art:attribute", | |
580 XPathConstants.NODE, | |
581 ArtifactNamespaceContext.INSTANCE); | |
582 | |
583 if (tmp == null) { | |
584 log.warn("No attribute found. Operation failed."); | |
585 return null; | |
586 } | |
587 | |
588 log.debug("Search theme for facet '" + facet + "' in attribute."); | |
589 | |
590 Node theme = (Node) XMLUtils.xpath( | |
591 tmp, | |
592 "art:themes/theme[@facet='" + facet + | |
593 "' and @index='" + String.valueOf(index) + "']", | |
594 XPathConstants.NODE, | |
595 ArtifactNamespaceContext.INSTANCE); | |
596 | |
597 if (theme == null) { | |
598 log.warn("Could not find the theme in attribute of: " + uuid); | |
599 | |
600 Theme t = getThemeForFacet( | |
601 uuid, facet, pattern, index, outName, context); | |
602 | |
603 if (t == null) { | |
604 log.warn("No theme found for facet: " + facet); | |
605 return null; | |
606 } | |
607 | |
608 addThemeToAttribute(uuid, attr, t, context); | |
609 theme = t.toXML().getFirstChild(); | |
610 } | |
611 | |
612 Document doc = XMLUtils.newDocument(); | |
613 doc.appendChild(doc.importNode(theme, true)); | |
614 | |
615 return doc; | |
616 } | |
617 | |
618 | |
619 /** | |
620 * Adds the theme of a facet to a CollectionItem's attribute. | |
621 * | |
622 * @param uuid The uuid of the artifact. | |
623 * @param attr The current attribute of an artifact. | |
624 * @param t The theme to add. | |
625 * @param context The CallContext. | |
626 */ | |
627 protected void addThemeToAttribute( | |
628 String uuid, | |
629 Document attr, | |
630 Theme t, | |
631 CallContext context) | |
632 { | |
633 log.debug("FLYSArtifactCollection.addThemeToAttribute: " + uuid); | |
634 | |
635 if (t == null) { | |
636 log.warn("Theme is empty - cancel adding it to attribute!"); | |
637 return; | |
638 } | |
639 | |
640 XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator( | |
641 attr, | |
642 ArtifactNamespaceContext.NAMESPACE_URI, | |
643 ArtifactNamespaceContext.NAMESPACE_PREFIX); | |
644 | |
645 Node tmp = (Node) XMLUtils.xpath( | |
646 attr, | |
647 "/art:attribute", | |
648 XPathConstants.NODE, | |
649 ArtifactNamespaceContext.INSTANCE); | |
650 | |
651 if (tmp == null) { | |
652 tmp = ec.create("attribute"); | |
653 attr.appendChild(tmp); | |
654 } | |
655 | |
656 Node themes = (Node) XMLUtils.xpath( | |
657 tmp, | |
658 "art:themes", | |
659 XPathConstants.NODE, | |
660 ArtifactNamespaceContext.INSTANCE); | |
661 | |
662 if (themes == null) { | |
663 themes = ec.create("themes"); | |
664 tmp.appendChild(themes); | |
665 } | |
666 | |
667 themes.appendChild(attr.importNode(t.toXML().getFirstChild(), true)); | |
668 | |
669 try { | |
670 setCollectionItemAttribute(uuid, attr, context); | |
671 | |
672 log.debug("Successfully added theme to item attribute."); | |
673 } | |
674 catch (ArtifactDatabaseException e) { | |
675 // do nothing | |
676 log.warn("Cannot set attribute of item: " + uuid); | |
677 } | |
678 } | |
679 | |
680 | |
681 /** | |
682 * Initializes the attribute of an collection item with the theme of a | |
683 * specific facet. | |
684 * | |
685 * @param uuid The uuid of an artifact. | |
686 * @param facet The name of a facet. | |
687 * @param context The CallContext. | |
688 * | |
689 * @param the new attribute. | |
690 */ | |
691 protected Document initItemAttribute( | |
692 String uuid, | |
693 String facet, | |
694 String pattern, | |
695 int index, | |
696 String outName, | |
697 CallContext context) | |
698 { | |
699 log.info("FLYSArtifactCollection.initItemAttribute"); | |
700 | |
701 Theme t = getThemeForFacet(uuid, facet, pattern, index, outName, context); | |
702 | |
703 if (t == null) { | |
704 log.info("Could not find theme for facet. Cancel initialization."); | |
705 return null; | |
706 } | |
707 | |
708 Document attr = XMLUtils.newDocument(); | |
709 | |
710 addThemeToAttribute(uuid, attr, t, context); | |
711 | |
712 return attr; | |
713 } | |
714 | |
715 | |
716 /** | |
717 * Sets the attribute of a CollectionItem specified by <i>uuid</i> to a new | |
718 * value <i>attr</i>. | |
719 * | |
720 * @param uuid The uuid of the CollectionItem. | |
721 * @param attr The new attribute for the CollectionItem. | |
722 * @param context The CallContext. | |
723 */ | |
724 public void setCollectionItemAttribute( | |
725 String uuid, | |
726 Document attr, | |
727 CallContext context) | |
728 throws ArtifactDatabaseException | |
729 { | |
730 Document doc = ClientProtocolUtils.newSetItemAttributeDocument( | |
731 uuid, | |
732 attr); | |
733 | |
734 if (doc == null) { | |
735 log.warn("Cannot set item attribute: No attribute found."); | |
736 return; | |
737 } | |
738 | |
739 ArtifactDatabase db = context.getDatabase(); | |
740 CallMeta meta = context.getMeta(); | |
741 | |
742 db.setCollectionItemAttribute(identifier(), uuid, doc, meta); | |
743 } | |
744 | |
745 | |
746 /** | |
747 * Returns the theme of a specific facet. | |
748 * | |
749 * @param uuid The uuid of an artifact. | |
750 * @param facet The name of the facet. | |
751 * @param context The CallContext object. | |
752 * | |
753 * @return the desired theme. | |
754 */ | |
755 protected Theme getThemeForFacet( | |
756 String uuid, | |
757 String facet, | |
758 String pattern, | |
759 int index, | |
760 String outName, | |
761 CallContext context) | |
762 { | |
763 log.info("FLYSArtifactCollection.getThemeForFacet: " + facet); | |
764 | |
765 FLYSContext flysContext = context instanceof FLYSContext | |
766 ? (FLYSContext) context | |
767 : (FLYSContext) context.globalContext(); | |
768 | |
769 // Push artifact in flysContext. | |
770 ArtifactDatabase db = context.getDatabase(); | |
771 try { | |
772 FLYSArtifact artifact = (FLYSArtifact) db.getRawArtifact(uuid); | |
773 log.debug("Got raw artifact"); | |
774 flysContext.put(flysContext.ARTIFACT_KEY, artifact); | |
775 } | |
776 catch (ArtifactDatabaseException dbe) { | |
777 log.error("Exception caught when trying to get art.", dbe); | |
778 } | |
779 | |
780 Theme t = ThemeFactory.getTheme(flysContext, facet, pattern, outName); | |
781 | |
782 if (t != null) { | |
783 t.setFacet(facet); | |
784 t.setIndex(index); | |
785 } | |
786 | |
787 return t; | |
788 } | |
789 | |
790 | |
791 /** | |
792 * Returns the OutGenerator for a specified <i>type</i>. | |
793 * | |
794 * @param name The name of the output type. | |
795 * @param type Defines the type of the desired OutGenerator. | |
796 * | |
797 * @return Instance of an OutGenerator for specified <i>type</i>. | |
798 */ | |
799 protected OutGenerator getOutGenerator( | |
800 CallContext context, | |
801 String name, | |
802 String type) | |
803 { | |
804 FLYSContext flysContext = context instanceof FLYSContext | |
805 ? (FLYSContext) context | |
806 : (FLYSContext) context.globalContext(); | |
807 | |
808 Map<String, Class> generators = (Map<String, Class>) | |
809 flysContext.get(FLYSContext.OUTGENERATORS_KEY); | |
810 | |
811 if (generators == null) { | |
812 log.error("No output generators found in the running application!"); | |
813 return null; | |
814 } | |
815 | |
816 Class clazz = generators.get(name); | |
817 | |
818 try { | |
819 return clazz != null ? (OutGenerator) clazz.newInstance() : null; | |
820 } | |
821 catch (InstantiationException ie) { | |
822 log.error(ie, ie); | |
823 } | |
824 catch (IllegalAccessException iae) { | |
825 log.error(iae, iae); | |
826 } | |
827 | |
828 return null; | |
829 } | |
830 | |
831 | |
832 /** | |
833 * Create the Artifacts Node that contains outputmode and statedata. | |
834 * @param uuid uuid of the artifact. | |
835 */ | |
836 protected Element buildArtifactNode( | |
837 ArtifactDatabase database, | |
838 String uuid, | |
839 CallContext context, | |
840 XMLUtils.ElementCreator ec) | |
841 throws ArtifactDatabaseException | |
842 { | |
843 log.debug("Append artifact '" + uuid + "' to collection description"); | |
844 | |
845 // TODO | |
846 String hash = "MYHASH"; | |
847 | |
848 Element ci = ec.create("artifact"); | |
849 ec.addAttr(ci, "uuid", uuid, true); | |
850 ec.addAttr(ci, "hash", hash, true); | |
851 | |
852 // XXX I am not sure if it works well every time with an empty document | |
853 // in the describe operation of an artifact. | |
854 Document description = database.describe(uuid, null, context.getMeta()); | |
855 | |
856 // Add outputmode element(s). | |
857 Node outputModes = (Node) XMLUtils.xpath( | |
858 description, | |
859 XPATH_ARTIFACT_OUTPUTMODES, | |
860 XPathConstants.NODE, | |
861 ArtifactNamespaceContext.INSTANCE); | |
862 | |
863 if (outputModes != null) { | |
864 Document doc = ci.getOwnerDocument(); | |
865 ci.appendChild(doc.importNode(outputModes, true)); | |
866 } | |
867 | |
868 // Add state-data element(s). | |
869 Node dataNode = ci.appendChild( | |
870 ci.getOwnerDocument().createElement("art:data-items")); | |
871 | |
872 NodeList dataNodes = (NodeList) XMLUtils.xpath( | |
873 description, | |
874 XPATH_ARTIFACT_STATE_DATA, | |
875 XPathConstants.NODESET, | |
876 ArtifactNamespaceContext.INSTANCE); | |
877 | |
878 if (dataNodes != null) { | |
879 Document doc = ci.getOwnerDocument(); | |
880 for (int i = 0; i < dataNodes.getLength(); i++) { | |
881 dataNode.appendChild(doc.importNode(dataNodes.item(i), true)); | |
882 } | |
883 } | |
884 | |
885 return ci; | |
886 } | |
887 | |
888 | |
889 /** | |
890 * Inner class to structure/order the themes of a chart. | |
891 */ | |
892 private static class ThemeList { | |
893 private Logger logger = Logger.getLogger(ThemeList.class); | |
894 protected Map<Integer, ManagedFacet> themes; | |
895 | |
896 public ThemeList(Document output) { | |
897 themes = new HashMap<Integer, ManagedFacet>(); | |
898 parse(output); | |
899 } | |
900 | |
901 protected void parse(Document output) { | |
902 NodeList themeList = (NodeList) XMLUtils.xpath( | |
903 output, | |
904 "art:output/art:facet", | |
905 XPathConstants.NODESET, | |
906 ArtifactNamespaceContext.INSTANCE); | |
907 | |
908 int num = themeList != null ? themeList.getLength() : 0; | |
909 | |
910 logger.debug("Output has " + num + " elements."); | |
911 | |
912 if (num == 0) { | |
913 return; | |
914 } | |
915 | |
916 String uri = ArtifactNamespaceContext.NAMESPACE_URI; | |
917 | |
918 for (int i = 0; i < num; i++) { | |
919 Element theme = (Element) themeList.item(i); | |
920 | |
921 ManagedDomFacet facet = new ManagedDomFacet(theme); | |
922 themes.put(Integer.valueOf(facet.getPosition()-1), facet); | |
923 } | |
924 } | |
925 | |
926 public ManagedFacet get(int idx) { | |
927 return themes.get(Integer.valueOf(idx)); | |
928 } | |
929 | |
930 public int size() { | |
931 return themes.size(); | |
932 } | |
933 } | |
934 } | |
935 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : |