org.kalypso.observation.result.TupleResultUtilities.java Source code

Java tutorial

Introduction

Here is the source code for org.kalypso.observation.result.TupleResultUtilities.java

Source

/*----------------    FILE HEADER KALYPSO ------------------------------------------
 *
 *  This file is part of kalypso.
 *  Copyright (C) 2004 by:
 *
 *  Technical University Hamburg-Harburg (TUHH)
 *  Institute of River and coastal engineering
 *  Denickestrae 22
 *  21073 Hamburg, Germany
 *  http://www.tuhh.de/wb
 *
 *  and
 *
 *  Bjoernsen Consulting Engineers (BCE)
 *  Maria Trost 3
 *  56070 Koblenz, Germany
 *  http://www.bjoernsen.de
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 *  Contact:
 *
 *  E-Mail:
 *  belger@bjoernsen.de
 *  schlienger@bjoernsen.de
 *  v.doemming@tuhh.de
 *
 *  ---------------------------------------------------------------------------*/
package org.kalypso.observation.result;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;

import javax.xml.namespace.QName;

import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.kalypso.commons.math.LinearEquation;
import org.kalypso.commons.math.LinearEquation.SameXValuesException;
import org.kalypso.commons.xml.XmlTypes;
import org.kalypso.core.i18n.Messages;
import org.kalypso.observation.IObservation;
import org.kalypso.observation.phenomenon.IPhenomenon;

/**
 * TODO: Merge most of the stuff with {@link ComponentUtilities}.
 *
 * @author Gernot Belger
 */
public class TupleResultUtilities {
    private TupleResultUtilities() {
        // helper class, do not instantiate
    }

    /**
     * Get component by name.
     *
     * @return null, if no component with the given name was found.
     */
    public static IComponent findComponentByName(final TupleResult result, final String name) {
        final IComponent[] components = result.getComponents();
        for (final IComponent comp : components) {
            if (comp.getName().equals(name)) {
                return comp;
            }
        }

        return null;
    }

    /**
     * Find component by id.
     *
     * @return The first component with the given id, null, none was found.
     */
    public static IComponent findComponentById(final IObservation<TupleResult> observation, final String id) {
        return findComponentById(observation.getResult(), id);
    }

    /**
     * Find component by id.
     *
     * @return The first component with the given id, null, none was found.
     */
    public static IComponent findComponentById(final TupleResult result, final String id) {
        final IComponent[] components = result.getComponents();
        return findComponentById(components, id);
    }

    public static IComponent findComponentById(final IComponent[] components, final String id) {
        for (final IComponent comp : components) {
            if (comp.getId().equals(id)) {
                return comp;
            }
        }

        return null;
    }

    /**
     * @author thuel2
     * @return returns minimum value for component of a tupleResult.<br>
     *         Works for components of XmlType XS_BOOLEAN, XS_DOUBLE, XS_DATE, XS_STRING. <br>
     *         For all others <code>object.toString</code> will be used for comparison.
     */
    public static Object findComponentMinById(final TupleResult result, final String compID) {
        final IComponent comp = TupleResultUtilities.findComponentById(result, compID);
        if (comp == null) {
            return null;
        }
        final int iComp = result.indexOfComponent(comp);
        final QName valueTypeName = comp.getValueTypeName();

        if (XmlTypes.XS_BOOLEAN.equals(valueTypeName)) {
            final List<Boolean> values = new ArrayList<>();
            for (final IRecord record : result) {
                values.add((Boolean) record.getValue(iComp));
            }
            if (values.size() < 1) {
                return null;
            }
            return Collections.min(values);
        } else if (XmlTypes.XS_DOUBLE.equals(valueTypeName)) {
            // TODO think about other numerical types:
            // XmlTypes.XS_BYTE, XmlTypes.XS_DECIMAL, XmlTypes.XS_FLOAT, XmlTypes.XS_INT, XmlTypes.XS_INTEGER,
            // XmlTypes.XS_LONG, XmlTypes.XS_SHORT
            final List<java.lang.Double> values = new ArrayList<>();
            for (final IRecord record : result) {
                values.add((java.lang.Double) record.getValue(iComp));
            }
            if (values.size() < 1) {
                return null;
            }
            return Collections.min(values);
        } else if (XmlTypes.XS_DATE.equals(valueTypeName)) {
            // TODO think about other date types
            // XmlTypes.XS_DATETIME, XmlTypes.XS_DURATION, XmlTypes.XS_TIME
            final List<Date> values = new ArrayList<>();
            for (final IRecord record : result) {
                values.add((Date) record.getValue(iComp));
            }
            if (values.size() < 1) {
                return null;
            }
            return Collections.min(values);
        } else if (XmlTypes.XS_STRING.equals(valueTypeName)) {
            final List<String> values = new ArrayList<>();
            for (final IRecord record : result) {
                values.add((String) record.getValue(iComp));
            }
            if (values.size() < 1) {
                return null;
            }
            return Collections.min(values);
        } else {
            final List<String> values = new ArrayList<>();
            for (final IRecord record : result) {
                values.add(record.getValue(iComp).toString());
            }
            if (values.size() < 1) {
                return null;
            }
            return Collections.min(values);
        }
    }

    /**
     * @author thuel2
     * @return returns maximum value for component of a tupleResult. <br>
     *         Works for components of XmlType XS_BOOLEAN, XS_DOUBLE, XS_DATE, XS_STRING. <br>
     *         For all others <code>object.toString()</code> will be used for comparison.
     */
    public static Object findComponentMaxById(final TupleResult result, final String compID) {
        final IComponent comp = TupleResultUtilities.findComponentById(result, compID);
        if (comp == null) {
            return null;
        }
        final QName valueTypeName = comp.getValueTypeName();
        final int iComp = result.indexOfComponent(comp);

        if (XmlTypes.XS_BOOLEAN.equals(valueTypeName)) {
            final List<Boolean> values = new ArrayList<>();
            for (final IRecord record : result) {
                values.add((Boolean) record.getValue(iComp));
            }
            if (values.size() < 1) {
                return null;
            }
            return Collections.max(values);
        } else if (XmlTypes.XS_DOUBLE.equals(valueTypeName)) {
            // TODO think about other numerical types:
            // XmlTypes.XS_BYTE, XmlTypes.XS_DECIMAL, XmlTypes.XS_FLOAT, XmlTypes.XS_INT, XmlTypes.XS_INTEGER,
            // XmlTypes.XS_LONG, XmlTypes.XS_SHORT
            final List<java.lang.Double> values = new ArrayList<>();
            for (final IRecord record : result) {
                values.add((java.lang.Double) record.getValue(iComp));
            }
            if (values.size() < 1) {
                return null;
            }
            return Collections.max(values);
        } else if (XmlTypes.XS_DATE.equals(valueTypeName)) {
            // TODO think about other date types
            // XmlTypes.XS_DATETIME, XmlTypes.XS_DURATION, XmlTypes.XS_TIME
            final List<Date> values = new ArrayList<>();
            for (final IRecord record : result) {
                values.add((Date) record.getValue(iComp));
            }
            if (values.size() < 1) {
                return null;
            }
            return Collections.max(values);
        } else if (XmlTypes.XS_STRING.equals(valueTypeName)) {
            final List<String> values = new ArrayList<>();
            for (final IRecord record : result) {
                values.add((String) record.getValue(iComp));
            }
            if (values.size() < 1) {
                return null;
            }
            return Collections.max(values);
        } else {
            final List<String> values = new ArrayList<>();
            for (final IRecord record : result) {
                values.add(record.getValue(iComp).toString());
            }
            if (values.size() < 1) {
                return null;
            }
            return Collections.max(values);
        }
    }

    /**
     * Copies records from one {@link TupleResult} to another.
     *
     * @param componentMap
     *          Map of component ids.
     * @throws IllegalArgumentException
     *           If for an id from the map no component is found.
     */
    public static void copyValues(final TupleResult sourceResult, final TupleResult targetResult,
            final Map<String, String> componentMap) {
        /* Find Components */
        final IComponent[] sourceComponents = new IComponent[componentMap.size()];
        final IComponent[] targetComponents = new IComponent[componentMap.size()];

        int count = 0;
        for (final Map.Entry<String, String> entry : componentMap.entrySet()) {
            final String sourceID = entry.getKey();
            final String targetID = entry.getValue();

            final IComponent sourceComponent = ComponentUtilities.findComponentByID(sourceResult.getComponents(),
                    sourceID);
            if (sourceComponent == null)
                throw new IllegalArgumentException(
                        Messages.getString("org.kalypso.observation.result.TupleResultUtilities.0") + sourceID); //$NON-NLS-1$

            final IComponent targetComponent = ComponentUtilities.findComponentByID(targetResult.getComponents(),
                    targetID);
            if (targetComponent == null)
                throw new IllegalArgumentException(
                        Messages.getString("org.kalypso.observation.result.TupleResultUtilities.1") + targetID); //$NON-NLS-1$

            sourceComponents[count] = sourceComponent;
            targetComponents[count] = targetComponent;
            count++;
        }

        /* Copy values */
        for (final IRecord sourceRecord : sourceResult) {
            final IRecord targetRecord = targetResult.createRecord();

            for (int i = 0; i < sourceComponents.length; i++) {
                final Object value = sourceRecord.getValue(sourceResult.indexOfComponent(sourceComponents[i]));
                targetRecord.setValue(targetResult.indexOfComponent(targetComponents[i]), value);
            }

            targetResult.add(targetRecord);
        }
    }

    /**
     * Returns the index of the first component with a given id.
     *
     * @return -1, if no such component exists.
     */
    public static int indexOfComponent(final IObservation<TupleResult> observation, final String id) {
        return indexOfComponent(observation.getResult(), id);
    }

    /**
     * Returns the index of the first component with a given id.
     *
     * @return -1, if no such component exists.
     */
    public static int indexOfComponent(final TupleResult result, final String id) {
        final IComponent[] components = result.getComponents();
        for (int i = 0; i < components.length; i++) {
            final IComponent component = components[i];
            if (component.getId().equals(id))
                return i;
        }

        return -1;
    }

