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@147: import java.util.Date; ingo@300: import java.util.List; ingo@300: import java.util.Map; 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@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; ingo@147: ingo@300: import de.intevation.flys.artifacts.context.FLYSContext; ingo@300: import de.intevation.flys.exports.OutGenerator; ingo@300: ingo@147: ingo@147: /** ingo@147: * @author Ingo Weinzierl ingo@147: */ ingo@147: public class FLYSArtifactCollection extends DefaultArtifactCollection { ingo@147: ingo@147: /** The logger used in this class.*/ ingo@147: private static Logger log = Logger.getLogger(FLYSArtifactCollection.class); ingo@147: ingo@147: ingo@147: /** 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: 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: ingo@300: ingo@147: ingo@147: @Override ingo@147: public Document describe(CallContext context) { ingo@147: log.debug("FLYSArtifactCollection.describe: " + identifier); ingo@147: ingo@147: Document doc = XMLUtils.newDocument(); ingo@147: ingo@147: XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator( ingo@147: doc, ingo@147: ArtifactNamespaceContext.NAMESPACE_URI, ingo@147: ArtifactNamespaceContext.NAMESPACE_PREFIX); ingo@147: ingo@147: Date creationTime = getCreationTime(); ingo@147: String creation = creationTime != null ingo@147: ? Long.toString(creationTime.getTime()) ingo@147: : ""; ingo@147: ingo@147: Element collection = ec.create("artifact-collection"); ingo@147: Element artifacts = ec.create("artifacts"); ingo@346: Element attributes = ec.create("attribute"); ingo@147: ingo@147: ec.addAttr(collection, "name", getName(), true); ingo@147: ec.addAttr(collection, "uuid", identifier(), true); ingo@147: ec.addAttr(collection, "creation", creation, true); ingo@147: ingo@147: collection.appendChild(artifacts); ingo@346: collection.appendChild(attributes); ingo@147: doc.appendChild(collection); ingo@147: ingo@346: ArtifactDatabase db = context.getDatabase(); ingo@293: ingo@300: try { ingo@300: String[] artifactUUIDs = getArtifactUUIDs(context); ingo@293: ingo@346: Document oldAttrs = getAttribute(); ingo@346: Document attrs = buildAttributes( ingo@346: db, context, ingo@346: oldAttrs, ingo@346: artifactUUIDs); ingo@346: ingo@346: db.setCollectionAttribute(identifier(), context.getMeta(), attrs); ingo@346: ingo@346: Node child = attrs.getFirstChild(); ingo@346: attributes.appendChild(doc.importNode(child, true)); ingo@346: ingo@300: for (String uuid: artifactUUIDs) { ingo@293: try { ingo@293: artifacts.appendChild( ingo@293: buildArtifactNode(db, uuid, context, ec)); ingo@293: } ingo@293: catch (ArtifactDatabaseException dbe) { ingo@293: log.warn(dbe, dbe); ingo@293: } ingo@293: } ingo@293: } ingo@293: catch (ArtifactDatabaseException ade) { ingo@293: log.error(ade, ade); ingo@147: } ingo@147: ingo@147: return doc; ingo@147: } ingo@147: ingo@147: ingo@300: @Override ingo@300: public void out(Document format, OutputStream out, CallContext context) ingo@300: throws IOException ingo@300: { 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@300: String type = XMLUtils.xpathString( ingo@300: format, XPATH_OUT_TYPE, ArtifactNamespaceContext.INSTANCE); ingo@300: ingo@300: OutGenerator generator = getOutGenerator(context, name, type); ingo@300: if (generator == null) { ingo@300: log.error("There is no generator specified for output: " + type); ingo@300: // TODO throw an exception. ingo@300: ingo@300: return; ingo@300: } ingo@300: ingo@300: generator.init(format, out, context); ingo@300: ingo@300: try { ingo@300: Object[][] container = getArtifactsWithAttribute(context); ingo@300: ingo@300: for (Object[] obj: container) { ingo@300: generator.doOut((Artifact) obj[0], (Document) obj[1]); ingo@300: } ingo@300: } ingo@300: catch (ArtifactDatabaseException ade) { ingo@300: log.error(ade, ade); ingo@300: } ingo@300: ingo@300: generator.generate(); ingo@300: } ingo@300: ingo@300: ingo@346: protected Document buildAttributes( ingo@346: ArtifactDatabase db, ingo@346: CallContext context, ingo@346: Document oldAttr, ingo@346: String[] items) ingo@346: { ingo@346: Document doc = XMLUtils.newDocument(); ingo@346: ingo@346: XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator( ingo@346: doc, ingo@346: ArtifactNamespaceContext.NAMESPACE_URI, ingo@346: ArtifactNamespaceContext.NAMESPACE_PREFIX); ingo@346: ingo@346: AttributeParser aParser = new AttributeParser(); ingo@346: OutputParser oParser = new OutputParser(db, context.getMeta()); ingo@346: ingo@346: for (String uuid: items) { ingo@346: try { ingo@346: oParser.parse(uuid); ingo@346: } ingo@346: catch (ArtifactDatabaseException ade) { ingo@346: log.warn(ade, ade); ingo@346: } ingo@346: } ingo@346: ingo@346: aParser.parse(oldAttr); ingo@346: ingo@346: return new AttributeWriter(aParser.getOuts(), oParser.getOuts()).write(); ingo@346: } ingo@346: ingo@346: ingo@300: /** 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: /** ingo@300: * Returns the attribute that belongs to an artifact stored in this ingo@300: * collection. ingo@300: * ingo@300: * @param uuid The Artifact's uuid. ingo@300: * @param context The CallContext. ingo@300: * ingo@300: * @return an attribute in form of a document. ingo@300: */ ingo@300: protected Document getArtifactAttribute(String uuid, CallContext context) ingo@300: throws ArtifactDatabaseException ingo@300: { ingo@300: log.debug("FLYSArtifactCollection.getArtifactAttribute"); ingo@300: ingo@300: // TODO FILL ME ingo@300: return null; ingo@300: } ingo@300: ingo@300: ingo@300: /** ingo@300: * Returns a list of Artifact/Attribute pairs. ingo@300: * ingo@300: * @param context The CallContext. ingo@300: * ingo@300: * @return a list of Artifact/Attribute pairs. ingo@300: */ ingo@300: protected Object[][] getArtifactsWithAttribute(CallContext context) ingo@300: throws ArtifactDatabaseException ingo@300: { ingo@300: log.debug("FLYSArtifactCollection.getArtifactWithAttribute"); ingo@300: ingo@300: ArtifactDatabase db = context.getDatabase(); ingo@300: CallMeta meta = context.getMeta(); ingo@300: ingo@300: String[] uuids = getArtifactUUIDs(context); ingo@300: Object[][] awa = new Object[uuids.length][2]; ingo@300: ingo@300: for (int i = 0; i < uuids.length; i++) { ingo@300: try { ingo@300: Artifact artifact = getArtifact(uuids[i], context); ingo@300: Document attribute = getArtifactAttribute(uuids[i], context); ingo@300: ingo@300: if (artifact == null) { ingo@300: log.warn("Artifact '" + uuids[i] + "' is not existing."); ingo@300: continue; ingo@300: } ingo@300: ingo@300: awa[i][0] = artifact; ingo@300: awa[i][1] = attribute; ingo@300: } ingo@300: catch (ArtifactDatabaseException ade) { ingo@300: log.warn(ade, ade); ingo@300: } ingo@300: } ingo@300: ingo@300: return awa; 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: * ingo@300: * @return The OutGenerator specified by type. ingo@300: */ ingo@300: protected OutGenerator getOutGenerator( ingo@300: CallContext context, ingo@300: String name, ingo@300: String type) ingo@300: { 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@300: Class clazz = generators.get(type); 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: ingo@147: protected Element buildArtifactNode( ingo@293: ArtifactDatabase database, ingo@293: String uuid, ingo@147: CallContext context, ingo@147: XMLUtils.ElementCreator ec) ingo@293: throws ArtifactDatabaseException ingo@147: { ingo@293: log.debug("Append artifact '" + uuid + "' to collection description"); ingo@147: ingo@346: // TODO ingo@293: String hash = "MYHASH"; ingo@156: ingo@147: Element ci = ec.create("artifact"); ingo@148: ec.addAttr(ci, "uuid", uuid, true); ingo@293: ec.addAttr(ci, "hash", hash, true); ingo@147: ingo@346: // XXX I am not sure if it works well every time with an empty document ingo@346: // in the describe operation of an artifact. ingo@346: Document description = database.describe(uuid, null, context.getMeta()); ingo@346: ingo@293: Node outputModes = (Node) XMLUtils.xpath( ingo@147: description, ingo@147: XPATH_ARTIFACT_OUTPUTMODES, ingo@147: XPathConstants.NODE, ingo@147: ArtifactNamespaceContext.INSTANCE); ingo@147: ingo@147: if (outputModes != null) { ingo@147: Document doc = ci.getOwnerDocument(); ingo@147: ci.appendChild(doc.importNode(outputModes, true)); ingo@147: } ingo@147: ingo@147: return ci; ingo@147: } ingo@147: } ingo@147: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :