view flys-client/src/main/java/de/intevation/flys/client/server/ArtifactDescriptionFactory.java @ 803:653ae84533e7

Read/create recommended Artifacts and add them to the current Collection. flys-client/trunk@2350 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author Ingo Weinzierl <ingo.weinzierl@intevation.de>
date Mon, 18 Jul 2011 09:52:16 +0000
parents a078ba1c139d
children 6f65e70fa11d
line wrap: on
line source
package de.intevation.flys.client.server;

import java.util.ArrayList;
import java.util.List;

import javax.xml.xpath.XPathConstants;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import de.intevation.artifacts.common.ArtifactNamespaceContext;
import de.intevation.artifacts.common.utils.ClientProtocolUtils;
import de.intevation.artifacts.common.utils.XMLUtils;

import de.intevation.flys.client.shared.model.ArtifactDescription;
import de.intevation.flys.client.shared.model.DataItem;
import de.intevation.flys.client.shared.model.DataList;
import de.intevation.flys.client.shared.model.DefaultArtifactDescription;
import de.intevation.flys.client.shared.model.DefaultData;
import de.intevation.flys.client.shared.model.DefaultDataItem;
import de.intevation.flys.client.shared.model.DefaultOutputMode;
import de.intevation.flys.client.shared.model.OutputMode;
import de.intevation.flys.client.shared.model.WQDataItem;


/**
 * This factory class helps creating an {@link ArtifactDescription} based on the
 * DESCRIBE document of an artifact returned by the artifact server. Use the
 * {@link createArtifactDescription(org.w3c.dom.Document)} method with the
 * DESCRIBE document to create such an {@link ArtifactDescription}.
 *
 * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
 */
public class ArtifactDescriptionFactory {

    public static final String XPATH_STATE_NAME = "@art:name";

    public static final String XPATH_UIPROVIDER = "@art:uiprovider";

    public static final String XPATH_REACHABLE_STATE = "art:state";

    public static final String XPATH_STATIC_STATE_NODE = "art:state";

    public static final String XPATH_STATIC_DATA_NODE = "art:data";

    public static final String XPATH_STATIC_ITEM_NODE = "art:item";

    public static final String XPATH_RECOMMENDED_ARTIFACTS =
        "/art:result/art:recommended-artifacts/art:artifact-factory";

    /**
     * This method creates the {@link ArtifactDescription} of the DESCRIBE
     * document <i>doc</i>.
     *
     * @param doc A DESCRIBE document.
     *
     * @return the {@link ArtifactDescription}.
     */
    public static ArtifactDescription createArtifactDescription(Document doc) {
        System.out.println("ArtifactDescriptionFactory - create()");

        Node currentState = ClientProtocolUtils.getCurrentState(doc);
        Node staticNode   = ClientProtocolUtils.getStaticUI(doc);
        Node dynamicNode  = ClientProtocolUtils.getDynamicUI(doc);
        Node reachable    = ClientProtocolUtils.getReachableStates(doc);
        NodeList outputs  = ClientProtocolUtils.getOutputModes(doc);

        String state = (String) XMLUtils.xpath(
            currentState,
            XPATH_STATE_NAME,
            XPathConstants.STRING,
            ArtifactNamespaceContext.INSTANCE);
        System.out.println("Current state name: " + state);

        DataList currentData = extractCurrentData(dynamicNode, state);
        DataList[] old       = extractOldData(staticNode);
        String[] states      = extractReachableStates(reachable);
        OutputMode[] outs    = extractOutputModes(outputs);
        String[] recommended = extractRecommendedArtifacts(doc);

        return new DefaultArtifactDescription(
            old,
            currentData,
            state,
            states,
            outs,
            recommended);
    }


    /**
     * This method extracts the data that the user is able to enter in the
     * current state of the artifact.
     *
     * @param dynamicNode The dynamic node of the DESCRIBE document.
     * @param state The name of the current state.
     *
     * @return A {@link Data} object that represents the data which might be
     * entered by the user in the current state or null, if no data might be
     * entered.
     */
    protected static DataList extractCurrentData(Node dynamicNode, String state) {
        System.out.println("ArtifactDescriptionFactory - extractCurrentData()");

        NodeList data     = ClientProtocolUtils.getSelectNode(dynamicNode);
        String uiProvider = extractUIProvider(dynamicNode);

        if (data == null || data.getLength() == 0) {
            return null;
        }

        int dataNum   = data.getLength();
        DataList list = new DataList(state, dataNum, uiProvider);

        for (int i = 0; i < dataNum; i++) {
            Node d = data.item(i);

            NodeList choices  = ClientProtocolUtils.getItemNodes(d);
            String   label    = ClientProtocolUtils.getLabel(d);
            String   name     = XMLUtils.xpathString(
                d, "@art:name", ArtifactNamespaceContext.INSTANCE);

            DataItem[] dataItems = extractCurrentDataItems(choices);
            DataItem   def       = extractDefaultDataItem(d);

            list.add(new DefaultData(name, label, null, dataItems, def));
        }

        return list;
    }


    /**
     * This method extracts the default value of a Data object.
     *
     * @param data The data object node.
     *
     * @return the default DataItem.
     */
    protected static DataItem extractDefaultDataItem(Node data) {
        System.out.println(
            "ArtifactDescriptionFactory - extractSelectedDataItem");

        String value = XMLUtils.xpathString(
            data, "@art:defaultValue", ArtifactNamespaceContext.INSTANCE);

        String label = XMLUtils.xpathString(
            data, "@art:defaultLabel", ArtifactNamespaceContext.INSTANCE);

        if (value != null && label != null) {
            return new DefaultDataItem(label, null, value);
        }

        return null;
    }


    /**
     * This method extract the {@link DataItem}s of the DESCRIBE document.
     *
     * @param items The items in the DESCRIBE document.
     *
     * @return the {@link DataItem}s.
     */
    protected static DataItem[] extractCurrentDataItems(NodeList items) {
        System.out.println(
            "ArtifactDescriptionFactory - extractCurrentDataItems()");

        if (items == null || items.getLength() == 0) {
            System.out.println("No data items found.");
            return null;
        }

        int count = items.getLength();

        List<DataItem> dataItems = new ArrayList<DataItem>(count);

        for (int i = 0; i < count; i++) {
            Node item    = items.item(i);
            String label = ClientProtocolUtils.getLabel(item);
            String value = ClientProtocolUtils.getValue(item);

            double[] mmQ = extractMinMaxQValues(item);
            double[] mmW = extractMinMaxWValues(item);

            if (mmQ != null || mmW != null) {
                dataItems.add(new WQDataItem(label, null, value, mmQ, mmW));
            }
            else {
                dataItems.add(new DefaultDataItem(label, null, value));
            }
        }

        return (DataItem[]) dataItems.toArray(new DataItem[count]);
    }


    protected static double[] extractMinMaxQValues(Node item) {
        System.out.println("ArtifactDescriptionFactory - extractMinMaxQValues");

        if (item == null) {
            System.err.println("This node is empty - no min/max Q values.");
            return null;
        }

        Node node = (Node) XMLUtils.xpath(
            item,
            "art:range[@art:type='Q']",
            XPathConstants.NODE,
            ArtifactNamespaceContext.INSTANCE);

        if (node == null) {
            System.out.println("No min/max Q values found.");
            return null;
        }

        return extractMinMaxValues(node);
    }


    protected static double[] extractMinMaxWValues(Node item) {
        System.out.println("ArtifactDescriptionFactory - extractMinMaxWValues");

        if (item == null) {
            System.err.println("This node is empty - no min/max W values.");
            return null;
        }

        Node node = (Node) XMLUtils.xpath(
            item,
            "art:range[@art:type='W']",
            XPathConstants.NODE,
            ArtifactNamespaceContext.INSTANCE);

        if (node == null) {
            System.out.println("No min/max W values found.");
            return null;
        }

        return extractMinMaxValues(node);
    }


    protected static double[] extractMinMaxValues(Node node) {
        System.out.println("ArtifactDescriptionFactory.extractMinMaxValues");

        String minStr = XMLUtils.xpathString(
            node, "art:min/text()", ArtifactNamespaceContext.INSTANCE);

        String maxStr = XMLUtils.xpathString(
            node, "art:max/text()", ArtifactNamespaceContext.INSTANCE);

        if (maxStr == null || minStr == null) {
            System.err.println("No min/max values found.");
            return null;
        }

        try {
            double min = Double.valueOf(minStr);
            double max = Double.valueOf(maxStr);

            return new double[] { min, max };
        }
        catch (NumberFormatException nfe) {
            System.err.println("Error while parsing min/max values.");
        }

        return null;
    }


    /**
     * This method extracts the data objects from the data node of the static ui
     * part of the DESCRIBE document.
     *
     * @param staticNode The static ui node of the DESCRIBE.
     *
     * @return the DataList objects.
     */
    protected static DataList[] extractOldData(Node staticNode) {
        System.out.println("ArtifactDescriptionFactory - extractOldData()");

        NodeList stateNodes = (NodeList) XMLUtils.xpath(
            staticNode,
            XPATH_STATIC_STATE_NODE,
            XPathConstants.NODESET,
            ArtifactNamespaceContext.INSTANCE);

        if (stateNodes == null || stateNodes.getLength() == 0) {
            System.out.println("No old items found.");
            return null;
        }

        int count       = stateNodes.getLength();
        DataList[] data = new DataList[count];

        for (int i = 0; i < count; i++) {
            Node tmp = stateNodes.item(i);

            String name = XMLUtils.xpathString(
                tmp, "@art:name", ArtifactNamespaceContext.INSTANCE);
            String uiprovider = XMLUtils.xpathString(
                tmp, "@art:uiprovider", ArtifactNamespaceContext.INSTANCE);
            String label = XMLUtils.xpathString(
                tmp, "@art:label", ArtifactNamespaceContext.INSTANCE);

            NodeList dataNodes = (NodeList) XMLUtils.xpath(
                tmp,
                XPATH_STATIC_DATA_NODE,
                XPathConstants.NODESET,
                ArtifactNamespaceContext.INSTANCE);

            if (dataNodes == null || dataNodes.getLength() == 0) {
                continue;
            }

            int size      = dataNodes.getLength();
            DataList list = new DataList(name, size, uiprovider, label);

            for (int j = 0; j < size; j++) {
                Node dataNode = dataNodes.item(j);

                String dName = XMLUtils.xpathString(
                    dataNode, "@art:name", ArtifactNamespaceContext.INSTANCE);
                String dType = XMLUtils.xpathString(
                    dataNode, "@art:type", ArtifactNamespaceContext.INSTANCE);

                DataItem[] items = extractOldDataItems(dataNode);

                list.add(new DefaultData(dName, dName, dType, items));

                data[i] = list;
            }
        }

        return data;
    }


