view gwt-client/src/main/java/org/dive4elements/river/client/server/DataFactory.java @ 9074:766890addcb2

state To client communication;
author gernotbelger
date Fri, 18 May 2018 17:26:26 +0200
parents 5e38e2924c07
children
line wrap: on
line source
/* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde
 * Software engineering by Intevation GmbH
 *
 * This file is Free Software under the GNU AGPL (>=v3)
 * and comes with ABSOLUTELY NO WARRANTY! Check out the
 * documentation coming with Dive4Elements River for details.
 */

package org.dive4elements.river.client.server;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import javax.xml.xpath.XPathConstants;

import org.apache.log4j.Logger;
import org.dive4elements.artifacts.common.ArtifactNamespaceContext;
import org.dive4elements.artifacts.common.utils.XMLUtils;
import org.dive4elements.river.client.shared.model.Data;
import org.dive4elements.river.client.shared.model.DataItem;
import org.dive4elements.river.client.shared.model.DefaultData;
import org.dive4elements.river.client.shared.model.DefaultDataItem;
import org.dive4elements.river.client.shared.model.DoubleArrayData;
import org.dive4elements.river.client.shared.model.IntDataItem;
import org.dive4elements.river.client.shared.model.IntegerArrayData;
import org.dive4elements.river.client.shared.model.IntegerData;
import org.dive4elements.river.client.shared.model.IntegerOptionsData;
import org.dive4elements.river.client.shared.model.IntegerRangeData;
import org.dive4elements.river.client.shared.model.LongRangeData;
import org.dive4elements.river.client.shared.model.MultiAttributeData;
import org.dive4elements.river.client.shared.model.MultiDataItem;
import org.dive4elements.river.client.shared.model.StringData;
import org.dive4elements.river.client.shared.model.StringOptionsData;
import org.w3c.dom.Attr;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

/**
 * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
 */
public class DataFactory {

    private static final Logger log = Logger.getLogger(DataFactory.class);

    public static final String NS_URI = ArtifactNamespaceContext.NAMESPACE_URI;

    /**
     * Creates a new Data instance based on the <i>art:type</i> attribute of
     * <i>element</i>.
     *
     * @param element
     *            The Data element.
     *
     * @return a Data instance.
     */
    public static Data createDataFromElement(final Element element) {
        final String name = element.getAttributeNS(NS_URI, "name");
        String type = element.getAttributeNS(NS_URI, "type");
        String label = element.getAttributeNS(NS_URI, "label");

        label = label != null && label.length() > 0 ? label : name;

        try {
            log.debug("Create Data instance for: " + name + " | " + type);

            if (type == null || type.length() == 0) {
                return createDefaultData(element, name, label);
            }

            type = type.toLowerCase();

            if (type.equals(StringData.TYPE)) {
                return createStringData(element, name, label);
            } else if (type.equals(IntegerData.TYPE)) {
                return createIntegerData(element, name, label);
            } else if (type.equals(StringOptionsData.TYPE)) {
                return createStringOptionsData(element, name, label);
            } else if (type.equals(IntegerOptionsData.TYPE)) {
                return createIntegerOptionsData(element, name, label);
            } else if (type.equals(IntegerRangeData.TYPE)) {
                return createIntegerRangeData(element, name, label);
            } else if (type.equals(IntegerArrayData.TYPE)) {
                return createIntegerArrayData(element, name, label);
            } else if (type.equals(DoubleArrayData.TYPE)) {
                return createDoubleArrayData(element, name, label);
            } else if (type.equals(LongRangeData.TYPE)) {
                return createLongRangeData(element, name, label);
            } else if (type.equals(MultiAttributeData.TYPE)) {
                return createMultiAttributeData(element, name, label);
            } else {
                return createDefaultData(element, name, label);
            }
        }
        catch (final Exception e) {
            log.error("Error while data creation for: " + name);
        }

        return null;
    }

    public static Data createMultiAttributeData(final Element element, final String name, final String label) {
        return new MultiAttributeData(name, label, extractMultiDataItems(element), extractMeta(element));
    }

    private static Map<String, Map<String, String>> extractMeta(final Element element) {
        final NodeList nl = element.getElementsByTagName("art:meta");
        final int N = nl.getLength();
        if (N != 1) {
            log.debug("No or too much meta data found for multi attribute data");
            return Collections.<String, Map<String, String>>emptyMap();
        }
        final Map<String, Map<String, String>> map = new HashMap<String, Map<String, String>>();

        final Element metaElement = (Element) nl.item(0);
        final NodeList metaChildren = metaElement.getChildNodes();

        for (int i = 0; i < metaChildren.getLength(); ++i) {

            final Node childNode = metaChildren.item(i);
            if (childNode instanceof Element) {

                final Element e = (Element) childNode;
                final NamedNodeMap attrs = e.getAttributes();
                final Map<String, String> kvs = new HashMap<String, String>();
                for (int j = 0, A = attrs.getLength(); j < A; ++j) {
                    final Attr attr = (Attr) attrs.item(j);
                    kvs.put(attr.getName(), attr.getValue());
                }
                map.put(e.getLocalName(), kvs);
            }
        }

        return map;
    }

    protected static DataItem[] extractMultiDataItems(final Element element) {
        final NodeList itemList = (NodeList) XMLUtils.xpath(element, "art:item", XPathConstants.NODESET, ArtifactNamespaceContext.INSTANCE);

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

        final int count = itemList.getLength();

        final MultiDataItem[] items = new MultiDataItem[count];

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

            final HashMap<String, String> data = new HashMap<String, String>();
            final String label = tmp.getAttributeNS(NS_URI, "label");
            final NamedNodeMap attributes = tmp.getAttributes();
            for (int j = 0, L = attributes.getLength(); j < L; j++) {
                final Node n = attributes.item(j);
                if (n.getNodeName().equals("label")) {
                    continue;
                }
                data.put(n.getNodeName(), n.getNodeValue());
            }
            items[i] = new MultiDataItem(label, label, data);
        }
        return items;
    }

    /**
     * This method creates a new instance of DefaultData which has no real type
     * set.
     *
     * @param ele
     *            The Data element.
     * @param name
     *            The name of the Data instance.
     *
     * @return an instance of DefaultData.
     */
    protected static Data createDefaultData(final Element ele, final String name, final String label) {
        log.debug("Create new DefaultData");
        return new DefaultData(name, label, "default", extractDataItems(ele));
    }

    /**
     * This method creates a new instance of StringData which has a type
     * "string" set.
     *
     * @param ele
     *            The Data element.
     * @param name
     *            The name of the Data instance.
     *
     * @return an instance of StringData.
     */
    protected static Data createStringData(final Element ele, final String name, final String label) {
        return new StringData(name, label, extractDataItems(ele));
    }

    /**
     * This method creates a new instance of DefaultData which has a type
     * "integer" set.
     *
     * @param ele
     *            The Data element.
     * @param name
     *            The name of the Data instance.
     *
     * @return an instance of IntegerData.
     */
    protected static Data createIntegerData(final Element ele, final String name, final String label) {
        return new IntegerData(name, label, extractDataItems(ele));
    }

    /**
     * This method creates a new instance of StringOptionsData which has a type
     * "options" set.
     *
     * @param ele
     *            The Data element.
     * @param name
     *            The name of the Data instance.
     *
     * @return an instance of StringOptionsData.
     */
    protected static Data createStringOptionsData(final Element ele, final String name, final String label) {
        return new StringOptionsData(name, label, extractDataItems(ele));
    }

    /**
     * This method creates a new instance of DefaultData which has a type
     * "intoptions" set.
     *
     * @param ele
     *            The Data element.
     * @param name
     *            The name of the Data instance.
     *
     * @return an instance of IntegerOptionsData.
     */
    protected static Data createIntegerOptionsData(final Element ele, final String name, final String label) {
        return new IntegerOptionsData(name, label, extractDataItems(ele));
    }

    /**
     * This method creates a new instance of DefaultData which has a type
     * "intrange" set.
     *
     * @param ele
     *            The Data element.
     * @param name
     *            The name of the Data instance.
     *
     * @return an instance of IntegerRangeData.
     */
    protected static Data createIntegerRangeData(final Element ele, final String name, final String label) {
        final DataItem[] items = extractDataItems(ele);
        final String rawValue = items[0].getStringValue();

        final String[] minmax = rawValue.split(";");

        return new IntegerRangeData(name, label, Integer.valueOf(minmax[0]), Integer.valueOf(minmax[1]));
    }

    /**
     * This method creates a new instance of DefaultData which has a type
     * "integerarray" set.
     *
     * @param ele
     *            The Data element.
     * @param name
     *            The name of the Data instance.
     *
     * @return an instance of IntegerArrayData.
     */
    protected static Data createIntegerArrayData(final Element ele, final String name, final String label) {
        final IntDataItem[] items = extractIntDataItems(ele);
        return new IntegerArrayData(name, label, items);
    }

    /**
     * This method creates a new instance of DefaultData which has a type
     * "doublearray" set.
     *
     * @param ele
     *            The Data element.
     * @param name
     *            The name of the Data instance.
     *
     * @return an instance of DoubleArrayData.
     */
    protected static Data createDoubleArrayData(final Element ele, final String name, final String label) {
        final DataItem[] items = extractDataItems(ele);
        final String rawValue = items[0].getStringValue();

        final String[] values = rawValue.split(";");
        final double[] doubles = new double[values.length];

        for (int i = 0; i < values.length; i++) {
            try {
                doubles[i] = Double.valueOf(values[i]);
            }
            catch (final NumberFormatException nfe) {
                log.warn("Error while parsing DoubleArrayData: " + nfe);
            }
        }

        return new DoubleArrayData(name, label, doubles);
    }

    /**
     * This method extracts the art:item elements placed under <i>elements</i>.
     *
     * @param element
     *            A data node that contains items.
     *
     * @return a list of DataItems.
     */
    protected static DataItem[] extractDataItems(final Element element) {
        final NodeList itemList = (NodeList) XMLUtils.xpath(element, "art:item", XPathConstants.NODESET, ArtifactNamespaceContext.INSTANCE);

        if (itemList == null || itemList.getLength() == 0) {
            log.debug("No data items found.");
            return null;
        }

        final int count = itemList.getLength();

        final DataItem[] items = new DataItem[count];

        log.debug("There are " + count + " data items in element.");

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

            final String value = tmp.getAttributeNS(NS_URI, "value");
            final String label = tmp.getAttributeNS(NS_URI, "label");

            log.debug("Found data item:");
            log.debug("   label: " + label);
            log.debug("   value: " + value);

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

        return items;
    }

    /**
     * This method extracts the art:item elements placed under <i>elements</i>.
     *
     * @param element
     *            A data node that contains items.
     *
     * @return a list of DataItems.
     */
    protected static IntDataItem[] extractIntDataItems(final Element element) {
        final NodeList itemList = (NodeList) XMLUtils.xpath(element, "art:item", XPathConstants.NODESET, ArtifactNamespaceContext.INSTANCE);

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

        final int count = itemList.getLength();

        final IntDataItem[] items = new IntDataItem[count];

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

            final String value = tmp.getAttributeNS(NS_URI, "value");
            final String label = tmp.getAttributeNS(NS_URI, "label");

            try {
                final int data = Integer.parseInt(value);
                items[i] = new IntDataItem(label, label, data);
            }
            catch (final NumberFormatException nfe) {
                log.debug(nfe, nfe);
            }
        }
        return items;
    }

    /**
     * This method creates a new instance of LongRangeData which has a type
     * "longrange" set.
     *
     * @param ele
     *            The Data element.
     * @param name
     *            The name of the Data instance.
     *
     * @return an instance of IntegerRangeData.
     */
    protected static Data createLongRangeData(final Element ele, final String name, final String label) {
        final DataItem[] items = extractDataItems(ele);
        final String rawValue = items[0].getStringValue();

        final String[] minmax = rawValue.split(";");

        return new LongRangeData(name, label, Long.valueOf(minmax[0]), Long.valueOf(minmax[1]));
    }

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

http://dive4elements.wald.intevation.org