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.artifacts; ingo@937: ingo@937: import java.util.HashMap; ingo@937: import java.util.List; ingo@937: import java.util.Map; ingo@937: teichmann@7471: import net.sf.ehcache.Cache; teichmann@7471: ingo@937: import org.w3c.dom.Document; ingo@937: import org.w3c.dom.Element; ingo@937: import org.w3c.dom.Node; teichmann@7464: import org.w3c.dom.NodeList; ingo@937: teichmann@5831: import org.dive4elements.artifacts.Artifact; teichmann@5831: import org.dive4elements.artifacts.ArtifactNamespaceContext; teichmann@5831: import org.dive4elements.artifacts.CallContext; teichmann@5831: import org.dive4elements.artifacts.Hook; ingo@937: teichmann@7471: import org.dive4elements.artifacts.common.utils.XMLUtils; teichmann@5831: import org.dive4elements.artifacts.common.utils.XMLUtils.ElementCreator; ingo@937: teichmann@5831: import org.dive4elements.artifactdatabase.state.Output; ingo@964: teichmann@7471: import org.dive4elements.river.artifacts.cache.CacheFactory; teichmann@5831: import org.dive4elements.river.artifacts.datacage.Recommendations; ingo@937: felix@5107: /** Monitors collection changes. */ ingo@937: public class CollectionMonitor implements Hook { ingo@937: teichmann@7471: public static final String CACHE_NAME = "recommendations"; teichmann@7471: ingo@937: @Override ingo@937: public void setup(Node cfg) { ingo@937: } ingo@937: ingo@937: ingo@937: @Override ingo@940: public void execute(Artifact artifact, CallContext context, Document doc) { teichmann@5867: D4EArtifact flys = (D4EArtifact) artifact; ingo@937: teichmann@7434: // Do not generate recommendations for a loaded artifact. teichmann@7434: String out = flys.getBoundToOut(); teichmann@7434: if (out != null && !out.isEmpty()) { teichmann@7434: return; teichmann@7434: } teichmann@7434: teichmann@7464: NodeList results = doc.getElementsByTagNameNS( teichmann@7464: ArtifactNamespaceContext.NAMESPACE_URI, "result"); teichmann@7464: teichmann@7464: if (results.getLength() < 1) { teichmann@7464: return; teichmann@7464: } teichmann@7464: teichmann@7464: Element result = (Element)results.item(0); ingo@937: teichmann@7471: result.appendChild(getRecommendedElement(flys, context, doc)); teichmann@7471: } teichmann@7471: teichmann@7471: protected Element getRecommendedElement( teichmann@7471: D4EArtifact artifact, teichmann@7471: CallContext context, teichmann@7471: Document doc teichmann@7471: ) { teichmann@7471: String [] outs = extractOutputNames(artifact, context); teichmann@7471: teichmann@7471: Element recommendations = null; teichmann@7471: teichmann@7471: Cache cache = CacheFactory.getCache(CACHE_NAME); teichmann@7471: teichmann@7471: if (cache != null) { teichmann@7471: String key = generateCacheKey(artifact, outs); teichmann@7471: teichmann@7471: net.sf.ehcache.Element ce = cache.get(key); teichmann@7471: if (ce != null) { // Found in cache. teichmann@7471: Element e = (Element)ce.getValue(); teichmann@7471: // Sync to avoid thread issues with XML DOM docs. teichmann@7471: synchronized (e.getOwnerDocument()) { teichmann@7471: recommendations = (Element)doc.importNode(e, true); teichmann@7471: } teichmann@7471: } else { // Not found in cache -> generate it. teichmann@7471: Element r = createElement(XMLUtils.newDocument()); teichmann@7471: teichmann@7471: Recommendations.getInstance().recommend( teichmann@7471: artifact, null, outs, teichmann@7471: getNoneUserSpecificParameters(artifact, context), r); teichmann@7471: teichmann@7471: recommendations = (Element)doc.importNode(r, true); teichmann@7471: teichmann@7471: cache.put(new net.sf.ehcache.Element(key, r)); teichmann@7471: } teichmann@7471: } else { // No cache configured -> append directly. teichmann@7471: teichmann@7471: recommendations = createElement(doc); teichmann@7471: teichmann@7471: Recommendations.getInstance().recommend( teichmann@7471: artifact, null, outs, teichmann@7471: getNoneUserSpecificParameters(artifact, context), teichmann@7471: recommendations); teichmann@7471: } teichmann@7471: teichmann@7471: return recommendations; teichmann@7471: } teichmann@7471: teichmann@7471: private static final Element createElement(Document doc) { ingo@940: ElementCreator creator = new ElementCreator( ingo@940: doc, ingo@940: ArtifactNamespaceContext.NAMESPACE_URI, ingo@940: ArtifactNamespaceContext.NAMESPACE_PREFIX); ingo@937: teichmann@7471: return creator.create("recommended-artifacts"); teichmann@7471: } ingo@940: teichmann@7471: private static final String generateCacheKey(D4EArtifact artifact, String [] outs) { teichmann@7471: StringBuilder sb = new StringBuilder(artifact.hash()); teichmann@7471: // XXX: The hash really should be unique enough. teichmann@7471: for (String out: outs) { teichmann@7471: sb.append(';').append(out); teichmann@7471: } teichmann@7471: return sb.toString(); ingo@964: } ingo@964: ingo@964: felix@1834: /** felix@1834: * Get outputnames from current state (only the ones for which felix@1834: * facets exist). felix@1834: */ teichmann@7471: private static final String [] extractOutputNames( teichmann@5867: D4EArtifact flys, ingo@964: CallContext context) ingo@964: { raimund@2132: if (flys instanceof ChartArtifact) { raimund@2132: return new String[0]; raimund@2132: } raimund@2132: felix@4527: List outs = flys.getCurrentOutputs(context); ingo@964: sascha@1012: int num = outs == null ? 0 : outs.size(); sascha@1012: sascha@1012: String[] names = new String[num]; sascha@1012: sascha@1012: for (int i = 0; i < num; i++) { ingo@964: names[i] = outs.get(i).getName(); ingo@937: } ingo@937: ingo@964: return names; ingo@964: } ingo@964: ingo@964: felix@4527: /** felix@4527: * Creates Map from Strings "recommended" to "true". felix@4527: */ teichmann@7471: private static final Map getNoneUserSpecificParameters( teichmann@5867: D4EArtifact flys, teichmann@7471: CallContext context) ingo@964: { teichmann@7471: Map params = new HashMap(); ingo@964: params.put("recommended", "true"); ingo@964: ingo@964: return params; ingo@937: } ingo@937: } ingo@937: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :