teichmann@5863: /* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde teichmann@5863: * Software engineering by Intevation GmbH teichmann@5863: * teichmann@5994: * This file is Free Software under the GNU AGPL (>=v3) teichmann@5863: * and comes with ABSOLUTELY NO WARRANTY! Check out the teichmann@5994: * documentation coming with Dive4Elements River for details. teichmann@5863: */ teichmann@5863: teichmann@5831: package org.dive4elements.river.exports; raimund@3295: raimund@3295: import java.io.IOException; raimund@3295: import java.util.ArrayList; weinzierl@4255: import java.util.Collections; raimund@3295: import java.util.HashMap; raimund@3295: import java.util.List; raimund@3295: import java.util.Map; raimund@3295: raimund@3295: import javax.xml.xpath.XPathConstants; raimund@3295: raimund@3295: import org.apache.log4j.Logger; raimund@3295: import org.w3c.dom.Document; raimund@3295: import org.w3c.dom.Element; raimund@3295: import org.w3c.dom.Node; raimund@3295: import org.w3c.dom.NodeList; raimund@3295: teichmann@5831: import org.dive4elements.artifactdatabase.Backend; teichmann@5831: import org.dive4elements.artifactdatabase.Backend.PersistentArtifact; teichmann@5831: import org.dive4elements.artifactdatabase.state.ArtifactAndFacet; aheinecke@6140: import org.dive4elements.artifactdatabase.state.Facet; teichmann@5831: import org.dive4elements.artifacts.Artifact; teichmann@5831: import org.dive4elements.artifacts.ArtifactDatabase; teichmann@5831: import org.dive4elements.artifacts.ArtifactDatabaseException; teichmann@5831: import org.dive4elements.artifacts.CallContext; teichmann@5831: import org.dive4elements.artifacts.CallMeta; teichmann@5831: import org.dive4elements.artifacts.common.ArtifactNamespaceContext; teichmann@5831: import org.dive4elements.artifacts.common.utils.ClientProtocolUtils; teichmann@5831: import org.dive4elements.artifacts.common.utils.XMLUtils; teichmann@5867: import org.dive4elements.river.artifacts.D4EArtifact; teichmann@5866: import org.dive4elements.river.artifacts.context.RiverContext; teichmann@5831: import org.dive4elements.river.artifacts.model.ManagedDomFacet; teichmann@5831: import org.dive4elements.river.artifacts.model.ManagedFacet; teichmann@5831: import org.dive4elements.river.themes.Theme; teichmann@5831: import org.dive4elements.river.themes.ThemeFactory; raimund@3295: raimund@3295: public class OutputHelper { raimund@3295: /** The logger used in this class. */ raimund@3295: private static Logger log = Logger.getLogger(OutputHelper.class); raimund@3295: raimund@3295: protected String identifier; raimund@3295: raimund@3295: public OutputHelper(String identifier) { raimund@3295: this.identifier = identifier; raimund@3295: } raimund@3295: /** raimund@3295: * Creates a concrete output. raimund@3295: * raimund@3295: * @param generator The OutGenerator that creates the output. raimund@3295: * @param outputName The name of the requested output. raimund@3295: * @param attributes The collection's attributes for this concrete output raimund@3295: * type. raimund@3295: * @param context The context object. raimund@3295: */ raimund@3295: public void doOut( raimund@3295: OutGenerator generator, raimund@3295: String outName, raimund@3295: String facet, raimund@3295: Document attributes, raimund@3295: CallContext context) raimund@3295: throws IOException raimund@3295: { raimund@3295: boolean debug = log.isDebugEnabled(); raimund@3295: raimund@3295: if (debug) { felix@6564: log.debug("OutputHelper.doOut: " + outName); raimund@3295: } raimund@3295: raimund@3295: ThemeList themeList = new ThemeList(attributes); raimund@3295: raimund@3295: List dataProviders = aheinecke@6140: doBlackboardPass(themeList, context, outName); raimund@3295: raimund@3295: try { aheinecke@6140: for (int i = 0; i < themeList.size(); i++) { raimund@3295: ManagedFacet theme = themeList.get(i); raimund@3295: raimund@3295: if (theme == null) { raimund@3295: log.debug("Theme is empty - no output is generated."); raimund@3295: continue; raimund@3295: } raimund@3295: raimund@3295: String art = theme.getArtifact(); raimund@3295: String facetName = theme.getName(); raimund@3295: raimund@3295: if (debug) { raimund@3295: log.debug("Do output for..."); raimund@3295: log.debug("... artifact: " + art); raimund@3295: log.debug("... facet: " + facetName); raimund@3295: } raimund@3295: raimund@3295: if (outName.equals("export") && !facetName.equals(facet)) { raimund@3295: continue; raimund@3295: } raimund@3295: raimund@3295: // Skip invisible themes. raimund@3295: if (theme.getVisible() == 0) { raimund@3295: continue; raimund@3295: } raimund@3295: raimund@3295: if (outName.equals("sq_overview")) { raimund@3295: generator.doOut( raimund@3295: dataProviders.get(i), raimund@3295: attributes, raimund@3295: theme.getActive() == 1); raimund@3295: } raimund@3295: else { raimund@3295: generator.doOut( raimund@3295: dataProviders.get(i), raimund@3295: getFacetThemeFromAttribute( raimund@3295: art, raimund@3295: outName, raimund@3295: facetName, raimund@3295: theme.getDescription(), raimund@3295: theme.getIndex(), raimund@3295: context), raimund@3295: theme.getActive() == 1); raimund@3295: } raimund@3295: } raimund@3295: } raimund@3295: catch (ArtifactDatabaseException ade) { raimund@3295: log.error(ade, ade); raimund@3295: } raimund@3295: } raimund@3295: /** raimund@3295: * Returns the attribute that belongs to an artifact and facet stored in raimund@3295: * this collection. raimund@3295: * raimund@3295: * @param uuid The Artifact's uuid. raimund@3295: * @param outname The name of the requested output. raimund@3295: * @param facet The name of the requested facet. raimund@3295: * @param context The CallContext. raimund@3295: * raimund@3295: * @return an attribute in form of a document. raimund@3295: */ raimund@3295: protected Document getFacetThemeFromAttribute( raimund@3295: String uuid, raimund@3295: String outName, raimund@3295: String facet, raimund@3295: String pattern, raimund@3295: int index, raimund@3295: CallContext context) raimund@3295: throws ArtifactDatabaseException raimund@3295: { raimund@3295: boolean debug = log.isDebugEnabled(); raimund@3295: raimund@3295: if (debug) { raimund@3295: log.debug( felix@6564: "OutputHelper.getFacetThemeFromAttribute(facet=" raimund@3295: + facet + ", index=" + index + ")"); raimund@3295: } raimund@3295: raimund@3295: ArtifactDatabase db = context.getDatabase(); raimund@3295: CallMeta meta = context.getMeta(); raimund@3295: raimund@3295: Document attr = db.getCollectionItemAttribute(identifier, uuid, meta); raimund@3295: raimund@3295: if (attr == null) { raimund@3295: attr = initItemAttribute(uuid, facet, pattern, index, outName, context); raimund@3295: raimund@3295: if (attr == null) { raimund@3295: return null; raimund@3295: } raimund@3295: } raimund@3295: raimund@3295: if (debug) { raimund@3295: log.debug("Search attribute of collection item: " + uuid); raimund@3295: } raimund@3295: raimund@3295: Node tmp = (Node) XMLUtils.xpath( raimund@3295: attr, raimund@3295: "/art:attribute", raimund@3295: XPathConstants.NODE, raimund@3295: ArtifactNamespaceContext.INSTANCE); raimund@3295: raimund@3295: if (tmp == null) { raimund@3295: log.warn("No attribute found. Operation failed."); raimund@3295: return null; raimund@3295: } raimund@3295: raimund@3295: if (debug) { raimund@3295: log.debug("Search theme for facet '" + facet + "' in attribute."); raimund@3295: } raimund@3295: raimund@3295: Map vars = new HashMap(); raimund@3295: vars.put("facet", facet); raimund@3295: vars.put("index", String.valueOf(index)); raimund@3295: raimund@3295: Node theme = (Node) XMLUtils.xpath( raimund@3295: tmp, raimund@3295: "art:themes/theme[@facet=$facet and @index=$index]", raimund@3295: XPathConstants.NODE, raimund@3295: ArtifactNamespaceContext.INSTANCE, raimund@3295: vars); raimund@3295: raimund@3295: if (theme == null) { raimund@3295: log.warn("Could not find the theme in attribute of: " + facet + " " + uuid); raimund@3295: raimund@3295: Theme t = getThemeForFacet( raimund@3295: uuid, facet, pattern, index, outName, context); raimund@3295: raimund@3295: if (t == null) { raimund@3295: log.warn("No theme found for facet: " + facet); raimund@3295: return null; raimund@3295: } raimund@3295: raimund@3295: addThemeToAttribute(uuid, attr, t, context); raimund@3295: theme = t.toXML().getFirstChild(); raimund@3295: } raimund@3295: raimund@3295: Document doc = XMLUtils.newDocument(); raimund@3295: doc.appendChild(doc.importNode(theme, true)); raimund@3295: raimund@3295: return doc; raimund@3295: } raimund@3295: /** raimund@3295: * Adds the theme of a facet to a CollectionItem's attribute. raimund@3295: * raimund@3295: * @param uuid The uuid of the artifact. raimund@3295: * @param attr The current attribute of an artifact. raimund@3295: * @param t The theme to add. raimund@3295: * @param context The CallContext. raimund@3295: */ raimund@3295: protected void addThemeToAttribute( raimund@3295: String uuid, raimund@3295: Document attr, raimund@3295: Theme t, raimund@3295: CallContext context) raimund@3295: { felix@6564: log.debug("OutputHelper.addThemeToAttribute: " + uuid); raimund@3295: raimund@3295: if (t == null) { raimund@3295: log.warn("Theme is empty - cancel adding it to attribute!"); raimund@3295: return; raimund@3295: } raimund@3295: raimund@3295: XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator( raimund@3295: attr, raimund@3295: ArtifactNamespaceContext.NAMESPACE_URI, raimund@3295: ArtifactNamespaceContext.NAMESPACE_PREFIX); raimund@3295: raimund@3295: Node tmp = (Node) XMLUtils.xpath( raimund@3295: attr, raimund@3295: "/art:attribute", raimund@3295: XPathConstants.NODE, raimund@3295: ArtifactNamespaceContext.INSTANCE); raimund@3295: raimund@3295: if (tmp == null) { raimund@3295: tmp = ec.create("attribute"); raimund@3295: attr.appendChild(tmp); raimund@3295: } raimund@3295: raimund@3295: Node themes = (Node) XMLUtils.xpath( raimund@3295: tmp, raimund@3295: "art:themes", raimund@3295: XPathConstants.NODE, raimund@3295: ArtifactNamespaceContext.INSTANCE); raimund@3295: raimund@3295: if (themes == null) { raimund@3295: themes = ec.create("themes"); raimund@3295: tmp.appendChild(themes); raimund@3295: } raimund@3295: raimund@3295: themes.appendChild(attr.importNode(t.toXML().getFirstChild(), true)); raimund@3295: raimund@3295: try { raimund@3295: setCollectionItemAttribute(uuid, attr, context); raimund@3295: } raimund@3295: catch (ArtifactDatabaseException e) { raimund@3295: // do nothing raimund@3295: log.warn("Cannot set attribute of item: " + uuid); raimund@3295: } raimund@3295: } raimund@3295: raimund@3295: /** raimund@3295: * Sets the attribute of a CollectionItem specified by uuid to a new raimund@3295: * value attr. raimund@3295: * raimund@3295: * @param uuid The uuid of the CollectionItem. raimund@3295: * @param attr The new attribute for the CollectionItem. raimund@3295: * @param context The CallContext. raimund@3295: */ raimund@3295: public void setCollectionItemAttribute( raimund@3295: String uuid, raimund@3295: Document attr, raimund@3295: CallContext context) raimund@3295: throws ArtifactDatabaseException raimund@3295: { raimund@3295: Document doc = ClientProtocolUtils.newSetItemAttributeDocument( raimund@3295: uuid, raimund@3295: attr); raimund@3295: raimund@3295: if (doc == null) { raimund@3295: log.warn("Cannot set item attribute: No attribute found."); raimund@3295: return; raimund@3295: } raimund@3295: raimund@3295: ArtifactDatabase db = context.getDatabase(); raimund@3295: CallMeta meta = context.getMeta(); raimund@3295: raimund@3295: db.setCollectionItemAttribute(identifier, uuid, doc, meta); raimund@3295: } raimund@3295: raimund@3295: raimund@3295: /** raimund@3295: * Show blackboard (context) to each facet and create a list of raimund@3295: * ArtifactAndFacets on the fly (with the same ordering as the passed raimund@3295: * ThemeList). raimund@3295: * @param themeList ThemeList to create a ArtifactAndFacetList along. raimund@3295: * @param context The "Blackboard". raimund@3295: */ raimund@3295: protected List doBlackboardPass( aheinecke@6140: ThemeList themeList, CallContext context, String outname raimund@3295: ) { raimund@3295: ArrayList dataProviders = raimund@3295: new ArrayList(); raimund@3295: raimund@3295: try { raimund@3295: // Collect all ArtifactAndFacets for blackboard pass. aheinecke@6140: for (int i = 0; i < themeList.size(); i++) { aheinecke@6140: log.debug("BLackboard pass for: " + outname); raimund@3295: ManagedFacet theme = themeList.get(i); raimund@3295: if (theme == null) { raimund@3295: log.warn("A ManagedFacet in ThemeList is null."); aheinecke@6140: themeList.remove(i); aheinecke@6140: i--; raimund@3295: continue; raimund@3295: } aheinecke@6140: raimund@3295: String uuid = theme.getArtifact(); raimund@3295: Artifact artifact = getArtifact(uuid, context); teichmann@5867: D4EArtifact flys = (D4EArtifact) artifact; aheinecke@6140: Facet face = flys.getNativeFacet(theme, outname); aheinecke@6140: log.debug("Looking for Native Facet for theme: " + theme + " and out: " + aheinecke@6140: outname + " in artifact: " + uuid + aheinecke@6140: face == null ? " Found. " : " Not Found. "); aheinecke@6140: if (face == null) { aheinecke@6140: log.warn("Theme " + theme.getName() + " for " + outname + " has no facets!. Removing theme."); aheinecke@6140: themeList.remove(i); aheinecke@6140: i--; aheinecke@6140: continue; aheinecke@6140: } raimund@3295: raimund@3295: ArtifactAndFacet artifactAndFacet = new ArtifactAndFacet( raimund@3295: artifact, aheinecke@6140: face); raimund@3295: raimund@3295: // XXX HELP ME PLEASE raimund@3295: artifactAndFacet.setFacetDescription(theme.getDescription()); raimund@3295: raimund@3295: // Show blackboard to facet. raimund@3295: artifactAndFacet.register(context); raimund@3295: raimund@3295: // Add to themes. raimund@3295: dataProviders.add(i, artifactAndFacet); raimund@3295: } raimund@3295: } raimund@3295: catch (ArtifactDatabaseException ade) { raimund@3295: log.error("ArtifactDatabaseException!", ade); raimund@3295: } raimund@3295: raimund@3295: return dataProviders; raimund@3295: } raimund@3295: /** raimund@3295: * Returns a concrete Artifact of this collection specified by its uuid. raimund@3295: * raimund@3295: * @param uuid The Artifact's uuid. raimund@3295: * @param context The CallContext. raimund@3295: * raimund@3295: * @return an Artifact. raimund@3295: */ raimund@3295: protected Artifact getArtifact(String uuid, CallContext context) raimund@3295: throws ArtifactDatabaseException raimund@3295: { felix@6564: log.debug("OutputHelper.getArtifact"); raimund@3295: raimund@3295: Backend backend = Backend.getInstance(); raimund@3295: PersistentArtifact persistent = backend.getArtifact(uuid); raimund@3295: raimund@3295: return persistent != null ? persistent.getArtifact() : null; raimund@3295: } raimund@3295: raimund@3295: /** raimund@3295: * Initializes the attribute of an collection item with the theme of a raimund@3295: * specific facet. raimund@3295: * raimund@3295: * @param uuid The uuid of an artifact. raimund@3295: * @param facet The name of a facet. raimund@3295: * @param context The CallContext. raimund@3295: * raimund@3295: * @param the new attribute. raimund@3295: */ raimund@3295: protected Document initItemAttribute( raimund@3295: String uuid, raimund@3295: String facet, raimund@3295: String pattern, raimund@3295: int index, raimund@3295: String outName, raimund@3295: CallContext context) raimund@3295: { raimund@3295: boolean debug = log.isDebugEnabled(); raimund@3295: raimund@3295: if (debug) { felix@6564: log.debug("OutputHelper.initItemAttribute"); raimund@3295: } raimund@3295: raimund@3295: Theme t = getThemeForFacet(uuid, facet, pattern, index, outName, context); raimund@3295: raimund@3295: if (t == null) { raimund@3295: log.info("Could not find theme for facet. Cancel initialization."); raimund@3295: return null; raimund@3295: } raimund@3295: raimund@3295: Document attr = XMLUtils.newDocument(); raimund@3295: addThemeToAttribute(uuid, attr, t, context); raimund@3295: raimund@3295: if (debug) { raimund@3295: log.debug("initItemAttribute for facet " + facet + ": " raimund@3295: + XMLUtils.toString(attr)); raimund@3295: } raimund@3295: raimund@3295: return attr; raimund@3295: } sascha@3299: raimund@3295: /** raimund@3295: * Returns the theme of a specific facet. raimund@3295: * raimund@3295: * @param uuid The uuid of an artifact. raimund@3295: * @param facet The name of the facet. raimund@3295: * @param context The CallContext object. raimund@3295: * raimund@3295: * @return the desired theme. raimund@3295: */ raimund@3295: protected Theme getThemeForFacet( raimund@3295: String uuid, raimund@3295: String facet, raimund@3295: String pattern, raimund@3295: int index, raimund@3295: String outName, raimund@3295: CallContext context) raimund@3295: { felix@6564: log.info("OutputHelper.getThemeForFacet: " + facet); raimund@3295: teichmann@5866: RiverContext flysContext = context instanceof RiverContext teichmann@5866: ? (RiverContext) context teichmann@5866: : (RiverContext) context.globalContext(); raimund@3295: raimund@3295: // Push artifact in flysContext. raimund@3295: ArtifactDatabase db = context.getDatabase(); raimund@3295: try { teichmann@5867: D4EArtifact artifact = (D4EArtifact) db.getRawArtifact(uuid); raimund@3295: log.debug("Got raw artifact"); teichmann@5866: flysContext.put(RiverContext.ARTIFACT_KEY, artifact); raimund@3295: } raimund@3295: catch (ArtifactDatabaseException dbe) { raimund@3295: log.error("Exception caught when trying to get art.", dbe); raimund@3295: } raimund@3295: raimund@3295: Theme t = ThemeFactory.getTheme( raimund@3295: flysContext, raimund@3295: facet, raimund@3295: pattern, raimund@3295: outName, raimund@3295: "default"); raimund@3295: raimund@3295: if (t != null) { ingo@3781: log.debug("found theme for facet '" + facet + "'"); raimund@3295: t.setFacet(facet); raimund@3295: t.setIndex(index); raimund@3295: } ingo@3781: else { ingo@3781: log.warn("unable to find theme for facet '" + facet + "'"); ingo@3781: } raimund@3295: raimund@3295: return t; raimund@3295: } raimund@3295: raimund@3295: /** raimund@3295: * Inner class to structure/order the themes of a chart. raimund@3295: */ raimund@3295: private static class ThemeList { raimund@3295: private Logger logger = Logger.getLogger(ThemeList.class); weinzierl@4255: protected List themes; raimund@3295: raimund@3295: public ThemeList(Document output) { weinzierl@4255: themes = new ArrayList(); raimund@3295: parse(output); raimund@3295: } raimund@3295: raimund@3295: protected void parse(Document output) { raimund@3295: NodeList themeList = (NodeList) XMLUtils.xpath( raimund@3295: output, raimund@3295: "art:output/art:facet", raimund@3295: XPathConstants.NODESET, raimund@3295: ArtifactNamespaceContext.INSTANCE); raimund@3295: raimund@3295: int num = themeList != null ? themeList.getLength() : 0; raimund@3295: raimund@3295: logger.debug("Output has " + num + " elements."); raimund@3295: raimund@3295: if (num == 0) { raimund@3295: return; raimund@3295: } raimund@3295: raimund@3295: for (int i = 0; i < num; i++) { raimund@3295: Element theme = (Element) themeList.item(i); raimund@3295: raimund@3295: ManagedDomFacet facet = new ManagedDomFacet(theme); weinzierl@4255: themes.add(facet); raimund@3295: } weinzierl@4255: weinzierl@4255: Collections.sort(themes); raimund@3295: } raimund@3295: raimund@3295: public ManagedFacet get(int idx) { weinzierl@4255: return themes.get(idx); raimund@3295: } raimund@3295: aheinecke@6140: public void remove(int idx) { aheinecke@6140: themes.remove(idx); aheinecke@6140: } aheinecke@6140: raimund@3295: public int size() { raimund@3295: return themes.size(); raimund@3295: } raimund@3295: } raimund@3295: } sascha@3304: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :