Mercurial > dive4elements > river
diff flys-artifacts/src/main/java/de/intevation/flys/collections/AttributeWriter.java @ 3812:f788d2d901d6
merged flys-artifacts/pre2.6-2011-12-05
author | Thomas Arendsen Hein <thomas@intevation.de> |
---|---|
date | Fri, 28 Sep 2012 12:14:53 +0200 |
parents | 490ab097f58c |
children | 0b466bd4ab24 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/collections/AttributeWriter.java Fri Sep 28 12:14:53 2012 +0200 @@ -0,0 +1,302 @@ +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 :