    /** Extracts a numerical column of values from an observation. */
    public static Number[] getValuesAsNumbers(final IObservation<TupleResult> observation, final int componentIndex)
            throws ClassCastException {
        final TupleResult result = observation.getResult();
        final Collection<Number> values = new ArrayList<>(result.size());

        for (final IRecord record : result) {
            final Number value = (Number) record.getValue(componentIndex);
            values.add(value);
        }

        return values.toArray(new Number[values.size()]);
    }

    public static double[] getInterpolatedValues(final IObservation<TupleResult> observation, final int valueIndex,
            final int interpolateIndex) {
        final Number[] domainValues = getValuesAsNumbers(observation, interpolateIndex);
        final Number[] rangeValues = getValuesAsNumbers(observation, valueIndex);
        final double[] interpolatedValues = new double[rangeValues.length];

        int lastIndexNonNull = -1;

        for (int i = 0; i < rangeValues.length; i++) {
            final Number currentValue = rangeValues[i];
            if (currentValue == null)
                interpolatedValues[i] = Double.NaN;
            else {
                interpolatedValues[i] = currentValue.doubleValue();

                final Number domain = domainValues[i];
                if (domain != null) {
                    if (lastIndexNonNull != -1 && lastIndexNonNull != i - 1) {
                        final double startDomain = domainValues[lastIndexNonNull].doubleValue();
                        final double startValue = rangeValues[lastIndexNonNull].doubleValue();
                        final double endDomain = domainValues[i].doubleValue();
                        final double endValue = rangeValues[i].doubleValue();
                        try {
                            final LinearEquation linearEquation = new LinearEquation(startDomain, startValue,
                                    endDomain, endValue);
                            for (int j = lastIndexNonNull + 1; j < i; j++) {
                                final Number currentDomain = domainValues[j];
                                if (currentDomain != null) {
                                    final double interpolationValue = currentDomain.doubleValue();
                                    interpolatedValues[j] = linearEquation.computeY(interpolationValue);
                                }
                            }
                        } catch (final SameXValuesException e) {
                            // Unable to interpolate between same values, set all to Double.NaN
                            for (int j = lastIndexNonNull + 1; j < i; j++)
                                interpolatedValues[j] = Double.NaN;
                        }
                    }

                    lastIndexNonNull = i;
                }
            }
        }

        return interpolatedValues;
    }

    /**
     * Returns the first (index of a) component, that has the given component id.
     *
     * @reutrn -1, if no such component was found.
     */
    public static int indexOfComponentByPhenomenon(final TupleResult result, final String phenomenonID) {
        final IComponent[] components = result.getComponents();
        for (int i = 0; i < components.length; i++) {
            final IComponent comp = components[i];
            final IPhenomenon phenomenon = comp.getPhenomenon();
            final String phenID = phenomenon.getID();
            if (ObjectUtils.equals(phenomenonID, phenID))
                return i;
        }

        return -1;
    }

    public static void setNumberValue(final IRecord record, final IComponent component, final Number value) {
        final QName qname = component.getValueTypeName();
        if (XmlTypes.XS_DECIMAL.equals(qname))
            record.setValue(component, BigDecimal.valueOf(value.doubleValue()));
        else if (XmlTypes.XS_DOUBLE.equals(qname))
            record.setValue(component, Double.valueOf(value.doubleValue()));
        else if (XmlTypes.XS_FLOAT.equals(qname))
            record.setValue(component, Float.valueOf(value.floatValue()));
        else if (XmlTypes.XS_INT.equals(qname))
            record.setValue(component, Integer.valueOf(value.intValue()));
        else if (XmlTypes.XS_INTEGER.equals(qname))
            record.setValue(component, BigInteger.valueOf(value.longValue()));
        else if (XmlTypes.XS_LONG.equals(qname))
            record.setValue(component, Long.valueOf(value.longValue()));
        else if (XmlTypes.XS_SHORT.equals(qname))
            record.setValue(component, Short.valueOf(value.shortValue()));
        else
            throw new UnsupportedOperationException();

    }

    public static void copyValues(final TupleResult sourceResult, final TupleResult targetResult) {
        final IComponent[] components = sourceResult.getComponents();
        for (final IComponent component : components)
            targetResult.addComponent(component);

        for (int index = 0; index < sourceResult.size(); index++) {
            final IRecord target = targetResult.createRecord();
            final IRecord record = sourceResult.get(index);

            for (int component = 0; component < ArrayUtils.getLength(components); component++)
                target.setValue(component, record.getValue(component));

            targetResult.add(target);
        }
    }

    /**
     * Either gets and existing component, or creates it if it doesn't exist yet.
     *
     * @return The index of the component
     */
    public static int getOrCreateComponent(final TupleResult result, final String componentID) {
        final int index = result.indexOfComponent(componentID);
        if (index != -1)
            return index;

        result.addComponent(ComponentUtilities.getFeatureComponent(componentID));
        return result.indexOfComponent(componentID);
    }
}