ingo@105: /* ingo@105: * Copyright (c) 2011 by Intevation GmbH ingo@105: * ingo@105: * This program is free software under the LGPL (>=v2.1) ingo@105: * Read the file LGPL.txt coming with the software for details ingo@105: * or visit http://www.gnu.org/licenses/ if it does not exist. ingo@105: */ ingo@105: package de.intevation.artifactdatabase.state; ingo@105: ingo@209: import java.util.ArrayList; ingo@105: import java.util.HashMap; ingo@209: import java.util.List; ingo@105: import java.util.Map; ingo@105: ingo@106: import javax.xml.xpath.XPathConstants; ingo@106: ingo@226: import org.apache.log4j.Logger; ingo@226: ingo@105: import org.w3c.dom.Document; ingo@205: import org.w3c.dom.Element; ingo@105: import org.w3c.dom.Node; ingo@209: import org.w3c.dom.NodeList; ingo@105: ingo@244: import de.intevation.artifacts.Artifact; ingo@209: import de.intevation.artifacts.ArtifactNamespaceContext; ingo@105: import de.intevation.artifacts.CallContext; ingo@363: import de.intevation.artifacts.CallMeta; ingo@105: ingo@106: import de.intevation.artifacts.common.utils.XMLUtils; ingo@106: ingo@105: import de.intevation.artifactdatabase.data.StateData; ingo@105: ingo@105: ingo@105: /** ingo@105: * An abstract implementation of a {@link State}. It implements some basic ingo@105: * methods that return the id, description and data. The methods ingo@105: * describe() and setup() depend on the concrete class ingo@105: * and need to be implemented by those. ingo@105: */ ingo@105: public abstract class AbstractState implements State { ingo@105: ingo@106: /** The XPath to the ID of the state relative to the state node in the ingo@106: * configuration. */ ingo@106: public static final String XPATH_ID = "@id"; ingo@106: ingo@106: /** The XPath to the description of the state relative to the state node in ingo@106: * the configuration. */ ingo@106: public static final String XPATH_DESCRIPTION = "@description"; ingo@106: felix@367: /** The XPath to the output nodes of the state configuration. */ ingo@209: public static final String XPATH_OUTPUT_MODES = "outputmodes/outputmode"; ingo@209: ingo@226: /** The XPath to the list of facets relative to the output mode it belongs felix@367: * to. */ ingo@226: public static final String XPATH_FACETS = "facets/facet"; ingo@226: ingo@226: felix@367: /** The logger that is used in this class. */ ingo@226: private static Logger logger = Logger.getLogger(AbstractState.class); ingo@226: ingo@106: ingo@105: /** The ID of the state. */ ingo@105: protected String id; ingo@105: ingo@105: /** The description of the state. */ ingo@105: protected String description; ingo@105: ingo@105: /** The data provided by this state. */ ingo@105: protected Map data; ingo@105: felix@367: /** A list of output modes which are available for this state. */ ingo@209: protected List outputs; ingo@209: ingo@105: ingo@205: public AbstractState() { ingo@209: outputs = new ArrayList(); ingo@205: } ingo@205: ingo@205: ingo@105: /** ingo@105: * The default constructor. ingo@105: * ingo@105: * @param id The ID of the state. ingo@105: * @param description The description of the state. ingo@105: */ ingo@105: public AbstractState(String id, String description) { ingo@209: super(); ingo@209: ingo@105: this.id = id; ingo@105: this.description = description; ingo@105: } ingo@105: ingo@105: ingo@105: /** ingo@105: * Returns the ID of the state. ingo@105: * ingo@105: * @return the ID of the state. ingo@105: */ ingo@105: public String getID() { ingo@105: return id; ingo@105: } ingo@105: ingo@105: ingo@105: /** ingo@105: * Set the ID of the state. ingo@105: * ingo@105: * @param id The ID of the state. ingo@105: */ ingo@105: public void setID(String id) { ingo@105: this.id = id; ingo@105: } ingo@105: ingo@105: ingo@105: /** ingo@105: * Returns the description of the state. ingo@105: * ingo@105: * @return the description of the state. ingo@105: */ ingo@105: public String getDescription() { ingo@105: return description; ingo@105: } ingo@105: ingo@105: ingo@105: /** ingo@105: * Set the description of the state. ingo@105: * ingo@105: * @param description The description of the state. ingo@105: */ ingo@105: public void setDescription(String description) { ingo@105: this.description = description; ingo@105: } ingo@105: ingo@105: ingo@105: /** ingo@105: * Returns the data of the state. ingo@105: * ingo@105: * @return the data of the state. ingo@105: */ ingo@105: public Map getData() { ingo@105: return data; ingo@105: } ingo@105: ingo@105: ingo@105: /** ingo@256: * Returns a specific data object of the state. ingo@256: * ingo@256: * @param name The name of the data object. ingo@256: * ingo@256: * @return a data object of the state or null if no such data object exists. ingo@256: */ ingo@256: public StateData getData(String name) { ingo@256: return data.get(name); ingo@256: } ingo@256: ingo@256: ingo@256: /** ingo@105: * Add new data to the state. NOTE: If there is already an object existing ingo@105: * with the key name, this object is overwritten by the new value. ingo@105: * ingo@105: * @param name The name of the data object. ingo@105: * @param StateData The data object. ingo@105: */ ingo@105: public void addData(String name, StateData data) { ingo@105: if (this.data == null) { ingo@105: this.data = new HashMap(); ingo@105: } ingo@105: ingo@105: this.data.put(name, data); ingo@105: } ingo@105: ingo@105: ingo@105: /** ingo@209: * Returns the list of possible outputs of this state. The list is empty ingo@209: * if no output is available for this state. ingo@209: * ingo@209: * @return a list of possible outputs of this state. ingo@209: */ ingo@209: public List getOutputs() { ingo@209: return outputs; ingo@209: } ingo@209: ingo@209: ingo@209: /** ingo@106: * Initialize the state based on the state node in the configuration. ingo@105: * ingo@105: * @param config The state configuration node. ingo@105: */ ingo@106: public void setup(Node config) { ingo@226: logger.info("AbstractState.setup"); ingo@226: ingo@106: id = (String) XMLUtils.xpath(config, XPATH_ID, XPathConstants.STRING); ingo@106: ingo@106: description = (String) XMLUtils.xpath( ingo@106: config, XPATH_DESCRIPTION, XPathConstants.STRING); ingo@209: ingo@209: setupOutputs(config); ingo@209: } ingo@209: ingo@209: ingo@209: /** ingo@363: * This default implementation does nothing at all. ingo@365: * ingo@365: * @param orig ingo@365: * @param owner ingo@365: * @param context ingo@365: * @param callMeta ingo@363: */ ingo@365: public void initialize( ingo@365: Artifact orig, ingo@365: Artifact owner, ingo@365: Object context, ingo@365: CallMeta callMeta ingo@365: ) { ingo@363: // do nothing. ingo@363: } ingo@363: ingo@363: ingo@363: /** ingo@209: * This method tries reading the available output nodes configured in the ingo@209: * state configuration and adds possible Outputs to the outputs list. ingo@209: * ingo@209: * @param config The state configuration node. ingo@209: */ ingo@209: protected void setupOutputs(Node config) { ingo@209: NodeList outs = (NodeList) XMLUtils.xpath( ingo@209: config, ingo@209: XPATH_OUTPUT_MODES, ingo@209: XPathConstants.NODESET, ingo@209: ArtifactNamespaceContext.INSTANCE); ingo@209: ingo@209: if (outs == null || outs.getLength() == 0) { ingo@209: return; ingo@209: } ingo@209: ingo@209: int size = outs.getLength(); ingo@209: ingo@209: for (int i = 0; i < size; i++) { ingo@209: outputs.add(buildOutput(outs.item(i))); ingo@209: } ingo@209: } ingo@209: ingo@209: ingo@209: /** ingo@209: * A helper method that creates an Output object based on the out ingo@209: * node. ingo@209: * ingo@209: * @param out The output node configuration. ingo@209: * ingo@209: * @return an Output object. ingo@209: */ ingo@209: protected Output buildOutput(Node out) { ingo@209: String name = XMLUtils.xpathString( ingo@209: out, "@name", ArtifactNamespaceContext.INSTANCE); ingo@209: ingo@209: String desc = XMLUtils.xpathString( ingo@209: out, "@description", ArtifactNamespaceContext.INSTANCE); ingo@209: ingo@209: String mimetype = XMLUtils.xpathString( ingo@209: out, "@mime-type", ArtifactNamespaceContext.INSTANCE); ingo@209: ingo@290: String type = XMLUtils.xpathString( ingo@290: out, "@type", ArtifactNamespaceContext.INSTANCE); ingo@290: ingo@226: if (name == null) { ingo@226: return null; ingo@226: } ingo@226: ingo@226: NodeList facets = (NodeList) XMLUtils.xpath( ingo@226: out, ingo@226: XPATH_FACETS, ingo@226: XPathConstants.NODESET, ingo@226: ArtifactNamespaceContext.INSTANCE); ingo@226: ingo@226: if (facets == null || facets.getLength() == 0) { ingo@290: return new DefaultOutput(name, desc, mimetype, type); ingo@226: } ingo@226: ingo@226: int num = facets.getLength(); ingo@226: ingo@226: List facetList = new ArrayList(num); ingo@226: ingo@226: for (int i = 0; i < num; i++) { ingo@226: Facet facet = buildFacet(facets.item(i)); ingo@226: ingo@226: if (facet != null) { ingo@226: facetList.add(facet); ingo@226: } ingo@226: } ingo@226: ingo@290: return new DefaultOutput(name, desc, mimetype, facetList, type); ingo@226: } ingo@226: ingo@226: ingo@226: /** ingo@226: * A helper method that creates a Facet object based on the facet ingo@226: * node. ingo@226: * ingo@226: * @param facet The facet node. ingo@226: * ingo@226: * @return a Facet object or null if no valid Facet was found. ingo@226: */ ingo@226: protected Facet buildFacet(Node facet) { ingo@226: String name = XMLUtils.xpathString( ingo@226: facet, "@name", ArtifactNamespaceContext.INSTANCE); ingo@226: ingo@226: String desc = XMLUtils.xpathString( ingo@226: facet, "@description", ArtifactNamespaceContext.INSTANCE); ingo@226: ingo@226: return name != null ? new DefaultFacet(name, desc) : null; ingo@106: } ingo@105: ingo@105: ingo@105: /** ingo@105: * Describes the UI of the state. This method needs to be implemented by ingo@105: * concrete subclasses. ingo@105: * ingo@244: * @param artifact A reference to the artifact this state belongs to. ingo@105: * @param document Describe doucment. ingo@105: * @param rootNode Parent node for all new elements. ingo@105: * @param context The CallContext. ingo@105: * @param uuid The uuid of an artifact. ingo@105: */ ingo@205: public abstract Element describe( ingo@244: Artifact artifact, ingo@105: Document document, ingo@105: Node rootNode, ingo@105: CallContext context, ingo@105: String uuid ingo@105: ); ingo@327: ingo@327: ingo@327: @Override ingo@327: public void endOfLife(Artifact artifact, Object context) { ingo@327: // nothing to do here ingo@327: } ingo@105: } ingo@105: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :