ingo@147: package de.intevation.flys.collections; ingo@147: ingo@300: import java.io.IOException; ingo@300: import java.io.OutputStream; ingo@300: import java.util.ArrayList; ingo@638: import java.util.HashMap; ingo@300: import java.util.List; ingo@300: import java.util.Map; ingo@1979: import java.util.Set; ingo@147: ingo@147: import javax.xml.xpath.XPathConstants; ingo@147: ingo@147: import org.apache.log4j.Logger; ingo@147: ingo@147: import org.w3c.dom.Document; ingo@147: import org.w3c.dom.Element; ingo@147: import org.w3c.dom.Node; ingo@293: import org.w3c.dom.NodeList; ingo@147: ingo@300: import de.intevation.artifacts.Artifact; ingo@293: import de.intevation.artifacts.ArtifactDatabase; ingo@293: import de.intevation.artifacts.ArtifactDatabaseException; ingo@147: import de.intevation.artifacts.ArtifactNamespaceContext; ingo@147: import de.intevation.artifacts.CallContext; ingo@293: import de.intevation.artifacts.CallMeta; ingo@147: ingo@350: import de.intevation.artifacts.common.utils.ClientProtocolUtils; ingo@147: import de.intevation.artifacts.common.utils.XMLUtils; ingo@147: ingo@300: import de.intevation.artifactdatabase.Backend; ingo@300: import de.intevation.artifactdatabase.Backend.PersistentArtifact; ingo@147: import de.intevation.artifactdatabase.DefaultArtifactCollection; felix@1946: import de.intevation.artifactdatabase.state.ArtifactAndFacet; ingo@1979: import de.intevation.artifactdatabase.state.Output; ingo@1979: import de.intevation.artifactdatabase.state.Settings; felix@1785: import de.intevation.artifactdatabase.state.StateEngine; ingo@147: ingo@300: import de.intevation.flys.artifacts.context.FLYSContext; felix@1784: import de.intevation.flys.artifacts.FLYSArtifact; ingo@347: import de.intevation.flys.artifacts.model.ManagedFacet; ingo@1717: import de.intevation.flys.artifacts.model.ManagedDomFacet; ingo@300: import de.intevation.flys.exports.OutGenerator; ingo@350: import de.intevation.flys.themes.Theme; ingo@350: import de.intevation.flys.themes.ThemeFactory; ingo@300: felix@1784: import de.intevation.flys.utils.FLYSUtils; ingo@147: ingo@147: /** ingo@147: * @author Ingo Weinzierl ingo@147: */ ingo@147: public class FLYSArtifactCollection extends DefaultArtifactCollection { felix@1013: /** The logger used in this class. */ ingo@147: private static Logger log = Logger.getLogger(FLYSArtifactCollection.class); ingo@147: felix@1013: /** Constant XPath that points to the outputmodes of an artifact. */ ingo@147: public static final String XPATH_ARTIFACT_OUTPUTMODES = ingo@147: "/art:result/art:outputmodes"; ingo@147: felix@1950: public static final String XPATH_ARTIFACT_STATE_DATA = felix@1950: "/art:result/art:ui/art:static/art:state/art:data"; felix@1950: ingo@293: public static final String XPATH_COLLECTION_ITEMS = ingo@293: "/art:result/art:artifact-collection/art:collection-item"; ingo@293: ingo@300: public static final String XPATH_OUT_NAME = "/art:action/@art:name"; ingo@300: ingo@300: public static final String XPATH_OUT_TYPE = "/art:action/@art:type"; ingo@300: felix@1780: /** Xpath to master artifacts uuid. */ felix@1780: public static final String XPATH_MASTER_UUID = felix@1780: "/art:artifact-collection/art:artifact/@art:uuid"; felix@1744: ingo@971: public static final String XPATH_LOADED_RECOMMENDATIONS = ingo@971: "/art:attribute/art:loaded-recommendations"; ingo@971: ingo@300: felix@1628: /** felix@1628: * Return description Document for this collection. felix@1628: */ ingo@147: @Override ingo@147: public Document describe(CallContext context) { ingo@147: log.debug("FLYSArtifactCollection.describe: " + identifier); ingo@147: ingo@1972: CollectionDescriptionHelper helper = new CollectionDescriptionHelper( ingo@1972: getName(), identifier(), getCreationTime(), getTTL(), ingo@1972: context); ingo@147: ingo@346: ArtifactDatabase db = context.getDatabase(); ingo@1976: ingo@1976: Document oldAttrs = getAttribute(); ingo@1976: AttributeParser parser = new AttributeParser(oldAttrs); ingo@293: ingo@300: try { ingo@1976: String[] aUUIDs = getArtifactUUIDs(context); raimund@2585: raimund@2585: oldAttrs = removeAttributes(oldAttrs, context); raimund@2585: parser = new AttributeParser(oldAttrs); raimund@2585: ingo@1976: CollectionAttribute newAttr = mergeAttributes( ingo@1976: db, context, parser, aUUIDs); ingo@638: ingo@1979: if (checkOutputSettings(newAttr, context)) { ingo@1979: saveCollectionAttribute(db, context, newAttr); ingo@1979: } ingo@1979: ingo@1972: helper.setAttribute(newAttr); ingo@346: felix@1784: // Make it an empty array if null. felix@1784: if (aUUIDs == null) { felix@1784: aUUIDs = new String[] {}; felix@1784: } felix@1784: felix@1784: for (String uuid: aUUIDs) { ingo@1972: helper.addArtifact(uuid); ingo@293: } ingo@293: } ingo@293: catch (ArtifactDatabaseException ade) { ingo@1972: log.error("Error while merging attribute documents.", ade); ingo@971: ingo@1976: helper.setAttribute(parser.getCollectionAttribute()); ingo@147: } ingo@147: ingo@1976: return helper.toXML(); ingo@147: } ingo@147: ingo@147: ingo@971: /** ingo@971: * Merge the current art:outputs nodes with the the outputs provided by the ingo@971: * artifacts in the Collection. felix@1784: * felix@1709: * @param uuids Artifact uuids. ingo@971: */ ingo@1976: protected CollectionAttribute mergeAttributes( ingo@971: ArtifactDatabase db, ingo@971: CallContext context, ingo@1976: AttributeParser oldParser, ingo@1976: String[] uuids ingo@1976: ) { ingo@1976: CollectionAttribute cAttribute = ingo@1976: buildOutAttributes(db, context, oldParser, uuids); ingo@971: ingo@1976: cAttribute.setLoadedRecommendations( ingo@1976: getLoadedRecommendations(oldParser.getAttributeDocument())); ingo@1976: ingo@1979: saveCollectionAttribute(db, context, cAttribute); ingo@1979: ingo@1979: return cAttribute; ingo@1979: } ingo@1979: ingo@1979: raimund@2585: protected Document removeAttributes(Document attrs, CallContext context) { raimund@2594: Node outs = (Node) XMLUtils.xpath( raimund@2594: attrs, raimund@2594: "/art:attribute/art:outputs", raimund@2594: XPathConstants.NODE, raimund@2594: ArtifactNamespaceContext.INSTANCE); raimund@2594: raimund@2594: NodeList nodes = (NodeList) XMLUtils.xpath( raimund@2594: attrs, raimund@2594: "/art:attribute/art:outputs/art:output", raimund@2594: XPathConstants.NODESET, raimund@2594: ArtifactNamespaceContext.INSTANCE); raimund@2594: raimund@2594: if (nodes != null) { raimund@2594: for (int i = 0; i < nodes.getLength(); i++) { raimund@2594: Element e = (Element)nodes.item(i); raimund@2594: if(!outputExists(e.getAttribute("name"), context)) { raimund@2594: outs.removeChild(e); raimund@2594: } raimund@2594: } raimund@2594: } raimund@2594: return attrs; raimund@2594: } raimund@2594: raimund@2594: felix@2728: /** felix@2728: * True if current MasterArtifact has given output. felix@2728: * @param name Name of the output of interest. felix@2728: * @param context current context felix@2728: * @return true iff current mater artifact has given output. felix@2728: */ raimund@2594: protected boolean outputExists(String name, CallContext context) { raimund@2585: FLYSArtifact master = getMasterArtifact(context); raimund@2585: List outList = master.getOutputs(context); raimund@2585: raimund@2594: for (Output o : outList) { raimund@2594: if (name.equals(o.getName())) { raimund@2594: return true; raimund@2585: } raimund@2585: } raimund@2594: return false; raimund@2585: } raimund@2585: ingo@1979: /** ingo@1979: * @param db The ArtifactDatabase which is required to save the attribute ingo@1979: * into. ingo@1979: * @param attribute The CollectionAttribute that should be stored in the ingo@1979: * database. ingo@1979: * ingo@1979: * @return true, if the transaction was successful, otherwise false. ingo@1979: */ ingo@1979: protected boolean saveCollectionAttribute( ingo@1979: ArtifactDatabase db, ingo@1979: CallContext context, ingo@1979: CollectionAttribute attribute ingo@1979: ) { ingo@1979: log.info("Save new CollectionAttribute into database."); ingo@1979: ingo@1979: Document doc = attribute.toXML(); ingo@971: ingo@971: try { felix@1013: // Save the merged document into database. ingo@971: db.setCollectionAttribute(identifier(), context.getMeta(), doc); ingo@1979: ingo@1979: log.info("Saving CollectionAttribute was successful."); ingo@1979: ingo@1979: return true; ingo@971: } ingo@971: catch (ArtifactDatabaseException adb) { ingo@971: log.error(adb, adb); ingo@971: } ingo@971: ingo@1979: return false; ingo@971: } ingo@971: ingo@971: ingo@971: /** ingo@971: * Merge the recommendations which have already been loaded from the old ingo@971: * attribute document into the new attribute document. This is necessary, ingo@971: * because mergeAttributes() only merges the art:outputs nodes - all ingo@971: * other nodes are skiped. ingo@971: */ ingo@1976: protected Node getLoadedRecommendations(Document oldAttrs) { ingo@971: Element loadedRecoms = (Element) XMLUtils.xpath( ingo@971: oldAttrs, ingo@971: XPATH_LOADED_RECOMMENDATIONS, ingo@971: XPathConstants.NODE, ingo@971: ArtifactNamespaceContext.INSTANCE); ingo@971: ingo@1976: return loadedRecoms; ingo@971: } ingo@971: ingo@971: ingo@1979: /** ingo@1979: * Evaluates the Output settings. If an Output has no Settings set, the ingo@1979: * relevant OutGenerator is used to initialize a default Settings object. ingo@1979: * ingo@1979: * @param attribute The CollectionAttribute. ingo@1979: * @param cc The CallContext. ingo@1979: * ingo@1979: * @return true, if the CollectionAttribute was modified, otherwise false. ingo@1979: */ ingo@1979: protected boolean checkOutputSettings( ingo@1979: CollectionAttribute attribute, ingo@1979: CallContext cc ingo@1979: ) { ingo@1979: boolean modified = false; ingo@1979: ingo@1979: Map outputMap = attribute != null ingo@1979: ? attribute.getOutputs() ingo@1979: : null; ingo@1979: ingo@1979: if (outputMap == null || outputMap.size() == 0) { ingo@1979: log.debug("No Output Settings check necessary."); ingo@1979: return modified; ingo@1979: } ingo@1979: ingo@1979: Set> entries = outputMap.entrySet(); ingo@1979: ingo@1979: for (Map.Entry entry: entries) { ingo@1979: String outName = entry.getKey(); ingo@1979: Output output = entry.getValue(); ingo@1979: ingo@1979: Settings settings = output.getSettings(); ingo@1979: ingo@1979: if (settings == null) { ingo@1979: log.debug("No Settings set for Output '" + outName + "'."); ingo@1999: output.setSettings( ingo@1999: createInitialOutputSettings(cc, attribute, outName)); ingo@1979: ingo@1979: modified = true; ingo@1979: } ingo@1979: } ingo@1979: ingo@1979: return modified; ingo@1979: } ingo@1979: ingo@1979: ingo@1979: /** ingo@1979: * This method uses the the OutGenerator for the specified Output ingo@1979: * out to create an initial Settings object. ingo@1999: * ingo@1999: * @param cc The CallContext object. ingo@1999: * @param attr The CollectionAttribute. ingo@1999: * @param out The name of the output. ingo@1999: * ingo@1999: * @return a default Settings object for the specified Output. ingo@1979: */ ingo@1999: protected Settings createInitialOutputSettings( ingo@1999: CallContext cc, ingo@1999: CollectionAttribute attr, ingo@1999: String out ingo@1999: ) { ingo@1979: OutGenerator outGen = getOutGenerator(cc, out, null); ingo@1979: ingo@1999: if (outGen == null) { ingo@1999: return null; ingo@1999: } ingo@1999: ingo@1988: // XXX NOTE: the outGen is not able to process its generate() operation, ingo@1988: // because it has no OutputStream set! ingo@1988: outGen.init(XMLUtils.newDocument(), null, cc); ingo@1988: prepareMasterArtifact(outGen, cc); ingo@1988: ingo@1988: try { ingo@1999: Document outAttr = getAttribute(cc, attr, out); ingo@1999: doOut(outGen, out, out, outAttr, cc); ingo@1988: } ingo@1988: catch (ArtifactDatabaseException adbe) { ingo@1988: log.error(adbe, adbe); ingo@1988: } ingo@1988: catch (IOException ioe) { ingo@1988: log.error(ioe, ioe); ingo@1988: } ingo@1979: ingo@1979: return outGen.getSettings(); ingo@1979: } ingo@1979: ingo@1979: ingo@300: @Override ingo@646: public void out( ingo@646: String type, ingo@646: Document format, ingo@646: OutputStream out, ingo@646: CallContext context) ingo@300: throws IOException ingo@300: { ingo@1998: long reqBegin = System.currentTimeMillis(); ingo@1998: ingo@300: log.info("FLYSArtifactCollection.out"); ingo@300: ingo@300: String name = XMLUtils.xpathString( ingo@300: format, XPATH_OUT_NAME, ArtifactNamespaceContext.INSTANCE); ingo@300: ingo@646: String subtype = XMLUtils.xpathString( ingo@300: format, XPATH_OUT_TYPE, ArtifactNamespaceContext.INSTANCE); ingo@300: ingo@646: log.info("-> Output name = " + name); ingo@646: log.info("-> Output type = " + type); ingo@646: log.info("-> Output subtype = " + subtype); ingo@388: ingo@646: OutGenerator generator = null; felix@1780: if (type != null felix@1780: && type.length() > 0 felix@1780: && type.indexOf("chartinfo") > 0) felix@1780: { felix@1780: generator = getOutGenerator(context, type, subtype); ingo@646: } ingo@646: else { ingo@646: generator = getOutGenerator(context, name, subtype); ingo@646: } ingo@646: ingo@300: if (generator == null) { ingo@390: log.error("There is no generator specified for output: " + name); felix@1013: // TODO Throw an exception. ingo@300: ingo@300: return; ingo@300: } ingo@300: ingo@1999: Document oldAttrs = getAttribute(); ingo@1999: AttributeParser parser = new AttributeParser(oldAttrs); ingo@1999: CollectionAttribute cAttr = parser.getCollectionAttribute(); ingo@1999: ingo@1999: Output output = cAttr.getOutput(name); ingo@1999: Settings settings = output.getSettings(); ingo@1999: ingo@300: generator.init(format, out, context); ingo@2047: generator.setSettings(settings); ingo@1988: prepareMasterArtifact(generator, context); ingo@300: ingo@1988: try { ingo@1999: Document attr = getAttribute(context, cAttr, name); ingo@1988: doOut(generator, name, subtype, attr, context); ingo@1988: generator.generate(); ingo@1988: } ingo@1988: catch (ArtifactDatabaseException adbe) { ingo@1988: log.error(adbe, adbe); ingo@1988: } ingo@1998: ingo@1998: long duration = System.currentTimeMillis() -reqBegin; ingo@1998: log.info("Processing out(" + name + ") took " + duration + " ms."); ingo@1988: } ingo@1988: ingo@1988: ingo@1988: /** ingo@1988: * Sets the master Artifact at the given generator. ingo@1988: * ingo@1988: * @param generator The generator that gets a master Artifact. ingo@1988: * @param cc The CallContext. ingo@1988: */ ingo@1988: protected void prepareMasterArtifact(OutGenerator generator, CallContext cc ingo@1988: ) { felix@1744: // Get master artifact. ingo@1988: FLYSArtifact master = getMasterArtifact(cc); felix@1784: if (master != null) { ingo@1988: log.debug("Set master Artifact to uuid: " + master.identifier()); felix@1784: generator.setMasterArtifact(master); felix@1780: } felix@1784: else { felix@1784: log.warn("Could not set master artifact."); felix@1744: } ingo@347: } ingo@300: ingo@347: ingo@347: /** felix@1029: * Creates the concrete output. ingo@347: * ingo@347: * @param generator The OutGenerator that creates the output. ingo@350: * @param outputName The name of the requested output. ingo@347: * @param attributes The collection's attributes for this concrete output ingo@347: * type. ingo@347: * @param context The context object. ingo@347: */ ingo@347: protected void doOut( ingo@347: OutGenerator generator, ingo@350: String outName, ingo@388: String facet, ingo@347: Document attributes, ingo@347: CallContext context) ingo@347: throws IOException ingo@347: { ingo@646: log.info("FLYSArtifactCollection.doOut: " + outName); ingo@347: ingo@347: ThemeList themeList = new ThemeList(attributes); ingo@347: ingo@347: int size = themeList.size(); ingo@347: log.debug("Output will contain " + size + " elements."); ingo@347: felix@1946: List dataProviders = felix@1946: doBlackboardPass(themeList, context); felix@1946: ingo@347: try { ingo@347: for (int i = 0; i < size; i++) { ingo@347: ManagedFacet theme = themeList.get(i); ingo@347: ingo@347: if (theme == null) { ingo@370: log.debug("Theme is empty - no output is generated."); ingo@347: continue; ingo@347: } ingo@347: ingo@347: String art = theme.getArtifact(); felix@1946: String facetName = theme.getName(); ingo@347: ingo@347: if (log.isDebugEnabled()) { ingo@347: log.debug("Do output for..."); ingo@347: log.debug("... artifact: " + art); felix@1946: log.debug("... facet: " + facetName); ingo@347: } ingo@347: ingo@388: if (outName.equals("export") && !facetName.equals(facet)) { ingo@388: continue; ingo@388: } ingo@388: felix@2011: // Skip invisible themes. felix@2011: if (theme.getVisible() == 0) { felix@2011: continue; felix@2011: } felix@2011: ingo@347: generator.doOut( felix@1946: dataProviders.get(i), ingo@350: getFacetThemeFromAttribute( ingo@350: art, ingo@350: outName, ingo@364: facetName, ingo@1747: theme.getDescription(), ingo@1668: theme.getIndex(), ingo@1684: context), ingo@1684: theme.getActive() == 1); ingo@300: } ingo@300: } ingo@300: catch (ArtifactDatabaseException ade) { ingo@300: log.error(ade, ade); ingo@300: } ingo@300: } ingo@300: ingo@300: felix@1628: /** felix@1946: * Show blackboard (context) to each facet and create a list of felix@1946: * ArtifactAndFacets on the fly (with the same ordering as the passed felix@1946: * ThemeList). felix@1946: * @param themeList ThemeList to create a ArtifactAndFacetList along. felix@1946: * @param contect The "Blackboard". felix@1946: */ felix@1946: protected List doBlackboardPass( felix@1946: ThemeList themeList, CallContext context felix@1946: ) { felix@1946: ArrayList dataProviders = felix@1946: new ArrayList(); felix@1946: int size = themeList.size(); felix@1946: felix@1946: try { felix@1946: // Collect all ArtifactAndFacets for blackboard pass. felix@1946: for (int i = 0; i < size; i++) { felix@1946: ManagedFacet theme = themeList.get(i); felix@2212: if (theme == null) { felix@2212: log.warn("A ManagedFacet in ThemeList is null."); felix@2212: continue; felix@2212: } felix@1946: String uuid = theme.getArtifact(); felix@1946: Artifact artifact = getArtifact(uuid, context); felix@1946: FLYSArtifact flys = (FLYSArtifact) artifact; ingo@2325: ingo@2325: ArtifactAndFacet artifactAndFacet = new ArtifactAndFacet( ingo@2325: artifact, felix@1946: flys.getNativeFacet(theme)); felix@1946: ingo@2325: // XXX HELP ME PLEASE ingo@2325: artifactAndFacet.setFacetDescription(theme.getDescription()); ingo@2325: felix@1946: // Show blackboard to facet. felix@1946: artifactAndFacet.register(context); felix@1946: felix@1946: // Add to themes. felix@1946: dataProviders.add(i, artifactAndFacet); felix@1946: } felix@1946: } felix@1946: catch (ArtifactDatabaseException ade) { felix@1946: log.error("ArtifactDatabaseException!", ade); felix@1946: } felix@1946: felix@1946: return dataProviders; felix@1946: } ingo@1972: ingo@1972: felix@1946: /** felix@1784: * @return masterartifact or null if exception/not found. felix@1784: */ felix@1784: protected FLYSArtifact getMasterArtifact(CallContext context) felix@1784: { felix@1784: try { felix@1784: ArtifactDatabase db = context.getDatabase(); felix@1784: CallMeta callMeta = context.getMeta(); felix@1784: Document document = db.getCollectionsMasterArtifact( felix@1784: identifier(), callMeta); ingo@1972: felix@1784: String masterUUID = XMLUtils.xpathString( felix@1784: document, XPATH_MASTER_UUID, ArtifactNamespaceContext.INSTANCE); felix@1784: FLYSArtifact masterArtifact = felix@1784: (FLYSArtifact) getArtifact(masterUUID, context); felix@1784: return masterArtifact; felix@1784: } felix@1784: catch (ArtifactDatabaseException ade) { felix@1784: log.error(ade, ade); felix@1784: } felix@1784: return null; felix@1784: } felix@1784: felix@1784: felix@1784: /** felix@1628: * Return merged output document. felix@1709: * @param uuids List of artifact uuids. felix@1628: */ ingo@1976: protected CollectionAttribute buildOutAttributes( ingo@346: ArtifactDatabase db, ingo@346: CallContext context, ingo@1976: AttributeParser aParser, felix@1709: String[] uuids) ingo@346: { ingo@346: Document doc = XMLUtils.newDocument(); ingo@346: felix@1785: FLYSContext flysContext = FLYSUtils.getFlysContext(context); felix@1785: StateEngine engine = (StateEngine) flysContext.get( felix@1785: FLYSContext.STATE_ENGINE_KEY); felix@1785: felix@1785: FLYSArtifact masterArtifact = getMasterArtifact(context); ingo@1972: ingo@346: XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator( ingo@346: doc, ingo@346: ArtifactNamespaceContext.NAMESPACE_URI, ingo@346: ArtifactNamespaceContext.NAMESPACE_PREFIX); ingo@1972: ingo@1976: OutputParser oParser = new OutputParser(db, context); ingo@1972: felix@1709: if (uuids != null) { felix@1709: for (String uuid: uuids) { ingo@1175: try { ingo@1175: oParser.parse(uuid); ingo@1175: } ingo@1175: catch (ArtifactDatabaseException ade) { ingo@1175: log.warn(ade, ade); ingo@1175: } ingo@346: } ingo@346: } ingo@1976: ingo@1976: aParser.parse(); felix@1950: felix@1709: return new AttributeWriter( felix@1709: db, ingo@1993: aParser.getCollectionAttribute(), felix@1709: aParser.getOuts(), felix@1785: aParser.getFacets(), felix@1785: oParser.getOuts(), felix@1785: oParser.getFacets(), felix@1785: engine.getCompatibleFacets(masterArtifact.getStateHistoryIds()) felix@1785: ).write(); ingo@346: } ingo@346: ingo@346: ingo@300: /** felix@1780: * Returns the "attribute" (part of description document) for a specific felix@1780: * output type. ingo@347: * ingo@1999: * @param context The CallContext object. ingo@1999: * @param cAttr The CollectionAttribute. ingo@347: * @param output The name of the desired output type. ingo@347: * ingo@347: * @return the attribute for the desired output type. ingo@347: */ ingo@1999: protected Document getAttribute( ingo@1999: CallContext context, ingo@1999: CollectionAttribute cAttr, ingo@1999: String output) ingo@347: throws ArtifactDatabaseException ingo@347: { ingo@1976: Document attr = cAttr.toXML(); ingo@1976: ingo@347: Node out = (Node) XMLUtils.xpath( ingo@347: attr, ingo@638: "art:attribute/art:outputs/art:output[@name='" + output + "']", ingo@347: XPathConstants.NODE, ingo@347: ArtifactNamespaceContext.INSTANCE); ingo@347: ingo@347: ingo@347: if (out != null) { ingo@347: Document o = XMLUtils.newDocument(); ingo@347: ingo@347: o.appendChild(o.importNode(out, true)); ingo@347: ingo@347: return o; ingo@347: } ingo@347: ingo@347: return null; ingo@347: } ingo@347: ingo@347: ingo@347: /** ingo@300: * This method returns the list of artifact UUIDs that this collections ingo@300: * contains. ingo@300: * ingo@300: * @param context The CallContext that is necessary to get information about ingo@300: * the ArtifactDatabase. ingo@300: * ingo@300: * @return a list of uuids. ingo@300: */ ingo@300: protected String[] getArtifactUUIDs(CallContext context) ingo@300: throws ArtifactDatabaseException ingo@300: { ingo@300: log.debug("FLYSArtifactCollection.getArtifactUUIDs"); ingo@300: ingo@300: ArtifactDatabase db = context.getDatabase(); ingo@300: CallMeta meta = context.getMeta(); ingo@300: ingo@300: Document itemList = db.listCollectionArtifacts(identifier(), meta); ingo@300: NodeList items = (NodeList) XMLUtils.xpath( ingo@300: itemList, ingo@300: XPATH_COLLECTION_ITEMS, ingo@300: XPathConstants.NODESET, ingo@300: ArtifactNamespaceContext.INSTANCE); ingo@300: ingo@300: if (items == null || items.getLength() == 0) { ingo@300: log.debug("No artifacts found in this collection."); ingo@300: return null; ingo@300: } ingo@300: ingo@300: int num = items.getLength(); ingo@300: ingo@300: List uuids = new ArrayList(num); ingo@300: ingo@300: for (int i = 0; i < num; i++) { ingo@300: String uuid = XMLUtils.xpathString( ingo@300: items.item(i), ingo@300: "@art:uuid", ingo@300: ArtifactNamespaceContext.INSTANCE); ingo@300: ingo@300: if (uuid != null && uuid.trim().length() != 0) { ingo@300: uuids.add(uuid); ingo@300: } ingo@300: } ingo@300: ingo@300: return (String[]) uuids.toArray(new String[uuids.size()]); ingo@300: } ingo@300: ingo@300: ingo@300: /** ingo@300: * Returns a concrete Artifact of this collection specified by its uuid. ingo@300: * ingo@300: * @param uuid The Artifact's uuid. ingo@300: * @param context The CallContext. ingo@300: * ingo@300: * @return an Artifact. ingo@300: */ ingo@300: protected Artifact getArtifact(String uuid, CallContext context) ingo@300: throws ArtifactDatabaseException ingo@300: { ingo@300: log.debug("FLYSArtifactCollection.getArtifact"); ingo@300: ingo@300: Backend backend = Backend.getInstance(); ingo@300: PersistentArtifact persistent = backend.getArtifact(uuid); ingo@300: ingo@300: return persistent != null ? persistent.getArtifact() : null; ingo@300: } ingo@300: ingo@300: ingo@300: /** felix@1822: * Returns the attribute that belongs to an artifact and facet stored in felix@1822: * this collection. ingo@300: * ingo@300: * @param uuid The Artifact's uuid. ingo@350: * @param outname The name of the requested output. ingo@350: * @param facet The name of the requested facet. ingo@300: * @param context The CallContext. ingo@300: * ingo@300: * @return an attribute in form of a document. ingo@300: */ ingo@350: protected Document getFacetThemeFromAttribute( ingo@350: String uuid, ingo@350: String outName, ingo@350: String facet, ingo@1747: String pattern, ingo@1668: int index, ingo@350: CallContext context) ingo@300: throws ArtifactDatabaseException ingo@300: { ingo@350: log.debug("FLYSArtifactCollection.getFacetThemeFromAttribute"); ingo@300: ingo@350: ArtifactDatabase db = context.getDatabase(); ingo@350: CallMeta meta = context.getMeta(); ingo@350: ingo@350: FLYSContext flysContext = context instanceof FLYSContext ingo@350: ? (FLYSContext) context ingo@350: : (FLYSContext) context.globalContext(); ingo@350: ingo@350: Document attr = db.getCollectionItemAttribute(identifier(), uuid, meta); ingo@350: ingo@350: if (attr == null) { felix@1828: attr = initItemAttribute(uuid, facet, pattern, index, outName, context); ingo@350: ingo@350: if (attr == null) { ingo@350: return null; ingo@350: } ingo@350: } ingo@350: ingo@350: log.debug("Search attribute of collection item: " + uuid); ingo@350: ingo@350: Node tmp = (Node) XMLUtils.xpath( ingo@350: attr, ingo@350: "/art:attribute", ingo@350: XPathConstants.NODE, ingo@350: ArtifactNamespaceContext.INSTANCE); ingo@350: ingo@350: if (tmp == null) { ingo@350: log.warn("No attribute found. Operation failed."); ingo@350: return null; ingo@350: } ingo@350: ingo@1747: log.debug("Search theme for facet '" + facet + "' in attribute."); ingo@350: ingo@350: Node theme = (Node) XMLUtils.xpath( ingo@350: tmp, ingo@1668: "art:themes/theme[@facet='" + facet + ingo@1668: "' and @index='" + String.valueOf(index) + "']", ingo@350: XPathConstants.NODE, ingo@350: ArtifactNamespaceContext.INSTANCE); ingo@350: ingo@350: if (theme == null) { ingo@350: log.warn("Could not find the theme in attribute of: " + uuid); ingo@350: felix@1828: Theme t = getThemeForFacet( felix@1828: uuid, facet, pattern, index, outName, context); ingo@350: ingo@350: if (t == null) { ingo@350: log.warn("No theme found for facet: " + facet); ingo@350: return null; ingo@350: } ingo@350: ingo@350: addThemeToAttribute(uuid, attr, t, context); felix@1828: theme = t.toXML().getFirstChild(); ingo@350: } ingo@350: ingo@350: Document doc = XMLUtils.newDocument(); ingo@350: doc.appendChild(doc.importNode(theme, true)); ingo@350: ingo@350: return doc; ingo@350: } ingo@350: ingo@350: ingo@350: /** ingo@350: * Adds the theme of a facet to a CollectionItem's attribute. ingo@350: * ingo@350: * @param uuid The uuid of the artifact. ingo@350: * @param attr The current attribute of an artifact. ingo@350: * @param t The theme to add. ingo@350: * @param context The CallContext. ingo@350: */ ingo@350: protected void addThemeToAttribute( ingo@350: String uuid, ingo@350: Document attr, ingo@350: Theme t, ingo@350: CallContext context) ingo@350: { ingo@350: log.debug("FLYSArtifactCollection.addThemeToAttribute: " + uuid); ingo@350: ingo@350: if (t == null) { ingo@350: log.warn("Theme is empty - cancel adding it to attribute!"); ingo@350: return; ingo@350: } ingo@350: ingo@350: XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator( ingo@350: attr, ingo@350: ArtifactNamespaceContext.NAMESPACE_URI, ingo@350: ArtifactNamespaceContext.NAMESPACE_PREFIX); ingo@350: ingo@350: Node tmp = (Node) XMLUtils.xpath( ingo@350: attr, ingo@350: "/art:attribute", ingo@350: XPathConstants.NODE, ingo@350: ArtifactNamespaceContext.INSTANCE); ingo@350: ingo@350: if (tmp == null) { ingo@350: tmp = ec.create("attribute"); ingo@350: attr.appendChild(tmp); ingo@350: } ingo@350: ingo@350: Node themes = (Node) XMLUtils.xpath( ingo@350: tmp, ingo@350: "art:themes", ingo@350: XPathConstants.NODE, ingo@350: ArtifactNamespaceContext.INSTANCE); ingo@350: ingo@350: if (themes == null) { ingo@350: themes = ec.create("themes"); ingo@350: tmp.appendChild(themes); ingo@350: } ingo@350: ingo@350: themes.appendChild(attr.importNode(t.toXML().getFirstChild(), true)); ingo@350: ingo@350: try { ingo@350: setCollectionItemAttribute(uuid, attr, context); ingo@350: ingo@350: log.debug("Successfully added theme to item attribute."); ingo@350: } ingo@350: catch (ArtifactDatabaseException e) { ingo@350: // do nothing ingo@350: log.warn("Cannot set attribute of item: " + uuid); ingo@350: } ingo@350: } ingo@350: ingo@350: ingo@350: /** ingo@350: * Initializes the attribute of an collection item with the theme of a ingo@350: * specific facet. ingo@350: * ingo@350: * @param uuid The uuid of an artifact. ingo@350: * @param facet The name of a facet. ingo@350: * @param context The CallContext. ingo@350: * ingo@350: * @param the new attribute. ingo@350: */ ingo@350: protected Document initItemAttribute( ingo@350: String uuid, ingo@350: String facet, ingo@1747: String pattern, ingo@1668: int index, felix@1828: String outName, ingo@350: CallContext context) ingo@350: { ingo@350: log.info("FLYSArtifactCollection.initItemAttribute"); ingo@350: felix@1828: Theme t = getThemeForFacet(uuid, facet, pattern, index, outName, context); ingo@350: ingo@350: if (t == null) { ingo@350: log.info("Could not find theme for facet. Cancel initialization."); ingo@350: return null; ingo@350: } ingo@350: ingo@350: Document attr = XMLUtils.newDocument(); ingo@350: ingo@350: addThemeToAttribute(uuid, attr, t, context); ingo@350: ingo@350: return attr; ingo@350: } ingo@350: ingo@350: ingo@350: /** ingo@350: * Sets the attribute of a CollectionItem specified by uuid to a new ingo@350: * value attr. ingo@350: * ingo@350: * @param uuid The uuid of the CollectionItem. ingo@350: * @param attr The new attribute for the CollectionItem. ingo@350: * @param context The CallContext. ingo@350: */ ingo@350: public void setCollectionItemAttribute( ingo@350: String uuid, ingo@350: Document attr, ingo@350: CallContext context) ingo@350: throws ArtifactDatabaseException ingo@350: { ingo@350: Document doc = ClientProtocolUtils.newSetItemAttributeDocument( ingo@350: uuid, ingo@350: attr); ingo@350: ingo@350: if (doc == null) { ingo@350: log.warn("Cannot set item attribute: No attribute found."); ingo@350: return; ingo@350: } ingo@350: ingo@350: ArtifactDatabase db = context.getDatabase(); ingo@350: CallMeta meta = context.getMeta(); ingo@350: ingo@350: db.setCollectionItemAttribute(identifier(), uuid, doc, meta); ingo@350: } ingo@350: ingo@350: ingo@350: /** ingo@350: * Returns the theme of a specific facet. ingo@350: * ingo@350: * @param uuid The uuid of an artifact. ingo@350: * @param facet The name of the facet. ingo@350: * @param context The CallContext object. ingo@350: * ingo@350: * @return the desired theme. ingo@350: */ ingo@350: protected Theme getThemeForFacet( ingo@350: String uuid, ingo@350: String facet, ingo@1747: String pattern, ingo@1668: int index, felix@1828: String outName, ingo@350: CallContext context) ingo@350: { ingo@350: log.info("FLYSArtifactCollection.getThemeForFacet: " + facet); ingo@350: ingo@350: FLYSContext flysContext = context instanceof FLYSContext ingo@350: ? (FLYSContext) context ingo@350: : (FLYSContext) context.globalContext(); ingo@350: felix@1822: // Push artifact in flysContext. felix@1822: ArtifactDatabase db = context.getDatabase(); felix@1822: try { felix@1822: FLYSArtifact artifact = (FLYSArtifact) db.getRawArtifact(uuid); felix@1822: log.debug("Got raw artifact"); felix@1822: flysContext.put(flysContext.ARTIFACT_KEY, artifact); felix@1822: } felix@1837: catch (ArtifactDatabaseException dbe) { felix@1837: log.error("Exception caught when trying to get art.", dbe); felix@1822: } felix@1822: raimund@2737: Theme t = ThemeFactory.getTheme( raimund@2737: flysContext, raimund@2737: facet, raimund@2737: pattern, raimund@2737: outName, raimund@2737: "default"); ingo@1668: ingo@1668: if (t != null) { ingo@1668: t.setFacet(facet); ingo@1668: t.setIndex(index); ingo@1668: } ingo@1668: ingo@1668: return t; ingo@300: } ingo@300: ingo@300: ingo@300: /** ingo@300: * Returns the OutGenerator for a specified type. ingo@300: * ingo@300: * @param name The name of the output type. ingo@300: * @param type Defines the type of the desired OutGenerator. ingo@300: * felix@1029: * @return Instance of an OutGenerator for specified type. ingo@300: */ ingo@300: protected OutGenerator getOutGenerator( ingo@300: CallContext context, ingo@300: String name, ingo@300: String type) ingo@300: { ingo@1999: log.debug("Search OutGenerator for Output '" + name + "'"); ingo@1999: ingo@300: FLYSContext flysContext = context instanceof FLYSContext ingo@300: ? (FLYSContext) context ingo@300: : (FLYSContext) context.globalContext(); ingo@300: ingo@300: Map generators = (Map) ingo@300: flysContext.get(FLYSContext.OUTGENERATORS_KEY); ingo@300: ingo@300: if (generators == null) { ingo@300: log.error("No output generators found in the running application!"); ingo@300: return null; ingo@300: } ingo@300: ingo@388: Class clazz = generators.get(name); ingo@300: ingo@300: try { ingo@300: return clazz != null ? (OutGenerator) clazz.newInstance() : null; ingo@300: } ingo@300: catch (InstantiationException ie) { ingo@300: log.error(ie, ie); ingo@300: } ingo@300: catch (IllegalAccessException iae) { ingo@300: log.error(iae, iae); ingo@300: } ingo@300: ingo@300: return null; ingo@300: } ingo@300: ingo@300: felix@1950: /** ingo@347: * Inner class to structure/order the themes of a chart. ingo@347: */ sascha@1718: private static class ThemeList { ingo@347: private Logger logger = Logger.getLogger(ThemeList.class); ingo@638: protected Map themes; ingo@347: ingo@347: public ThemeList(Document output) { ingo@638: themes = new HashMap(); ingo@347: parse(output); ingo@347: } ingo@347: ingo@347: protected void parse(Document output) { ingo@1717: NodeList themeList = (NodeList) XMLUtils.xpath( ingo@347: output, ingo@945: "art:output/art:facet", ingo@347: XPathConstants.NODESET, ingo@347: ArtifactNamespaceContext.INSTANCE); ingo@347: ingo@1717: int num = themeList != null ? themeList.getLength() : 0; ingo@347: ingo@347: logger.debug("Output has " + num + " elements."); ingo@347: ingo@347: if (num == 0) { ingo@347: return; ingo@347: } ingo@347: ingo@694: String uri = ArtifactNamespaceContext.NAMESPACE_URI; ingo@347: ingo@694: for (int i = 0; i < num; i++) { ingo@1717: Element theme = (Element) themeList.item(i); ingo@347: ingo@1717: ManagedDomFacet facet = new ManagedDomFacet(theme); sascha@1718: themes.put(Integer.valueOf(facet.getPosition()-1), facet); ingo@347: } ingo@347: } ingo@347: ingo@347: public ManagedFacet get(int idx) { sascha@1718: return themes.get(Integer.valueOf(idx)); ingo@347: } ingo@347: ingo@347: public int size() { ingo@347: return themes.size(); ingo@347: } ingo@347: } ingo@147: } ingo@147: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :