view flys-artifacts/src/main/java/de/intevation/flys/exports/OutputHelper.java @ 4221:480de0dbca8e

Extended location input helper. The locationpicker has now an attribute whether the input is distance or location to display one or two clickable columns. Replaced the record click handler with cell click handler.
author Raimund Renkert <rrenkert@intevation.de>
date Tue, 23 Oct 2012 13:17:20 +0200
parents 8e66293c5369
children 670e98f5a441
line wrap: on
line source
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();

        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) {
            log.debug("found theme for facet '" + facet + "'");
            t.setFacet(facet);
            t.setIndex(index);
        }
        else {
            log.warn("unable to find theme for facet '" + facet + "'");
        }

        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;
            }

            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 :

http://dive4elements.wald.intevation.org