changeset 3295:4fc442f1b4f6

Refactored FLYSArtifactCollection. flys-artifacts/trunk@4976 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author Raimund Renkert <raimund.renkert@intevation.de>
date Fri, 13 Jul 2012 09:33:16 +0000
parents 5e52202302e5
children 45af081061e7
files flys-artifacts/ChangeLog flys-artifacts/src/main/java/de/intevation/flys/artifacts/context/FLYSContext.java flys-artifacts/src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java flys-artifacts/src/main/java/de/intevation/flys/exports/OutputHelper.java
diffstat 4 files changed, 585 insertions(+), 501 deletions(-) [+]
line wrap: on
line diff
--- a/flys-artifacts/ChangeLog	Fri Jul 13 08:25:13 2012 +0000
+++ b/flys-artifacts/ChangeLog	Fri Jul 13 09:33:16 2012 +0000
@@ -1,3 +1,15 @@
+2012-07-13  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java:
+	  Refactored. Moved some functionality to FLYSContext and OutputHelper.
+
+	* src/main/java/de/intevation/flys/artifacts/context/FLYSContext.java:
+	  Added 'getOutGenerator' to get a concrete generator. Moved from
+	  FLYSArtifactCollection.
+
+	* src/main/java/de/intevation/flys/exports/OutputHelper.java:
+	  New. Provides the 'doOut' functionality for FYLSArtifactCollection.
+
 2012-07-13	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
 
 	* src/main/java/de/intevation/flys/artifacts/model/sq/Measurements.java:
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/context/FLYSContext.java	Fri Jul 13 08:25:13 2012 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/context/FLYSContext.java	Fri Jul 13 09:33:16 2012 +0000
@@ -1,10 +1,14 @@
 package de.intevation.flys.artifacts.context;
 
+import java.util.Map;
+
 import org.apache.log4j.Logger;
 
 import org.w3c.dom.Document;
 
 import de.intevation.artifactdatabase.DefaultArtifactContext;
+import de.intevation.artifacts.CallContext;
+import de.intevation.flys.exports.OutGenerator;
 
 
 /**
@@ -65,5 +69,45 @@
     public FLYSContext(Document config) {
         super(config);
     }
+
+    /**
+     * Returns the OutGenerator for a specified <i>type</i>.
+     *
+     * @param name The name of the output type.
+     * @param type Defines the type of the desired OutGenerator.
+     *
+     * @return Instance of an OutGenerator for specified <i>type</i>.
+     */
+    public static OutGenerator getOutGenerator(
+        CallContext context,
+        String      name,
+        String      type)
+    {
+
+        FLYSContext flysContext = context instanceof FLYSContext
+            ? (FLYSContext) context
+            : (FLYSContext) context.globalContext();
+
+        Map<String, Class> generators = (Map<String, Class>)
+            flysContext.get(FLYSContext.OUTGENERATORS_KEY);
+
+        if (generators == null) {
+            return null;
+        }
+
+        Class clazz = generators.get(name);
+
+        try {
+            return clazz != null ? (OutGenerator) clazz.newInstance() : null;
+        }
+        catch (InstantiationException ie) {
+            logger.error(ie, ie);
+        }
+        catch (IllegalAccessException iae) {
+            logger.error(iae, iae);
+        }
+
+        return null;
+    }
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java	Fri Jul 13 08:25:13 2012 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java	Fri Jul 13 09:33:16 2012 +0000
@@ -30,16 +30,14 @@
 import de.intevation.artifactdatabase.Backend;
 import de.intevation.artifactdatabase.Backend.PersistentArtifact;
 import de.intevation.artifactdatabase.DefaultArtifactCollection;
-import de.intevation.artifactdatabase.state.ArtifactAndFacet;
 import de.intevation.artifactdatabase.state.Output;
 import de.intevation.artifactdatabase.state.Settings;
 import de.intevation.artifactdatabase.state.StateEngine;
 
 import de.intevation.flys.artifacts.context.FLYSContext;
 import de.intevation.flys.artifacts.FLYSArtifact;
-import de.intevation.flys.artifacts.model.ManagedFacet;
-import de.intevation.flys.artifacts.model.ManagedDomFacet;
 import de.intevation.flys.exports.OutGenerator;
+import de.intevation.flys.exports.OutputHelper;
 import de.intevation.flys.themes.Theme;
 import de.intevation.flys.themes.ThemeFactory;
 
@@ -271,6 +269,9 @@
             String outName = entry.getKey();
             Output output  = entry.getValue();
 
+            if (outName.equals("sq_overview")) {
+                continue;
+            }
             Settings settings = output.getSettings();
 
             if (settings == null) {
@@ -301,7 +302,7 @@
         CollectionAttribute attr,
         String              out
     ) {
-        OutGenerator outGen = getOutGenerator(cc, out, null);
+        OutGenerator outGen = FLYSContext.getOutGenerator(cc, out, null);
 
         if (outGen == null) {
             return null;
@@ -314,7 +315,8 @@
 
         try {
             Document outAttr = getAttribute(cc, attr, out);
-            doOut(outGen, out, out, outAttr, cc);
+            OutputHelper helper = new OutputHelper(identifier());
+            helper.doOut(outGen, out, out, outAttr, cc);
         }
         catch (ArtifactDatabaseException adbe) {
             log.error(adbe, adbe);
@@ -354,10 +356,10 @@
              && type.length() > 0
              && type.indexOf("chartinfo") > 0)
         {
-            generator = getOutGenerator(context, type, subtype);
+            generator = FLYSContext.getOutGenerator(context, type, subtype);
         }
         else {
-            generator = getOutGenerator(context, name, subtype);
+            generator = FLYSContext.getOutGenerator(context, name, subtype);
         }
 
         if (generator == null) {
@@ -380,7 +382,11 @@
 
         try {
             Document attr = getAttribute(context, cAttr, name);
-            doOut(generator, name, subtype, attr, context);
+            OutputHelper helper = new OutputHelper(identifier());
+            if (name.equals("sq_overview")) {
+                helper.doOut(generator, name, subtype, format, context);
+            }
+            helper.doOut(generator, name, subtype, attr, context);
             generator.generate();
         }
         catch (ArtifactDatabaseException adbe) {
@@ -413,132 +419,6 @@
 
 
     /**
-     * Creates the concrete output.
-     *
-     * @param generator The OutGenerator that creates the output.
-     * @param outputName The name of the requested output.
-     * @param attributes The collection's attributes for this concrete output
-     * type.
-     * @param context The context object.
-     */
-    protected void doOut(
-        OutGenerator generator,
-        String       outName,
-        String       facet,
-        Document     attributes,
-        CallContext  context)
-    throws IOException
-    {
-        boolean debug = log.isDebugEnabled();
-
-        if (debug) {
-            log.debug("FLYSArtifactCollection.doOut: " + outName);
-        }
-
-        ThemeList themeList = new ThemeList(attributes);
-
-        int size = themeList.size();
-        if (debug) {
-            log.debug("Output will contain " + size + " elements.");
-        }
-
-        List<ArtifactAndFacet> dataProviders =
-            doBlackboardPass(themeList, context);
-
-        try {
-            for (int i = 0; i < size; i++) {
-                ManagedFacet theme = themeList.get(i);
-
-                if (theme == null) {
-                    log.debug("Theme is empty - no output is generated.");
-                    continue;
-                }
-
-                String art = theme.getArtifact();
-                String facetName = theme.getName();
-
-                if (debug) {
-                    log.debug("Do output for...");
-                    log.debug("... artifact: " + art);
-                    log.debug("... facet: " + facetName);
-                }
-
-                if (outName.equals("export") && !facetName.equals(facet)) {
-                    continue;
-                }
-
-                // Skip invisible themes.
-                if (theme.getVisible() == 0) {
-                    continue;
-                }
-
-                generator.doOut(
-                    dataProviders.get(i),
-                    getFacetThemeFromAttribute(
-                        art,
-                        outName,
-                        facetName,
-                        theme.getDescription(),
-                        theme.getIndex(),
-                        context),
-                    theme.getActive() == 1);
-            }
-        }
-        catch (ArtifactDatabaseException ade) {
-            log.error(ade, ade);
-        }
-    }
-
-
-    /**
-     * Show blackboard (context) to each facet and create a list of
-     * ArtifactAndFacets on the fly (with the same ordering as the passed
-     * ThemeList).
-     * @param themeList ThemeList to create a ArtifactAndFacetList along.
-     * @param context   The "Blackboard".
-     */
-    protected List<ArtifactAndFacet> doBlackboardPass(
-        ThemeList themeList, CallContext context
-    ) {
-        ArrayList<ArtifactAndFacet> dataProviders =
-            new ArrayList<ArtifactAndFacet>();
-        int size = themeList.size();
-
-        try {
-            // Collect all ArtifactAndFacets for blackboard pass.
-            for (int i = 0; i < size; i++) {
-                ManagedFacet theme = themeList.get(i);
-                if (theme == null) {
-                    log.warn("A ManagedFacet in ThemeList is null.");
-                    continue;
-                }
-                String uuid        = theme.getArtifact();
-                Artifact artifact  = getArtifact(uuid, context);
-                FLYSArtifact flys  = (FLYSArtifact) artifact;
-
-                ArtifactAndFacet artifactAndFacet = new ArtifactAndFacet(
-                    artifact,
-                    flys.getNativeFacet(theme));
-
-                // XXX HELP ME PLEASE
-                artifactAndFacet.setFacetDescription(theme.getDescription());
-
-                // Show blackboard to facet.
-                artifactAndFacet.register(context);
-
-                // Add to themes.
-                dataProviders.add(i, artifactAndFacet);
-            }
-        }
-        catch (ArtifactDatabaseException ade) {
-            log.error("ArtifactDatabaseException!", ade);
-        }
-
-        return dataProviders;
-    }
-
-
-    /**
      * @return masterartifact or null if exception/not found.
      */
     protected FLYSArtifact getMasterArtifact(CallContext context)
@@ -721,374 +601,7 @@
     }
 
 
-    /**
-     * Returns the attribute that belongs to an artifact and facet stored in
-     * this collection.
-     *
-     * @param uuid The Artifact's uuid.
-     * @param outname The name of the requested output.
-     * @param facet The name of the requested facet.
-     * @param context The CallContext.
-     *
-     * @return an attribute in form of a document.
-     */
-    protected Document getFacetThemeFromAttribute(
-        String      uuid,
-        String      outName,
-        String      facet,
-        String      pattern,
-        int         index,
-        CallContext context)
-    throws    ArtifactDatabaseException
-    {
-        boolean debug = log.isDebugEnabled();
-
-        if (debug) {
-            log.debug(
-                "FLYSArtifactCollection.getFacetThemeFromAttribute(facet="
-                + facet + ", index=" + index);
-        }
-
-
-        ArtifactDatabase db = context.getDatabase();
-        CallMeta       meta = context.getMeta();
-
-        FLYSContext flysContext = context instanceof FLYSContext
-            ? (FLYSContext) context
-            : (FLYSContext) context.globalContext();
-
-        Document attr = db.getCollectionItemAttribute(identifier(), uuid, meta);
-
-        if (attr == null) {
-            attr = initItemAttribute(uuid, facet, pattern, index, outName, context);
-
-            if (attr == null) {
-                return null;
-            }
-        }
-
-        if (debug) {
-            log.debug("Search attribute of collection item: " + uuid);
-        }
-
-        Node tmp = (Node) XMLUtils.xpath(
-            attr,
-            "/art:attribute",
-            XPathConstants.NODE,
-            ArtifactNamespaceContext.INSTANCE);
-
-        if (tmp == null) {
-            log.warn("No attribute found. Operation failed.");
-            return null;
-        }
-
-        if (debug) {
-            log.debug("Search theme for facet '" + facet + "' in attribute.");
-        }
-
-        Map<String, String> vars = new HashMap<String, String>();
-        vars.put("facet", facet);
-        vars.put("index", String.valueOf(index));
-
-        Node theme = (Node) XMLUtils.xpath(
-            tmp,
-            "art:themes/theme[@facet=$facet and @index=$index]",
-            XPathConstants.NODE,
-            ArtifactNamespaceContext.INSTANCE,
-            vars);
-
-        if (theme == null) {
-            log.warn("Could not find the theme in attribute of: " + facet + " " + uuid);
-
-            Theme t = getThemeForFacet(
-                uuid, facet, pattern, index, outName, context);
-
-            if (t == null) {
-                log.warn("No theme found for facet: " + facet);
-                return null;
-            }
-
-            addThemeToAttribute(uuid, attr, t, context);
-            theme = t.toXML().getFirstChild();
-        }
-
-        Document doc = XMLUtils.newDocument();
-        doc.appendChild(doc.importNode(theme, true));
-
-        return doc;
-    }
-
-
-    /**
-     * Adds the theme of a facet to a CollectionItem's attribute.
-     *
-     * @param uuid The uuid of the artifact.
-     * @param attr The current attribute of an artifact.
-     * @param t The theme to add.
-     * @param context The CallContext.
-     */
-    protected void addThemeToAttribute(
-        String      uuid,
-        Document    attr,
-        Theme       t,
-        CallContext context)
-    {
-        log.debug("FLYSArtifactCollection.addThemeToAttribute: " + uuid);
-
-        if (t == null) {
-            log.warn("Theme is empty - cancel adding it to attribute!");
-            return;
-        }
-
-        XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator(
-            attr,
-            ArtifactNamespaceContext.NAMESPACE_URI,
-            ArtifactNamespaceContext.NAMESPACE_PREFIX);
-
-        Node tmp = (Node) XMLUtils.xpath(
-            attr,
-            "/art:attribute",
-            XPathConstants.NODE,
-            ArtifactNamespaceContext.INSTANCE);
-
-        if (tmp == null) {
-            tmp = ec.create("attribute");
-            attr.appendChild(tmp);
-        }
-
-        Node themes = (Node) XMLUtils.xpath(
-            tmp,
-            "art:themes",
-            XPathConstants.NODE,
-            ArtifactNamespaceContext.INSTANCE);
-
-        if (themes == null) {
-            themes = ec.create("themes");
-            tmp.appendChild(themes);
-        }
-
-        themes.appendChild(attr.importNode(t.toXML().getFirstChild(), true));
-
-        try {
-            setCollectionItemAttribute(uuid, attr, context);
-        }
-        catch (ArtifactDatabaseException e) {
-            // do nothing
-            log.warn("Cannot set attribute of item: " + uuid);
-        }
-    }
 
 
-    /**
-     * Initializes the attribute of an collection item with the theme of a
-     * specific facet.
-     *
-     * @param uuid The uuid of an artifact.
-     * @param facet The name of a facet.
-     * @param context The CallContext.
-     *
-     * @param the new attribute.
-     */
-    protected Document initItemAttribute(
-        String      uuid,
-        String      facet,
-        String      pattern,
-        int         index,
-        String      outName,
-        CallContext context)
-    {
-        boolean debug = log.isDebugEnabled();
-
-        if (debug) {
-            log.debug("FLYSArtifactCollection.initItemAttribute");
-        }
-
-        Theme t = getThemeForFacet(uuid, facet, pattern, index, outName, context);
-
-        if (t == null) {
-            log.info("Could not find theme for facet. Cancel initialization.");
-            return null;
-        }
-
-        Document attr = XMLUtils.newDocument();
-        addThemeToAttribute(uuid, attr, t, context);
-
-        if (debug) {
-            log.debug("initItemAttribute for facet " + facet + ": "
-                + XMLUtils.toString(attr));
-        }
-
-        return attr;
-    }
-
-
-    /**
-     * Sets the attribute of a CollectionItem specified by <i>uuid</i> to a new
-     * value <i>attr</i>.
-     *
-     * @param uuid The uuid of the CollectionItem.
-     * @param attr The new attribute for the CollectionItem.
-     * @param context The CallContext.
-     */
-    public void setCollectionItemAttribute(
-        String      uuid,
-        Document    attr,
-        CallContext context)
-    throws ArtifactDatabaseException
-    {
-        Document doc = ClientProtocolUtils.newSetItemAttributeDocument(
-            uuid,
-            attr);
-
-        if (doc == null) {
-            log.warn("Cannot set item attribute: No attribute found.");
-            return;
-        }
-
-        ArtifactDatabase db = context.getDatabase();
-        CallMeta       meta = context.getMeta();
-
-        db.setCollectionItemAttribute(identifier(), uuid, doc, meta);
-    }
-
-
-    /**
-     * Returns the theme of a specific facet.
-     *
-     * @param uuid The uuid of an artifact.
-     * @param facet The name of the facet.
-     * @param context The CallContext object.
-     *
-     * @return the desired theme.
-     */
-    protected Theme getThemeForFacet(
-        String uuid,
-        String facet,
-        String pattern,
-        int    index,
-        String outName,
-        CallContext context)
-    {
-        log.info("FLYSArtifactCollection.getThemeForFacet: " + facet);
-
-        FLYSContext flysContext = context instanceof FLYSContext
-            ? (FLYSContext) context
-            : (FLYSContext) context.globalContext();
-
-        // Push artifact in flysContext.
-        ArtifactDatabase db = context.getDatabase();
-        try {
-            FLYSArtifact artifact = (FLYSArtifact) db.getRawArtifact(uuid);
-            log.debug("Got raw artifact");
-            flysContext.put(FLYSContext.ARTIFACT_KEY, artifact);
-        }
-        catch (ArtifactDatabaseException dbe) {
-            log.error("Exception caught when trying to get art.", dbe);
-        }
-
-        Theme t = ThemeFactory.getTheme(
-                      flysContext,
-                      facet,
-                      pattern,
-                      outName,
-                      "default");
-
-        if (t != null) {
-            t.setFacet(facet);
-            t.setIndex(index);
-        }
-
-        return t;
-    }
-
-
-    /**
-     * Returns the OutGenerator for a specified <i>type</i>.
-     *
-     * @param name The name of the output type.
-     * @param type Defines the type of the desired OutGenerator.
-     *
-     * @return Instance of an OutGenerator for specified <i>type</i>.
-     */
-    protected OutGenerator getOutGenerator(
-        CallContext context,
-        String      name,
-        String      type)
-    {
-        log.debug("Search OutGenerator for Output '" + name + "'");
-
-        FLYSContext flysContext = context instanceof FLYSContext
-            ? (FLYSContext) context
-            : (FLYSContext) context.globalContext();
-
-        Map<String, Class> generators = (Map<String, Class>)
-            flysContext.get(FLYSContext.OUTGENERATORS_KEY);
-
-        if (generators == null) {
-            log.error("No output generators found in the running application!");
-            return null;
-        }
-
-        Class clazz = generators.get(name);
-
-        try {
-            return clazz != null ? (OutGenerator) clazz.newInstance() : null;
-        }
-        catch (InstantiationException ie) {
-            log.error(ie, ie);
-        }
-        catch (IllegalAccessException iae) {
-            log.error(iae, iae);
-        }
-
-        return null;
-    }
-
-
-    /**
-     * Inner class to structure/order the themes of a chart.
-     */
-    private static class ThemeList {
-        private Logger logger = Logger.getLogger(ThemeList.class);
-        protected Map<Integer, ManagedFacet> themes;
-
-        public ThemeList(Document output) {
-            themes = new HashMap<Integer, ManagedFacet>();
-            parse(output);
-        }
-
-        protected void parse(Document output) {
-            NodeList themeList = (NodeList) XMLUtils.xpath(
-                output,
-                "art:output/art:facet",
-                XPathConstants.NODESET,
-                ArtifactNamespaceContext.INSTANCE);
-
-            int num = themeList != null ? themeList.getLength() : 0;
-
-            logger.debug("Output has " +  num + " elements.");
-
-            if (num == 0) {
-                return;
-            }
-
-            String uri = ArtifactNamespaceContext.NAMESPACE_URI;
-
-            for (int i = 0; i < num; i++) {
-                Element theme = (Element) themeList.item(i);
-
-                ManagedDomFacet facet = new ManagedDomFacet(theme);
-                themes.put(Integer.valueOf(facet.getPosition()-1), facet);
-            }
-        }
-
-        public ManagedFacet get(int idx) {
-            return themes.get(Integer.valueOf(idx));
-        }
-
-        public int size() {
-            return themes.size();
-        }
-    }
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/OutputHelper.java	Fri Jul 13 09:33:16 2012 +0000
@@ -0,0 +1,515 @@
+package de.intevation.flys.exports;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.xml.xpath.XPathConstants;
+
+import org.apache.log4j.Logger;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import de.intevation.artifactdatabase.Backend;
+import de.intevation.artifactdatabase.Backend.PersistentArtifact;
+import de.intevation.artifactdatabase.state.ArtifactAndFacet;
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.ArtifactDatabase;
+import de.intevation.artifacts.ArtifactDatabaseException;
+import de.intevation.artifacts.CallContext;
+import de.intevation.artifacts.CallMeta;
+import de.intevation.artifacts.common.ArtifactNamespaceContext;
+import de.intevation.artifacts.common.utils.ClientProtocolUtils;
+import de.intevation.artifacts.common.utils.XMLUtils;
+import de.intevation.flys.artifacts.FLYSArtifact;
+import de.intevation.flys.artifacts.context.FLYSContext;
+import de.intevation.flys.artifacts.model.ManagedDomFacet;
+import de.intevation.flys.artifacts.model.ManagedFacet;
+import de.intevation.flys.themes.Theme;
+import de.intevation.flys.themes.ThemeFactory;
+
+public class OutputHelper {
+    /** The logger used in this class. */
+    private static Logger log = Logger.getLogger(OutputHelper.class);
+
+    protected String identifier;
+
+    public OutputHelper(String identifier) {
+        this.identifier = identifier;
+    }
+    /**
+     * Creates a concrete output.
+     *
+     * @param generator The OutGenerator that creates the output.
+     * @param outputName The name of the requested output.
+     * @param attributes The collection's attributes for this concrete output
+     * type.
+     * @param context The context object.
+     */
+    public void doOut(
+        OutGenerator generator,
+        String       outName,
+        String       facet,
+        Document     attributes,
+        CallContext  context)
+    throws IOException
+    {
+        boolean debug = log.isDebugEnabled();
+
+        if (debug) {
+            log.debug("FLYSArtifactCollection.doOut: " + outName);
+        }
+
+        ThemeList themeList = new ThemeList(attributes);
+
+        int size = themeList.size();
+        if (debug) {
+            log.debug("Output will contain " + size + " elements.");
+        }
+
+        List<ArtifactAndFacet> dataProviders =
+            doBlackboardPass(themeList, context);
+
+        try {
+            for (int i = 0; i < size; i++) {
+                ManagedFacet theme = themeList.get(i);
+
+                if (theme == null) {
+                    log.debug("Theme is empty - no output is generated.");
+                    continue;
+                }
+
+                String art = theme.getArtifact();
+                String facetName = theme.getName();
+
+                if (debug) {
+                    log.debug("Do output for...");
+                    log.debug("... artifact: " + art);
+                    log.debug("... facet: " + facetName);
+                }
+
+                if (outName.equals("export") && !facetName.equals(facet)) {
+                    continue;
+                }
+
+                // Skip invisible themes.
+                if (theme.getVisible() == 0) {
+                    continue;
+                }
+
+                if (outName.equals("sq_overview")) {
+                    generator.doOut(
+                        dataProviders.get(i),
+                        attributes,
+                        theme.getActive() == 1);
+                }
+                else {
+                    generator.doOut(
+                            dataProviders.get(i),
+                            getFacetThemeFromAttribute(
+                                art,
+                                outName,
+                                facetName,
+                                theme.getDescription(),
+                                theme.getIndex(),
+                                context),
+                            theme.getActive() == 1);
+                }
+            }
+        }
+        catch (ArtifactDatabaseException ade) {
+            log.error(ade, ade);
+        }
+    }
+    /**
+     * Returns the attribute that belongs to an artifact and facet stored in
+     * this collection.
+     *
+     * @param uuid The Artifact's uuid.
+     * @param outname The name of the requested output.
+     * @param facet The name of the requested facet.
+     * @param context The CallContext.
+     *
+     * @return an attribute in form of a document.
+     */
+    protected Document getFacetThemeFromAttribute(
+        String      uuid,
+        String      outName,
+        String      facet,
+        String      pattern,
+        int         index,
+        CallContext context)
+    throws    ArtifactDatabaseException
+    {
+        boolean debug = log.isDebugEnabled();
+
+        if (debug) {
+            log.debug(
+                "FLYSArtifactCollection.getFacetThemeFromAttribute(facet="
+                + facet + ", index=" + index + ")");
+        }
+
+
+        ArtifactDatabase db = context.getDatabase();
+        CallMeta       meta = context.getMeta();
+
+        FLYSContext flysContext = context instanceof FLYSContext
+            ? (FLYSContext) context
+            : (FLYSContext) context.globalContext();
+
+        Document attr = db.getCollectionItemAttribute(identifier, uuid, meta);
+
+        if (attr == null) {
+            attr = initItemAttribute(uuid, facet, pattern, index, outName, context);
+
+            if (attr == null) {
+                return null;
+            }
+        }
+
+        if (debug) {
+            log.debug("Search attribute of collection item: " + uuid);
+        }
+
+        Node tmp = (Node) XMLUtils.xpath(
+            attr,
+            "/art:attribute",
+            XPathConstants.NODE,
+            ArtifactNamespaceContext.INSTANCE);
+
+        if (tmp == null) {
+            log.warn("No attribute found. Operation failed.");
+            return null;
+        }
+
+        if (debug) {
+            log.debug("Search theme for facet '" + facet + "' in attribute.");
+        }
+
+        Map<String, String> vars = new HashMap<String, String>();
+        vars.put("facet", facet);
+        vars.put("index", String.valueOf(index));
+
+        Node theme = (Node) XMLUtils.xpath(
+            tmp,
+            "art:themes/theme[@facet=$facet and @index=$index]",
+            XPathConstants.NODE,
+            ArtifactNamespaceContext.INSTANCE,
+            vars);
+
+        if (theme == null) {
+            log.warn("Could not find the theme in attribute of: " + facet + " " + uuid);
+
+            Theme t = getThemeForFacet(
+                uuid, facet, pattern, index, outName, context);
+
+            if (t == null) {
+                log.warn("No theme found for facet: " + facet);
+                return null;
+            }
+
+            addThemeToAttribute(uuid, attr, t, context);
+            theme = t.toXML().getFirstChild();
+        }
+
+        Document doc = XMLUtils.newDocument();
+        doc.appendChild(doc.importNode(theme, true));
+
+        return doc;
+    }
+    /**
+     * Adds the theme of a facet to a CollectionItem's attribute.
+     *
+     * @param uuid The uuid of the artifact.
+     * @param attr The current attribute of an artifact.
+     * @param t The theme to add.
+     * @param context The CallContext.
+     */
+    protected void addThemeToAttribute(
+        String      uuid,
+        Document    attr,
+        Theme       t,
+        CallContext context)
+    {
+        log.debug("FLYSArtifactCollection.addThemeToAttribute: " + uuid);
+
+        if (t == null) {
+            log.warn("Theme is empty - cancel adding it to attribute!");
+            return;
+        }
+
+        XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator(
+            attr,
+            ArtifactNamespaceContext.NAMESPACE_URI,
+            ArtifactNamespaceContext.NAMESPACE_PREFIX);
+
+        Node tmp = (Node) XMLUtils.xpath(
+            attr,
+            "/art:attribute",
+            XPathConstants.NODE,
+            ArtifactNamespaceContext.INSTANCE);
+
+        if (tmp == null) {
+            tmp = ec.create("attribute");
+            attr.appendChild(tmp);
+        }
+
+        Node themes = (Node) XMLUtils.xpath(
+            tmp,
+            "art:themes",
+            XPathConstants.NODE,
+            ArtifactNamespaceContext.INSTANCE);
+
+        if (themes == null) {
+            themes = ec.create("themes");
+            tmp.appendChild(themes);
+        }
+
+        themes.appendChild(attr.importNode(t.toXML().getFirstChild(), true));
+
+        try {
+            setCollectionItemAttribute(uuid, attr, context);
+        }
+        catch (ArtifactDatabaseException e) {
+            // do nothing
+            log.warn("Cannot set attribute of item: " + uuid);
+        }
+    }
+
+    /**
+     * Sets the attribute of a CollectionItem specified by <i>uuid</i> to a new
+     * value <i>attr</i>.
+     *
+     * @param uuid The uuid of the CollectionItem.
+     * @param attr The new attribute for the CollectionItem.
+     * @param context The CallContext.
+     */
+    public void setCollectionItemAttribute(
+        String      uuid,
+        Document    attr,
+        CallContext context)
+    throws ArtifactDatabaseException
+    {
+        Document doc = ClientProtocolUtils.newSetItemAttributeDocument(
+            uuid,
+            attr);
+
+        if (doc == null) {
+            log.warn("Cannot set item attribute: No attribute found.");
+            return;
+        }
+
+        ArtifactDatabase db = context.getDatabase();
+        CallMeta       meta = context.getMeta();
+
+        db.setCollectionItemAttribute(identifier, uuid, doc, meta);
+    }
+
+
+    /**
+     * Show blackboard (context) to each facet and create a list of
+     * ArtifactAndFacets on the fly (with the same ordering as the passed
+     * ThemeList).
+     * @param themeList ThemeList to create a ArtifactAndFacetList along.
+     * @param context   The "Blackboard".
+     */
+    protected List<ArtifactAndFacet> doBlackboardPass(
+        ThemeList themeList, CallContext context
+    ) {
+        ArrayList<ArtifactAndFacet> dataProviders =
+            new ArrayList<ArtifactAndFacet>();
+        int size = themeList.size();
+
+        try {
+            // Collect all ArtifactAndFacets for blackboard pass.
+            for (int i = 0; i < size; i++) {
+                ManagedFacet theme = themeList.get(i);
+                if (theme == null) {
+                    log.warn("A ManagedFacet in ThemeList is null.");
+                    continue;
+                }
+                String uuid        = theme.getArtifact();
+                Artifact artifact  = getArtifact(uuid, context);
+                FLYSArtifact flys  = (FLYSArtifact) artifact;
+
+                ArtifactAndFacet artifactAndFacet = new ArtifactAndFacet(
+                    artifact,
+                    flys.getNativeFacet(theme));
+
+                // XXX HELP ME PLEASE
+                artifactAndFacet.setFacetDescription(theme.getDescription());
+
+                // Show blackboard to facet.
+                artifactAndFacet.register(context);
+
+                // Add to themes.
+                dataProviders.add(i, artifactAndFacet);
+            }
+        }
+        catch (ArtifactDatabaseException ade) {
+            log.error("ArtifactDatabaseException!", ade);
+        }
+
+        return dataProviders;
+    }
+    /**
+     * Returns a concrete Artifact of this collection specified by its uuid.
+     *
+     * @param uuid The Artifact's uuid.
+     * @param context The CallContext.
+     *
+     * @return an Artifact.
+     */
+    protected Artifact getArtifact(String uuid, CallContext context)
+    throws    ArtifactDatabaseException
+    {
+        log.debug("FLYSArtifactCollection.getArtifact");
+
+        Backend backend               = Backend.getInstance();
+        PersistentArtifact persistent = backend.getArtifact(uuid);
+
+        return persistent != null ? persistent.getArtifact() : null;
+    }
+
+    /**
+     * Initializes the attribute of an collection item with the theme of a
+     * specific facet.
+     *
+     * @param uuid The uuid of an artifact.
+     * @param facet The name of a facet.
+     * @param context The CallContext.
+     *
+     * @param the new attribute.
+     */
+    protected Document initItemAttribute(
+        String      uuid,
+        String      facet,
+        String      pattern,
+        int         index,
+        String      outName,
+        CallContext context)
+    {
+        boolean debug = log.isDebugEnabled();
+
+        if (debug) {
+            log.debug("FLYSArtifactCollection.initItemAttribute");
+        }
+
+        Theme t = getThemeForFacet(uuid, facet, pattern, index, outName, context);
+
+        if (t == null) {
+            log.info("Could not find theme for facet. Cancel initialization.");
+            return null;
+        }
+
+        Document attr = XMLUtils.newDocument();
+        addThemeToAttribute(uuid, attr, t, context);
+
+        if (debug) {
+            log.debug("initItemAttribute for facet " + facet + ": "
+                + XMLUtils.toString(attr));
+        }
+
+        return attr;
+    }
+    
+        /**
+     * Returns the theme of a specific facet.
+     *
+     * @param uuid The uuid of an artifact.
+     * @param facet The name of the facet.
+     * @param context The CallContext object.
+     *
+     * @return the desired theme.
+     */
+    protected Theme getThemeForFacet(
+        String uuid,
+        String facet,
+        String pattern,
+        int    index,
+        String outName,
+        CallContext context)
+    {
+        log.info("FLYSArtifactCollection.getThemeForFacet: " + facet);
+
+        FLYSContext flysContext = context instanceof FLYSContext
+            ? (FLYSContext) context
+            : (FLYSContext) context.globalContext();
+
+        // Push artifact in flysContext.
+        ArtifactDatabase db = context.getDatabase();
+        try {
+            FLYSArtifact artifact = (FLYSArtifact) db.getRawArtifact(uuid);
+            log.debug("Got raw artifact");
+            flysContext.put(FLYSContext.ARTIFACT_KEY, artifact);
+        }
+        catch (ArtifactDatabaseException dbe) {
+            log.error("Exception caught when trying to get art.", dbe);
+        }
+
+        Theme t = ThemeFactory.getTheme(
+                      flysContext,
+                      facet,
+                      pattern,
+                      outName,
+                      "default");
+
+        if (t != null) {
+            t.setFacet(facet);
+            t.setIndex(index);
+        }
+
+        return t;
+    }
+
+    /**
+     * Inner class to structure/order the themes of a chart.
+     */
+    private static class ThemeList {
+        private Logger logger = Logger.getLogger(ThemeList.class);
+        protected Map<Integer, ManagedFacet> themes;
+
+        public ThemeList(Document output) {
+            themes = new HashMap<Integer, ManagedFacet>();
+            parse(output);
+        }
+
+        protected void parse(Document output) {
+            NodeList themeList = (NodeList) XMLUtils.xpath(
+                output,
+                "art:output/art:facet",
+                XPathConstants.NODESET,
+                ArtifactNamespaceContext.INSTANCE);
+
+            int num = themeList != null ? themeList.getLength() : 0;
+
+            logger.debug("Output has " +  num + " elements.");
+
+            if (num == 0) {
+                return;
+            }
+
+            String uri = ArtifactNamespaceContext.NAMESPACE_URI;
+
+            for (int i = 0; i < num; i++) {
+                Element theme = (Element) themeList.item(i);
+
+                ManagedDomFacet facet = new ManagedDomFacet(theme);
+                themes.put(Integer.valueOf(facet.getPosition()-1), facet);
+            }
+        }
+
+        public ManagedFacet get(int idx) {
+            return themes.get(Integer.valueOf(idx));
+        }
+
+        public int size() {
+            return themes.size();
+        }
+    }
+
+}

http://dive4elements.wald.intevation.org