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);
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:
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@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@1946: String uuid = theme.getArtifact();
felix@1946: Artifact artifact = getArtifact(uuid, context);
felix@1946: FLYSArtifact flys = (FLYSArtifact) artifact;
felix@1946: ArtifactAndFacet artifactAndFacet = new ArtifactAndFacet(artifact,
felix@1946: flys.getNativeFacet(theme));
felix@1946:
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:
felix@1828: Theme t = ThemeFactory.getTheme(flysContext, facet, pattern, outName);
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 :