All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.n52.svalbard.util.SweHelper Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (C) 2015-2022 52°North Spatial Information Research GmbH
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.n52.svalbard.util;

import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.n52.faroe.ConfigurationError;
import org.n52.faroe.Validation;
import org.n52.faroe.annotation.Configurable;
import org.n52.faroe.annotation.Setting;
import org.n52.shetland.ogc.gml.time.Time;
import org.n52.shetland.ogc.gml.time.TimePeriod;
import org.n52.shetland.ogc.om.AbstractObservationValue;
import org.n52.shetland.ogc.om.MultiObservationValues;
import org.n52.shetland.ogc.om.OmConstants;
import org.n52.shetland.ogc.om.OmObservation;
import org.n52.shetland.ogc.om.SingleObservationValue;
import org.n52.shetland.ogc.om.TimeValuePair;
import org.n52.shetland.ogc.om.values.BooleanValue;
import org.n52.shetland.ogc.om.values.CategoryValue;
import org.n52.shetland.ogc.om.values.ComplexValue;
import org.n52.shetland.ogc.om.values.CountValue;
import org.n52.shetland.ogc.om.values.CvDiscretePointCoverage;
import org.n52.shetland.ogc.om.values.GeometryValue;
import org.n52.shetland.ogc.om.values.HrefAttributeValue;
import org.n52.shetland.ogc.om.values.MultiPointCoverage;
import org.n52.shetland.ogc.om.values.NilTemplateValue;
import org.n52.shetland.ogc.om.values.ProfileValue;
import org.n52.shetland.ogc.om.values.QuantityRangeValue;
import org.n52.shetland.ogc.om.values.QuantityValue;
import org.n52.shetland.ogc.om.values.RectifiedGridCoverage;
import org.n52.shetland.ogc.om.values.ReferenceValue;
import org.n52.shetland.ogc.om.values.SweDataArrayValue;
import org.n52.shetland.ogc.om.values.TLVTValue;
import org.n52.shetland.ogc.om.values.TVPValue;
import org.n52.shetland.ogc.om.values.TextValue;
import org.n52.shetland.ogc.om.values.TimeValue;
import org.n52.shetland.ogc.om.values.TrajectoryValue;
import org.n52.shetland.ogc.om.values.TimeRangeValue;
import org.n52.shetland.ogc.om.values.UnknownValue;
import org.n52.shetland.ogc.om.values.Value;
import org.n52.shetland.ogc.om.values.XmlValue;
import org.n52.shetland.ogc.om.values.visitor.ValueVisitor;
import org.n52.shetland.ogc.swe.CoordinateSettingsProvider;
import org.n52.shetland.ogc.swe.SweAbstractDataComponent;
import org.n52.shetland.ogc.swe.SweDataArray;
import org.n52.shetland.ogc.swe.SweDataRecord;
import org.n52.shetland.ogc.swe.SweField;
import org.n52.shetland.ogc.swe.encoding.SweAbstractEncoding;
import org.n52.shetland.ogc.swe.encoding.SweTextEncoding;
import org.n52.shetland.ogc.swe.simpleType.SweAbstractUomType;
import org.n52.shetland.ogc.swe.simpleType.SweBoolean;
import org.n52.shetland.ogc.swe.simpleType.SweCategory;
import org.n52.shetland.ogc.swe.simpleType.SweCount;
import org.n52.shetland.ogc.swe.simpleType.SweObservableProperty;
import org.n52.shetland.ogc.swe.simpleType.SweQuantity;
import org.n52.shetland.ogc.swe.simpleType.SweText;
import org.n52.shetland.ogc.swe.simpleType.SweTime;
import org.n52.shetland.ogc.swe.simpleType.SweTimeRange;
import org.n52.shetland.util.CollectionHelper;
import org.n52.shetland.util.DateTimeHelper;
import org.n52.shetland.util.JavaHelper;
import org.n52.svalbard.CodingSettings;
import org.n52.svalbard.encode.exception.EncodingException;

import com.google.common.base.Strings;

import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;

/**
 * SWE helper class.
 *
 * @since 1.0.0
 *
 */
@Configurable
public final class SweHelper {

    private final Logger LOGGER = LoggerFactory.getLogger(SweHelper.class);

    private String tokenSeparator;

    private String tupleSeparator;

    private String decimalSeparator;

    private Set northingNames = Collections.emptySet();

    private Set eastingNames = Collections.emptySet();

