comparison flys-artifacts/src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java @ 3818:dc18457b1cef

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

http://dive4elements.wald.intevation.org