    /**
     * This method extracts the data items from the data nodes that are placed
     * in the static ui part of the DESCRIBE document.
     *
     * @param dataNode A data node that contains items.
     *
     * @return a list of DataItems.
     */
    protected static DataItem[] extractOldDataItems(Node dataNode) {
        NodeList itemList = (NodeList) XMLUtils.xpath(
            dataNode,
            XPATH_STATIC_ITEM_NODE,
            XPathConstants.NODESET,
            ArtifactNamespaceContext.INSTANCE);

        if (itemList == null || itemList.getLength() == 0) {
            System.out.println("No old data items found.");
            return null;
        }

        int count = itemList.getLength();

        DataItem[] items = new DataItem[count];

        for (int i = 0; i < count; i++) {
            Node tmp = itemList.item(i);

            String value = XMLUtils.xpathString(
                tmp, "@art:value", ArtifactNamespaceContext.INSTANCE);
            String label = XMLUtils.xpathString(
                tmp, "@art:label", ArtifactNamespaceContext.INSTANCE);

            items[i] = new DefaultDataItem(label, label, value);
        }

        return items;
    }


    /**
     * This method extracts the UIProvider specified by the data node.
     *
     * @param data The data node.
     *
     * @return the UIProvider that is specified in the data node.
     */
    protected static String extractUIProvider(Node ui) {
        return (String) XMLUtils.xpath(
            ui,
            XPATH_UIPROVIDER,
            XPathConstants.STRING,
            ArtifactNamespaceContext.INSTANCE);
    }


    /**
     * This method extracts the reachable states of the current artifact.
     *
     * @param reachable The reachable states node.
     *
     * @return an array with identifiers of reachable states.
     */
    protected static String[] extractReachableStates(Node reachable) {
        System.out.println("ArtifactDescriptionFactory - extractReachableStates()");

        NodeList list = (NodeList) XMLUtils.xpath(
            reachable,
            XPATH_REACHABLE_STATE,
            XPathConstants.NODESET,
            ArtifactNamespaceContext.INSTANCE);

        if (list == null || list.getLength() == 0) {
            return null;
        }

        int count = list.getLength();

        String[] states = new String[count];

        for (int i = 0; i < count; i++) {
            Node state = list.item(i);

            String name = XMLUtils.xpathString(
                state, "@art:name", ArtifactNamespaceContext.INSTANCE);

            states[i] = name;
        }

        return states;
    }


    /**
     * This method extract available output modes of the the current artifact.
     *
     * @param outputs A list of nodes that contain information about output
     * modes.
     *
     * @return an array of Output modes.
     */
    protected static OutputMode[] extractOutputModes(NodeList outputs) {
        System.out.println("ArtifactDescriptionFactory - extractOutputModes()");

        if (outputs == null || outputs.getLength() == 0) {
            return null;
        }

        int size = outputs.getLength();

        List<OutputMode> outs = new ArrayList<OutputMode>(size);

        for (int i = 0; i < size; i++) {
            Node out = outputs.item(i);

            String name = XMLUtils.xpathString(
                out, "@art:name", ArtifactNamespaceContext.INSTANCE);
            String desc = XMLUtils.xpathString(
                out, "@art:description", ArtifactNamespaceContext.INSTANCE);
            String mimeType = XMLUtils.xpathString(
                out, "@art:mime-type", ArtifactNamespaceContext.INSTANCE);

            if (name != null) {
                outs.add(new DefaultOutputMode(name, desc, mimeType));
            }
            else {
                System.err.println("Found an invalid output mode.");
            }
        }

        return (OutputMode[]) outs.toArray(new OutputMode[size]);
    }


    protected static String[] extractRecommendedArtifacts(Document doc) {
        System.out.println("ArtifactDescriptionFactory - extract recommended.");

        NodeList list = (NodeList) XMLUtils.xpath(
            doc,
            XPATH_RECOMMENDED_ARTIFACTS,
            XPathConstants.NODESET,
            ArtifactNamespaceContext.INSTANCE);

        int num = list != null ? list.getLength() : 0;

        String[] factories = new String[num];

        for (int i = 0; i < num; i++) {
            Element e = (Element) list.item(i);
            String  f = e.getAttribute("name");

            if (f != null && f.length() > 0) {
                factories[i] = f;
            }
        }

        return factories;
    }
}
// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :

http://dive4elements.wald.intevation.org