    private Set altitudeNames = Collections.emptySet();

    @Setting(value = CodingSettings.TOKEN_SEPARATOR, required = false)
    public void setTokenSeparator(final String separator) throws ConfigurationError {
        Validation.notNullOrEmpty("Token separator", separator);
        tokenSeparator = separator;
    }

    @Setting(value = CodingSettings.TUPLE_SEPARATOR, required = false)
    public void setTupleSeparator(final String separator) throws ConfigurationError {
        Validation.notNullOrEmpty("Tuple separator", separator);
        tupleSeparator = separator;
    }

    @Setting(value = CodingSettings.DECIMAL_SEPARATOR, required = false)
    public void setDecimalSeparator(final String separator) throws ConfigurationError {
        Validation.notNullOrEmpty("Decimal separator", separator);
        decimalSeparator = separator;
    }

    /**
     * Create {@link SweDataArray} from {@link OmObservation}
     *
     * @param sosObservation
     *            The {@link OmObservation} to create {@link SweDataArray} from
     *
     * @return Created {@link SweDataArray}
     *
     * @throws EncodingException
     *             If the service does not support the {@link SweDataArray}
     *             creation from value of {@link OmObservation}
     */
    public SweDataArray createSosSweDataArray(OmObservation sosObservation) throws EncodingException {
        String observablePropertyIdentifier =
                sosObservation.getObservationConstellation().getObservableProperty().getIdentifier();
        SweDataArrayValue dataArrayValue = new SweDataArrayValue();
        SweDataArray dataArray = new SweDataArray();
        dataArray.setEncoding(createTextEncoding(sosObservation));
        dataArrayValue.setValue(dataArray);
        if (sosObservation.getValue() instanceof SingleObservationValue) {
            SingleObservationValue singleValue = (SingleObservationValue) sosObservation.getValue();
            if (singleValue.getValue() instanceof SweDataArrayValue) {
                return (SweDataArray) singleValue.getValue().getValue();
            } else {
                dataArray.setElementType(createElementType(singleValue, observablePropertyIdentifier));
                dataArrayValue.addBlock(createBlock(dataArray.getElementType(), sosObservation.getPhenomenonTime(),
                        observablePropertyIdentifier, singleValue.getValue()));
            }
        } else if (sosObservation.getValue() instanceof MultiObservationValues) {
            MultiObservationValues multiValue = (MultiObservationValues) sosObservation.getValue();
            if (multiValue.getValue() instanceof SweDataArrayValue) {
                return ((SweDataArrayValue) multiValue.getValue()).getValue();
            } else if (multiValue.getValue() instanceof TVPValue) {
                TVPValue tvpValues = (TVPValue) multiValue.getValue();
                for (TimeValuePair timeValuePair : tvpValues.getValue()) {
                    if (timeValuePair != null && timeValuePair.getValue() != null
                            && timeValuePair.getValue().isSetValue()) {
                        if (!dataArray.isSetElementTyp()) {
                            dataArray.setElementType(createElementType(timeValuePair, observablePropertyIdentifier));
                        }
                        List newBlock = createBlock(dataArray.getElementType(), timeValuePair.getTime(),
                                observablePropertyIdentifier, timeValuePair.getValue());
                        dataArrayValue.addBlock(newBlock);
                    }
                }
            }
        }
        return dataArray;
    }

    /**
     * Create {@link SweDataArray} from {@link AbstractObservationValue}
     *
     * @param observationValue
     *            The {@link AbstractObservationValue} to create
     *            {@link SweDataArray} from
     *
     * @return Created {@link SweDataArray}
     *
     * @throws EncodingException
     *             If the service does not support the {@link SweDataArray}
     *             creation from {@link AbstractObservationValue}
     */
    public SweDataArray createSosSweDataArray(AbstractObservationValue observationValue) throws EncodingException {
        String observablePropertyIdentifier = observationValue.getObservableProperty();
        SweDataArrayValue dataArrayValue = new SweDataArrayValue();
        SweDataArray dataArray = new SweDataArray();
        dataArray.setEncoding(createTextEncoding(observationValue));
        dataArrayValue.setValue(dataArray);
        if (observationValue instanceof SingleObservationValue) {
            SingleObservationValue singleValue = (SingleObservationValue) observationValue;
            if (singleValue.getValue() instanceof SweDataArrayValue) {
                return (SweDataArray) singleValue.getValue().getValue();
            } else {
                dataArray.setElementType(createElementType(singleValue, observablePropertyIdentifier));
                dataArrayValue.addBlock(createBlock(dataArray.getElementType(), observationValue.getPhenomenonTime(),
                        observablePropertyIdentifier, singleValue.getValue()));
            }
        } else if (observationValue instanceof MultiObservationValues) {
            MultiObservationValues multiValue = (MultiObservationValues) observationValue;
            if (multiValue.getValue() instanceof SweDataArrayValue) {
                return ((SweDataArrayValue) multiValue.getValue()).getValue();
            } else if (multiValue.getValue() instanceof TVPValue) {
                TVPValue tvpValues = (TVPValue) multiValue.getValue();
                for (TimeValuePair timeValuePair : tvpValues.getValue()) {
                    if (timeValuePair != null && timeValuePair.getValue() != null
                            && timeValuePair.getValue().isSetValue()) {
                        if (!dataArray.isSetElementTyp()) {
                            dataArray.setElementType(createElementType(timeValuePair, observablePropertyIdentifier));
                        }
                        List newBlock = createBlock(dataArray.getElementType(), timeValuePair.getTime(),
                                observablePropertyIdentifier, timeValuePair.getValue());
                        dataArrayValue.addBlock(newBlock);
                    }
                }
            }
        }
        return dataArray;
    }

    private SweAbstractDataComponent createElementType(TimeValuePair tvp, String name) throws EncodingException {
        SweDataRecord dataRecord = new SweDataRecord();
        dataRecord.addField(getPhenomenonTimeField(tvp.getTime()));
        dataRecord.addField(getFieldForValue(tvp.getValue(), name));
        return dataRecord;
    }

    private SweAbstractDataComponent createElementType(SingleObservationValue sov, String name)
            throws EncodingException {
        SweDataRecord dataRecord = new SweDataRecord();
        dataRecord.addField(getPhenomenonTimeField(sov.getPhenomenonTime()));
        dataRecord.addField(getFieldForValue(sov.getValue(), name));
        return dataRecord;
    }

    private SweField getPhenomenonTimeField(Time sosTime) {
        SweAbstractUomType time;
        if (sosTime instanceof TimePeriod) {
            time = new SweTimeRange();
        } else {
            time = new SweTime();
        }
        time.setDefinition(OmConstants.PHENOMENON_TIME);
        time.setUom(OmConstants.PHEN_UOM_ISO8601);
        return new SweField(OmConstants.PHENOMENON_TIME_NAME, time);
    }

    private SweField getFieldForValue(Value iValue, String name) throws EncodingException {
        SweAbstractDataComponent value = getValue(iValue);
        value.setDefinition(name);
        return new SweField(name, value);
    }

    private SweAbstractDataComponent getValue(Value iValue) throws EncodingException {

        return iValue.accept(new ValueVisitor() {
            @Override
            public SweAbstractDataComponent visit(BooleanValue value) {
                return new SweBoolean();
            }

            @Override
            public SweAbstractDataComponent visit(CategoryValue value) {
                SweCategory sosSweCategory = new SweCategory();
                sosSweCategory.setCodeSpace(value.getUnit());
                return sosSweCategory;
            }

            @Override
            public SweAbstractDataComponent visit(NilTemplateValue value) {
                return new SweText();
            }

            @Override
            public SweAbstractDataComponent visit(QuantityValue value) {
                SweQuantity sosSweQuantity = new SweQuantity();
                sosSweQuantity.setUom(value.getUnit());
                return sosSweQuantity;
            }

            @Override
            public SweAbstractDataComponent visit(QuantityRangeValue value) throws EncodingException {
                throw notSupported();
            }

            @Override
            public SweAbstractDataComponent visit(TextValue value) {
                return new SweText();
            }

            @Override
            public SweAbstractDataComponent visit(CountValue value) {
                return new SweCount();
            }

            @Override
            public SweAbstractDataComponent visit(ComplexValue value) throws EncodingException {
                throw new EncodingException("The merging of '%s' is not yet supported!",
                        OmConstants.OBS_TYPE_COMPLEX_OBSERVATION);
            }

            @Override
            public SweAbstractDataComponent visit(GeometryValue value) throws EncodingException {
                throw notSupported();
            }

            @Override
            public SweAbstractDataComponent visit(HrefAttributeValue value) throws EncodingException {
                throw notSupported();
            }

            @Override
            public SweAbstractDataComponent visit(ReferenceValue value) throws EncodingException {
                throw notSupported();
            }

            @Override
            public SweAbstractDataComponent visit(SweDataArrayValue value) throws EncodingException {
                return ((SweDataArrayValue) iValue).getValue();
            }

            @Override
            public SweAbstractDataComponent visit(TVPValue value) throws EncodingException {
                throw notSupported();
            }

            @Override
            public SweAbstractDataComponent visit(UnknownValue value) throws EncodingException {
                throw notSupported();
            }

            @Override
            public SweAbstractDataComponent visit(TLVTValue value) throws EncodingException {
                throw notSupported();
            }

            @Override
            public SweAbstractDataComponent visit(CvDiscretePointCoverage value) throws EncodingException {
                throw notSupported();
            }

            @Override
            public SweAbstractDataComponent visit(MultiPointCoverage value) throws EncodingException {
                throw notSupported();
            }

            @Override
            public SweAbstractDataComponent visit(RectifiedGridCoverage value) throws EncodingException {
                throw notSupported();
            }

            @Override
            public SweAbstractDataComponent visit(ProfileValue value) throws EncodingException {
                throw notSupported();
            }

            @Override
            public SweAbstractDataComponent visit(TrajectoryValue value) throws EncodingException {
                throw notSupported();
            }

            @Override
            public SweAbstractDataComponent visit(TimeValue value) throws EncodingException {
                SweTime sweTime = new SweTime();
                sweTime.setUom(value.getUnit());
                return sweTime;
            }

            @Override
            public SweAbstractDataComponent visit(TimeRangeValue value) throws EncodingException {
                SweTimeRange sweTimeRange = new SweTimeRange();
                sweTimeRange.setUom(value.getUnit());
                return sweTimeRange;
            }

            @Override
            public SweAbstractDataComponent visit(XmlValue value) throws EncodingException {
                throw notSupported();
            }

            private EncodingException notSupported() {
                return new EncodingException("The merging of value type '%s' is not yet supported!",
                        iValue.getClass().getName());
            }
        });
    }

    /**
     * Create a TextEncoding object for token and tuple separators from
     * SosObservation. If separators not set, definitions from Configurator are
     * used.
     *
     * @param o
     *            SosObservation with token and tuple separator
     *
     * @return TextEncoding
     */
    public SweAbstractEncoding createTextEncoding(OmObservation o) {
        String tuple = o.isSetTupleSeparator() ? o.getTupleSeparator() : this.tupleSeparator;
        String token = o.isSetTokenSeparator() ? o.getTokenSeparator() : this.tokenSeparator;
        String decimal = o.isSetDecimalSeparator() ? o.getDecimalSeparator() : this.decimalSeparator;
        return createTextEncoding(tuple, token, decimal);
    }

    /**
     * Create a TextEncoding object for token and tuple separators from
     * SosObservation. If separators not set, definitions from Configurator are
     * used.
     *
     * @param v
     *            AbstractObservationValue with token and tuple separator
     *
     * @return TextEncoding
     */
    private SweAbstractEncoding createTextEncoding(AbstractObservationValue v) {
        String tuple = v.isSetTupleSeparator() ? v.getTupleSeparator() : this.tupleSeparator;
        String token = v.isSetTokenSeparator() ? v.getTokenSeparator() : this.tokenSeparator;
        String decimal = v.isSetDecimalSeparator() ? v.getDecimalSeparator() : this.decimalSeparator;
        return createTextEncoding(tuple, token, decimal);
    }

    /**
     * Create a TextEncoding object for token and tuple separators.
     *
     * @param tuple
     *            Token separator
     * @param token
     *            Tuple separator
     * @param decimal
     *            Decimal separator
     *
     * @return TextEncoding
     */
    public SweAbstractEncoding createTextEncoding(String tuple, String token, String decimal) {
        SweTextEncoding sosTextEncoding = new SweTextEncoding();
        sosTextEncoding.setBlockSeparator(tuple);
        sosTextEncoding.setTokenSeparator(token);
        if (!Strings.isNullOrEmpty(decimal)) {
            sosTextEncoding.setDecimalSeparator(decimal);
        }
        return sosTextEncoding;
    }

    public SweAbstractEncoding createDefaultTextEncoding() {
        SweTextEncoding sosTextEncoding = new SweTextEncoding();
        sosTextEncoding.setBlockSeparator(tupleSeparator);
        sosTextEncoding.setTokenSeparator(tokenSeparator);
        if (!Strings.isNullOrEmpty(decimalSeparator)) {
            sosTextEncoding.setDecimalSeparator(decimalSeparator);
        }
        return sosTextEncoding;
    }

