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@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:  * <code>describe()</code> and <code>setup()</code> 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: 
ingo@209:     /** 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
ingo@226:      * to.*/
ingo@226:     public static final String XPATH_FACETS = "facets/facet";
ingo@226: 
ingo@226: 
ingo@226:     /** 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<String, StateData> data;
ingo@105: 
ingo@209:     /** A list of output modes which are available for this state.*/
ingo@209:     protected List<Output> outputs;
ingo@209: 
ingo@105: 
ingo@205:     public AbstractState() {
ingo@209:         outputs = new ArrayList<Output>();
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@209: 
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<String, StateData> 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 <i>name</i>, 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<String, StateData>();
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<Output> 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@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 <i>out</i>
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<Facet> facetList = new ArrayList<Facet>(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 <i>facet</i>
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 :