Mercurial > dive4elements > river
view flys-artifacts/src/main/java/de/intevation/flys/collections/AttributeWriter.java @ 1927:1f90fdd4fa04
Resolved TODO about caching certain WstValueTables.
flys-artifacts/trunk@3307 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author | Felix Wolfsteller <felix.wolfsteller@intevation.de> |
---|---|
date | Wed, 23 Nov 2011 11:07:34 +0000 |
parents | 490ab097f58c |
children | 0b466bd4ab24 |
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 org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import de.intevation.artifacts.ArtifactDatabase; import de.intevation.artifacts.ArtifactDatabaseException; import de.intevation.artifacts.ArtifactNamespaceContext; import de.intevation.artifactdatabase.state.Facet; import de.intevation.artifactdatabase.state.Output; import de.intevation.artifacts.common.utils.XMLUtils; import de.intevation.artifacts.common.utils.XMLUtils.ElementCreator; 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; 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. */ public AttributeWriter( ArtifactDatabase db, Map<String, Output> oldAttr, List<Facet> oldFacets, Map<String, Output> newAttr, List<Facet> newFacets, Map<String, List<String>> matrix) { this.db = db; 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 Document write() { Document doc = XMLUtils.newDocument(); ElementCreator cr = new ElementCreator( doc, ArtifactNamespaceContext.NAMESPACE_URI, ArtifactNamespaceContext.NAMESPACE_PREFIX); Element attribute = cr.create("attribute"); Element outs = cr.create("outputs"); attribute.appendChild(outs); doc.appendChild(attribute); for (String outName: newAttr.keySet()) { Output a = newAttr.get(outName); Output b = oldAttr.get(outName); writeOutput(doc, outs, cr, a.getName(), newFacets, oldFacets); } return doc; } /** * @param doc Document to add output nodes to * @param outs Node in Document to add output nodes to * @param cr ElementCreator in use to modify doc/outs * @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( Document doc, Node outs, ElementCreator cr, String outputName, List<Facet> newOutFacets, List<Facet> oldOutFacets) { Element output = cr.create("output"); cr.addAttr(output, "name", outputName); List<String> compatibleFacets = this.compatibilities.get(outputName); try { if (writeFacets( doc, cr, output, newOutFacets, oldOutFacets, compatibleFacets)) { // Add output element only if it contains facets. outs.appendChild(output); } } catch (ArtifactDatabaseException ade) { logger.error(ade, ade); } } /** * @param doc Document to add facet nodes to * @param cr ElementCreator to use with output/doc * @param output Node in Document to add facet nodes to * @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( Document doc, ElementCreator cr, Element output, List<Facet> newFacets, List<Facet> oldFacets, List<String> compatibleFacets) throws ArtifactDatabaseException { if (compatibleFacets == null) { logger.warn("No compatible facets, not generating out."); 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>(); for (int i = 0; i < num; i++) { ManagedFacet facet = (ManagedFacet) newFacets.get(i); if (!compatibleFacets.contains(facet.getName())) { //logger.debug("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); } } // With each genuinely new Facet, ask Artifact whether it comes to live // in/activate. for (ManagedFacet newMF: genuinelyNewFacets) { FLYSArtifact flys = (FLYSArtifact) db.getRawArtifact(newMF.getArtifact()); newMF.setActive(flys.getInitialFacetActivity( output.getAttribute("name"), newMF.getName(), newMF.getIndex())); } // 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; 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) { Node node = oldMF.toXML(doc); if (node != null) { output.appendChild(node); } } return currentFacets.size() > 0; } /** * 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 :