    @SuppressFBWarnings("BC_VACUOUS_INSTANCEOF")
    private List createBlock(SweAbstractDataComponent elementType, Time phenomenonTime, String phenID,
            Value value) {
        if (elementType instanceof SweDataRecord) {
            SweDataRecord elementTypeRecord = (SweDataRecord) elementType;
            List block = new ArrayList<>(elementTypeRecord.getFields().size());
            if (!(value instanceof NilTemplateValue)) {
                elementTypeRecord.getFields().forEach(field -> {
                    if (field.getElement() instanceof SweTime || field.getElement() instanceof SweTimeRange) {
                        block.add(DateTimeHelper.format(phenomenonTime));
                    } else if (field.getElement() instanceof SweAbstractDataComponent
                            && field.getElement().getDefinition().equals(phenID)) {
                        block.add(value.getValue().toString());
                    } else if (field.getElement() instanceof SweObservableProperty) {
                        block.add(phenID);
                    }
                });
            }
            return block;
        }
        String exceptionMsg = String.format("Type of ElementType is not supported: %s",
                elementType != null ? elementType.getClass().getName() : "null");
        LOGGER.debug(exceptionMsg);
        throw new IllegalArgumentException(exceptionMsg);
    }

    /**
     * Create a {@link SweQuantity} from parameter
     *
     * @param value
     *            the {@link SweQuantity} value
     * @param axis
     *            the {@link SweQuantity} axis id
     * @param uom
     *            the {@link SweQuantity} unit of measure
     *
     * @return the {@link SweQuantity} from parameter
     */
    public SweQuantity createSweQuantity(Object value, String axis, String uom) {
        return new SweQuantity().setAxisID(axis).setUom(uom).setValue(JavaHelper.asDouble(value));
    }

    /**
     * @return the northingNames
     */
    public Set getNorthingNames() {
        return new LinkedHashSet<>(northingNames);
    }

    /**
     * @param northingNames
     *            the northingNames to set
     */
    @Setting(value = CoordinateSettingsProvider.NORTHING_COORDINATE_NAME, required = false)
    public void setNorthingNames(String northingNames) {
        if (!Strings.isNullOrEmpty(northingNames)) {
            this.northingNames = CollectionHelper.csvStringToSet(northingNames);
        }
    }

    /**
     * Check if northing names contains name
     *
     * @param names
     *            Names to check
     * @return true, if the name is defined.
     */
    public boolean hasNorthingName(String... names) {
        return check(getNorthingNames(), names);
    }

    /**
     * @return the eastingNames
     */
    public Set getEastingNames() {
        return new LinkedHashSet<>(eastingNames);
    }

    /**
     * @param eastingNames
     *            the eastingNames to set
     */
    @Setting(value = CoordinateSettingsProvider.EASTING_COORDINATE_NAME, required = false)
    public void setEastingNames(String eastingNames) {
        if (!Strings.isNullOrEmpty(eastingNames)) {
            this.eastingNames = CollectionHelper.csvStringToSet(eastingNames);
        }
    }

    /**
     * Check if easting names contains name
     *
     * @param names
     *            Names to check
     * @return true, if the name is defined.
     */
    public boolean hasEastingName(String... names) {
        return check(getEastingNames(), names);
    }

    /**
     * @return the altitudeNames
     */
    public Set getAltitudeNames() {
        return new LinkedHashSet<>(altitudeNames);
    }

    /**
     * @param altitudeNames
     *            the altitudeNames to set
     */
    @Setting(value = CoordinateSettingsProvider.ALTITUDE_COORDINATE_NAME, required = false)
    public void setAltitudeNames(String altitudeNames) {
        if (!Strings.isNullOrEmpty(altitudeNames)) {
            this.altitudeNames = CollectionHelper.csvStringToSet(altitudeNames);
        }
    }

    /**
     * Check if altitude names contains name
     *
     * @param names
     *            Names to check
     * @return true, if the name is defined.
     */
    public boolean hasAltitudeName(String... names) {
        return check(getAltitudeNames(), names);
    }

    private boolean check(Set set, String... names) {
        for (String string : set) {
            for (String name : names) {
                if (string.equalsIgnoreCase(name)) {
                    return true;
                }
            }
        }
        return false;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy