ingo@346: package de.intevation.flys.collections; ingo@346: felix@1639: import java.util.ArrayList; ingo@346: import java.util.List; felix@1810: import java.util.HashMap; ingo@346: import java.util.Map; ingo@346: ingo@346: import org.apache.log4j.Logger; ingo@346: ingo@346: import org.w3c.dom.Document; ingo@346: import org.w3c.dom.Element; ingo@346: import org.w3c.dom.Node; ingo@346: felix@1709: import de.intevation.artifacts.ArtifactDatabase; felix@1709: import de.intevation.artifacts.ArtifactDatabaseException; ingo@346: import de.intevation.artifacts.ArtifactNamespaceContext; ingo@346: ingo@346: import de.intevation.artifactdatabase.state.Facet; ingo@346: import de.intevation.artifactdatabase.state.Output; ingo@346: ingo@346: import de.intevation.artifacts.common.utils.XMLUtils; ingo@346: import de.intevation.artifacts.common.utils.XMLUtils.ElementCreator; ingo@346: felix@1709: import de.intevation.flys.artifacts.FLYSArtifact; ingo@346: import de.intevation.flys.artifacts.model.ManagedFacet; ingo@346: felix@1634: /** felix@1634: * Create attribute- element of describe document of an ArtifactCollection. felix@1634: * The attribute-element contains the merged output of all outputmodes and felix@1780: * facets that are part of the collection. felix@1634: */ ingo@346: public class AttributeWriter { ingo@346: felix@1709: /** ArtifactDatabase used to fetch Artifacts. */ felix@1709: protected ArtifactDatabase db = null; felix@1709: ingo@346: protected Map oldAttr; felix@1709: ingo@346: protected Map newAttr; ingo@346: felix@1785: /** List of already seen facets. */ felix@1785: protected List oldFacets; felix@1785: felix@1785: /** List of "new" facets. */ felix@1785: protected List newFacets; felix@1785: felix@1785: /** felix@1785: * "Compatibility matrix", mapws list of facet names to output names. felix@1785: * Any facet that is not found in the list for a specific output will felix@1785: * not be added to the resulting document. felix@1785: */ felix@1785: protected Map> compatibilities; felix@1785: ingo@346: private static Logger logger = Logger.getLogger(AttributeWriter.class); ingo@346: ingo@346: felix@1634: /** felix@1634: * Create a AttributeWriter. felix@1634: * Attributes not present in newAttr will not be included in the document. felix@1709: * @param db Database to fetch artifacts. felix@1634: * @param oldAttr "Old" (possibly user-changed) outputs. felix@1780: * @param newAttr "New" (eventually re-read in its original, unchanged felix@1634: * form) outputs. felix@1634: */ ingo@346: public AttributeWriter( felix@1709: ArtifactDatabase db, ingo@346: Map oldAttr, felix@1785: List oldFacets, felix@1785: Map newAttr, felix@1785: List newFacets, felix@1785: Map> matrix) ingo@346: { felix@1785: this.db = db; felix@1785: this.oldAttr = oldAttr; felix@1785: this.newAttr = newAttr; felix@1785: this.oldFacets = oldFacets; felix@1785: this.newFacets = newFacets; felix@1785: this.compatibilities = matrix; ingo@346: } ingo@346: ingo@346: felix@1628: /** felix@1634: * Create document by merging outputs given in felix@1634: * constructor. felix@1780: * felix@1634: * The "new" set rules about existance of attributes, so anything not felix@1634: * present in it will not be included in the resulting document. felix@1634: * The "old" set rules about the content of attributes (as user changes felix@1634: * are recorded here and not in the new set). felix@1780: * felix@1634: * @return document with merged outputs as described. felix@1628: */ ingo@346: protected Document write() { ingo@346: Document doc = XMLUtils.newDocument(); ingo@346: ingo@346: ElementCreator cr = new ElementCreator( ingo@346: doc, ingo@346: ArtifactNamespaceContext.NAMESPACE_URI, ingo@346: ArtifactNamespaceContext.NAMESPACE_PREFIX); ingo@346: ingo@638: Element attribute = cr.create("attribute"); sascha@705: Element outs = cr.create("outputs"); ingo@638: ingo@638: attribute.appendChild(outs); ingo@638: doc.appendChild(attribute); ingo@353: sascha@705: for (String outName: newAttr.keySet()) { ingo@346: Output a = newAttr.get(outName); ingo@346: Output b = oldAttr.get(outName); ingo@945: felix@1785: writeOutput(doc, outs, cr, a.getName(), newFacets, oldFacets); ingo@346: } ingo@346: ingo@346: return doc; ingo@346: } ingo@346: felix@1634: felix@1628: /** felix@1628: * @param doc Document to add output nodes to felix@1628: * @param outs Node in Document to add output nodes to felix@1785: * @param cr ElementCreator in use to modify doc/outs felix@1785: * @param outputName the "new" outputs name felix@1785: * @param newOutFacets Facets of the new outputs felix@1785: * @param oldOutFacets Facets of the old outputs (can be null) felix@1628: */ ingo@346: protected void writeOutput( ingo@346: Document doc, ingo@353: Node outs, ingo@346: ElementCreator cr, felix@1785: String outputName, felix@1785: List newOutFacets, felix@1785: List oldOutFacets) ingo@346: { ingo@346: Element output = cr.create("output"); felix@1785: cr.addAttr(output, "name", outputName); ingo@346: ingo@353: outs.appendChild(output); ingo@346: felix@1785: List compatibleFacets = this.compatibilities.get(outputName); felix@1709: try { felix@1785: writeFacets(doc, cr, output, newOutFacets, oldOutFacets, compatibleFacets); felix@1709: } felix@1709: catch (ArtifactDatabaseException ade) { felix@1709: logger.error(ade, ade); felix@1709: } ingo@346: } ingo@346: ingo@346: felix@1628: /** felix@1628: * @param doc Document to add facet nodes to felix@1785: * @param cr ElementCreator to use with output/doc felix@1628: * @param output Node in Document to add facet nodes to felix@1785: * @param newFacets the new facets felix@1785: * @param oldFacets the old facets felix@1785: * @param compatibleFacets List of facets to accept felix@1628: */ ingo@346: protected void writeFacets( ingo@346: Document doc, ingo@346: ElementCreator cr, ingo@346: Element output, felix@1635: List newFacets, felix@1785: List oldFacets, felix@1785: List compatibleFacets) felix@1709: throws ArtifactDatabaseException ingo@346: { felix@1788: if (compatibleFacets == null) { felix@1788: logger.warn("No compatible facets, not generating out."); felix@1788: return; felix@1788: } felix@1788: felix@1635: int num = newFacets.size(); ingo@346: felix@1635: // Add all new Facets either in their old state or (if really felix@1635: // new) as they are. felix@1639: List currentFacets = new ArrayList(); felix@1639: List genuinelyNewFacets = new ArrayList(); felix@1785: ingo@346: for (int i = 0; i < num; i++) { felix@1635: ManagedFacet facet = (ManagedFacet) newFacets.get(i); felix@1785: if (!compatibleFacets.contains(facet.getName())) { felix@1785: //logger.debug("Have incompatible facet, skip: " + facet.getName()); felix@1785: continue; felix@1785: } felix@1785: //else logger.debug("Have compatible facet: " + facet.getName()); ingo@346: felix@1635: ManagedFacet picked = pickFacet(facet, oldFacets); felix@1785: felix@1639: if (facet.equals(picked)) { felix@1639: genuinelyNewFacets.add(picked); felix@1639: } felix@1639: else { felix@1639: currentFacets.add(picked); felix@1639: } felix@1639: } felix@1639: felix@1709: // With each genuinely new Facet, ask Artifact whether it comes to live felix@1709: // in/activate. felix@1709: for (ManagedFacet newMF: genuinelyNewFacets) { felix@1709: FLYSArtifact flys = (FLYSArtifact) db.getRawArtifact(newMF.getArtifact()); felix@1709: newMF.setActive(flys.getInitialFacetActivity( felix@1810: output.getAttribute("name"), felix@1709: newMF.getName(), felix@1709: newMF.getIndex())); felix@1709: } felix@1709: felix@1639: // For each genuinely new Facet check positional conflicts. felix@1639: for (ManagedFacet newMF: genuinelyNewFacets) { felix@1639: boolean conflicts = true; felix@1639: // Loop until all conflicts resolved. felix@1639: while (conflicts) { felix@1639: conflicts = false; felix@1639: for (ManagedFacet oldMF: currentFacets) { felix@1639: if (newMF.getPosition() == oldMF.getPosition()) { felix@1639: conflicts = true; felix@1639: logger.debug("Positional conflict while merging " + felix@1780: "facets, pushing newest facet 1 up (" + newMF.getPosition() + ")"); felix@1639: newMF.setPosition(newMF.getPosition() + 1); felix@1639: break; felix@1639: } felix@1639: } felix@1639: } felix@1639: currentFacets.add(newMF); felix@1639: } felix@1639: felix@1810: // Fill/correct "gaps" (e.g. position 1,2,5 are taken, after gap filling felix@1810: // expect positions 1,2,3 [5->3]) felix@1810: // Preparations to be able to detect gaps. felix@1810: Map mfmap = new HashMap(); felix@1810: int max = 0; felix@1810: for (ManagedFacet mf: currentFacets) { felix@1810: int pos = mf.getPosition(); felix@1810: mfmap.put(Integer.valueOf(pos), mf); felix@1810: if (pos > max) max = pos; felix@1810: } felix@1810: felix@1810: // Finally do gap correction. felix@1810: if (max != currentFacets.size()) { felix@1810: int gap = 0; felix@1810: for (int i = 1; i <= max; i++) { felix@1810: ManagedFacet mf = mfmap.get(Integer.valueOf(i)); felix@1810: if (mf == null) { felix@1810: gap++; felix@1810: continue; felix@1810: } felix@1810: mf.setPosition(mf.getPosition() - gap); felix@1810: } felix@1810: } felix@1810: felix@1639: // Now add all facets. felix@1639: for (ManagedFacet oldMF: currentFacets) { felix@1639: Node node = oldMF.toXML(doc); felix@1635: if (node != null) { felix@1635: output.appendChild(node); ingo@346: } ingo@346: } ingo@346: } ingo@346: ingo@346: felix@1628: /** felix@1635: * Returns the facet to be added to Document. felix@1635: * Return the new facet only if the "same" facet was not present before. felix@1635: * Return the "old" facet otherwise (user-defined information sticks felix@1635: * to it). felix@1635: * @param facet the new facet. felix@1635: * @param oldFacets the old facets, new facet is compared against each of felix@1635: * these. felix@1635: * @return facet if genuinely new, matching old facet otherwise. felix@1628: */ felix@1635: protected ManagedFacet pickFacet(ManagedFacet facet, felix@1709: List oldFacets) felix@1709: { felix@1635: if (oldFacets == null) { felix@1635: logger.debug("No old facets to compare a new to found."); felix@1635: return facet; ingo@346: } felix@1635: felix@1635: String hash = facet.getName() + facet.getIndex() + facet.getArtifact(); ingo@346: felix@1635: // Compare "new" facet with all old facets. felix@1635: // Take oldFacet if that facet was already present (otherwise felix@1635: // information is lost, the new one otherwise. felix@1635: for (Facet oFacet: oldFacets) { felix@1635: ManagedFacet oldFacet = (ManagedFacet) oFacet; felix@1635: String oldHash = oldFacet.getName() felix@1635: + oldFacet.getIndex() felix@1635: + oldFacet.getArtifact(); felix@1635: if (hash.equals(oldHash)) { felix@1635: return oldFacet; ingo@346: } ingo@346: } felix@1635: return facet; ingo@346: } ingo@346: } sascha@705: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :