Mercurial > dive4elements > river
diff flys-artifacts/src/main/java/de/intevation/flys/collections/AttributeWriter.java @ 3814:8083f6384023
merged flys-artifacts/pre2.6-2012-01-04
author | Thomas Arendsen Hein <thomas@intevation.de> |
---|---|
date | Fri, 28 Sep 2012 12:14:56 +0200 |
parents | c6432e8ea31e |
children | ca6ccf722c24 |
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:56 2012 +0200 @@ -0,0 +1,269 @@ +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.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. + */ + 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() { + for (Map.Entry<String, Output> entry: newAttr.entrySet()) { + String outName = entry.getKey(); + Output a = entry.getValue(); + + Output exists = attribute.getOutput(outName); + if (exists == null) { + attribute.addOutput(outName, a); + } + + attribute.clearFacets(outName); + writeOutput(a.getName(), newFacets, oldFacets); + } + + 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); + 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."); + 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( + outputName, + 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) { + attribute.addFacet(outputName, oldMF); + } + + 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 :