view flys-artifacts/src/main/java/de/intevation/flys/collections/AttributeWriter.java @ 5627:2d9eb188fa51

Flys Issue 759 write longer strings and explicitly break the lines This makes the dem hover item layout more robust as it works with different string lengths
author Andre Heinecke <aheinecke@intevation.de>
date Wed, 10 Apr 2013 10:25:33 +0200
parents 345f3bba6f15
children
line wrap: on
line source
package de.intevation.flys.collections;

import java.util.ArrayList;
import java.util.List;
import java.util.HashMap;
import java.util.Map;

import org.apache.log4j.Logger;

import de.intevation.artifacts.ArtifactDatabase;
import de.intevation.artifacts.ArtifactDatabaseException;

import de.intevation.artifactdatabase.state.Facet;
import de.intevation.artifactdatabase.state.FacetActivity;
import de.intevation.artifactdatabase.state.Output;

import de.intevation.flys.artifacts.FLYSArtifact;
import de.intevation.flys.artifacts.model.ManagedFacet;

/**
 * Create attribute- element of describe document of an ArtifactCollection.
 * The attribute-element contains the merged output of all outputmodes and
 * facets that are part of the collection.
 */
public class AttributeWriter {

    /** ArtifactDatabase used to fetch Artifacts. */
    protected ArtifactDatabase db = null;

    protected Map<String, Output> oldAttr;

    protected Map<String, Output> newAttr;

    /** List of already seen facets. */
    protected List<Facet>         oldFacets;

    /** List of "new" facets. */
    protected List<Facet>         newFacets;

    /**
     * "Compatibility matrix", mapws list of facet names to output names.
     * Any facet that is not found in the list for a specific output will
     * not be added to the resulting document.
     */
    protected Map<String, List<String>> compatibilities;


    /** The result of the <i>write()</i> operation.*/
    protected CollectionAttribute attribute;


    private static Logger logger = Logger.getLogger(AttributeWriter.class);


    /**
     * Create a AttributeWriter.
     * Attributes not present in newAttr will not be included in the document.
     * @param db      Database to fetch artifacts.
     * @param oldAttr "Old" (possibly user-changed) outputs.
     * @param newAttr "New" (eventually re-read in its original, unchanged
     *                form) outputs.
     * @param matrix Compatibility matrix, mapping output names to list of
     *               facet names that can be included in this out.
     */
    public AttributeWriter(
        ArtifactDatabase    db,
        CollectionAttribute attribute,
        Map<String, Output> oldAttr,
        List<Facet>         oldFacets,
        Map<String, Output> newAttr,
        List<Facet>         newFacets,
        Map<String, List<String>> matrix)
    {
        this.db        = db;
        this.attribute = attribute;
        this.oldAttr   = oldAttr;
        this.newAttr   = newAttr;
        this.oldFacets = oldFacets;
        this.newFacets = newFacets;
        this.compatibilities = matrix;
    }


    /**
     * Create document by merging outputs given in
     * constructor.
     *
     * The "new" set rules about existance of attributes, so anything not
     * present in it will not be included in the resulting document.
     * The "old" set rules about the content of attributes (as user changes
     * are recorded here and not in the new set).
     *
     * @return document with merged outputs as described.
     */
    protected CollectionAttribute write() {

        boolean debug = logger.isDebugEnabled();

        for (Map.Entry<String, Output> entry: newAttr.entrySet()) {
            String outName = entry.getKey();
            Output a       = entry.getValue();

            if (!attribute.hasOutput(outName)) {
                attribute.addOutput(outName, a);
            }

            attribute.clearFacets(outName);

            if (debug) {
                logger.debug("Merge Output: " + outName);
                logger.debug("   old Facets: " + oldFacets.size());
                logger.debug("   new Facets: " + newFacets.size());
            }

            writeOutput(a.getName(), newFacets, oldFacets);
        }

        // THIS CALL IS ABSOLUTELY NECESSARY!
        attribute.cleanEmptyOutputs();

        return attribute;
    }


    /**
     * @param outputName the "new" outputs name
     * @param newOutFacets Facets of the new outputs
     * @param oldOutFacets Facets of the old outputs (can be null)
     */
    protected void writeOutput(
        String      outputName,
        List<Facet> newOutFacets,
        List<Facet> oldOutFacets
    ) {
        List<String> compatFacets = this.compatibilities.get(outputName);

        if (logger.isDebugEnabled() && compatFacets != null) {
            logger.debug("Compabitle Facets:");
            for (String compatible: compatFacets) {
                logger.debug(   "- " + compatible);
            }
        }

        try {
            writeFacets(outputName, newOutFacets, oldOutFacets, compatFacets);
        }
        catch (ArtifactDatabaseException ade) {
            logger.error(ade, ade);
        }
    }


    /**
     * @param newFacets the new facets
     * @param oldFacets the old facets
     * @param compatibleFacets List of facets to accept
     * @return true if any facets are written to the out.
     */
    protected boolean writeFacets(
        String        outputName,
        List<Facet>   newFacets,
        List<Facet>   oldFacets,
        List<String>  compatibleFacets)
    throws ArtifactDatabaseException
    {
        if (compatibleFacets == null) {
            logger.warn("No compatible facets, not generating out " + outputName + ".");
            return false;
        }

        int num = newFacets.size();

        // Add all new Facets either in their old state or (if really
        // new) as they are.
        List<ManagedFacet> currentFacets      = new ArrayList<ManagedFacet>();
        List<ManagedFacet> genuinelyNewFacets = new ArrayList<ManagedFacet>();

        boolean debug = logger.isDebugEnabled();
        if (debug) {
           logger.debug("Compatible facets are " + compatibleFacets);
        }

        for (int i = 0; i < num; i++) {
            ManagedFacet facet = (ManagedFacet) newFacets.get(i);

            if (debug) {
                logger.debug("Try to add Facet: " + facet.getName());
            }

            if (!compatibleFacets.contains(facet.getName())) {
                logger.warn("Have incompatible facet, skip: " + facet.getName());
                continue;
            }
            else {
                logger.debug("Have compatible facet: " + facet.getName());
            }

            ManagedFacet picked = pickFacet(facet, oldFacets);

            if (facet.equals(picked)) {
                genuinelyNewFacets.add(picked);
            }
            else {
                currentFacets.add(picked);
            }
        }

        FacetActivity.Registry registry = FacetActivity.Registry.getInstance();

        // With each genuinely new Facet, figure out whether it comes to live
        // in/activate.
        for (ManagedFacet newMF: genuinelyNewFacets) {
            FLYSArtifact flys =
                (FLYSArtifact)db.getRawArtifact(newMF.getArtifact());

            boolean isActive = registry.isInitialActive(
                flys.getName(), flys, newMF, outputName);

            newMF.setActive(isActive ? 1 : 0);
        }

        // For each genuinely new Facet check positional conflicts.
        for (ManagedFacet newMF: genuinelyNewFacets) {
            boolean conflicts = true;
            // Loop until all conflicts resolved.
            while (conflicts) {
                conflicts = false;
                for (ManagedFacet oldMF: currentFacets) {
                    if (newMF.getPosition() == oldMF.getPosition()) {
                        conflicts = true;
                        if (debug) {
                            logger.debug(
                                "Positional conflict while merging " +
                                "facets, pushing newest facet 1 up (" +
                                newMF.getPosition() + ")");
                        }
                        newMF.setPosition(newMF.getPosition() + 1);
                        break;
                    }
                }
            }
            currentFacets.add(newMF);
        }

        // Fill/correct "gaps" (e.g. position 1,2,5 are taken, after gap filling
        // expect positions 1,2,3 [5->3])
        // Preparations to be able to detect gaps.
        Map<Integer, ManagedFacet> mfmap =
            new HashMap<Integer, ManagedFacet>();
        int max = 0;
        for (ManagedFacet mf: currentFacets) {
            int pos = mf.getPosition();
            mfmap.put(Integer.valueOf(pos), mf);
            if (pos > max) max = pos;
        }

        // Finally do gap correction.
        if (max != currentFacets.size()) {
            int gap = 0;
            for (int i = 1; i <= max; i++) {
                ManagedFacet mf = mfmap.get(Integer.valueOf(i));
                if (mf == null) {
                    gap++;
                    continue;
                }
                mf.setPosition(mf.getPosition() - gap);
            }
        }

        // Now add all facets.
        for (ManagedFacet oldMF: currentFacets) {
            attribute.addFacet(outputName, oldMF);
        }

        return !currentFacets.isEmpty();
    }


    /**
     * Returns the facet to be added to Document.
     * Return the new facet only if the "same" facet was not present before.
     * Return the "old" facet otherwise (user-defined information sticks
     * to it).
     * @param facet     the new facet.
     * @param oldFacets the old facets, new facet is compared against each of
     *                  these.
     * @return facet if genuinely new, matching old facet otherwise.
     */
    protected ManagedFacet pickFacet(ManagedFacet facet, List<Facet> oldFacets)
    {
        if (oldFacets == null) {
            logger.debug("No old facets to compare a new to found.");
            return facet;
        }

        String hash = facet.getName() + facet.getIndex() + facet.getArtifact();

        // Compare "new" facet with all old facets.
        // Take oldFacet if that facet was already present (otherwise
        // information is lost, the new one otherwise.
        for (Facet oFacet: oldFacets) {
            ManagedFacet oldFacet = (ManagedFacet) oFacet;
            String oldHash = oldFacet.getName()
                           + oldFacet.getIndex()
                           + oldFacet.getArtifact();
            if (hash.equals(oldHash)) {
                return oldFacet;
            }
        }
        return facet;
    }
}
// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :

http://dive4elements.wald.intevation.org