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

org.n52.svalbard.write.TsmlTVPEncoderv10XmlStreamWriter 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.write;

import java.io.OutputStream;
import java.util.List;
import java.util.Optional;

import javax.annotation.Nullable;
import javax.xml.stream.XMLStreamException;

import org.apache.commons.lang.StringEscapeUtils;
import org.apache.xmlbeans.XmlObject;
import org.n52.shetland.ogc.gml.CodeType;
import org.n52.shetland.ogc.gml.GmlConstants;
import org.n52.shetland.ogc.gml.ReferenceType;
import org.n52.shetland.ogc.om.MultiObservationValues;
import org.n52.shetland.ogc.om.ObservationValue;
import org.n52.shetland.ogc.om.OmConstants;
import org.n52.shetland.ogc.om.OmObservableProperty;
import org.n52.shetland.ogc.om.OmObservation;
import org.n52.shetland.ogc.om.SingleObservationValue;
import org.n52.shetland.ogc.om.StreamingValue;
import org.n52.shetland.ogc.om.TimeValuePair;
import org.n52.shetland.ogc.om.series.MeasurementTimeseriesMetadata;
import org.n52.shetland.ogc.om.series.tsml.TimeseriesMLConstants;
import org.n52.shetland.ogc.om.series.tsml.TimeseriesMLConstants.InterpolationType;
import org.n52.shetland.ogc.om.values.CountValue;
import org.n52.shetland.ogc.om.values.ProfileValue;
import org.n52.shetland.ogc.om.values.QuantityValue;
import org.n52.shetland.ogc.om.values.SweDataArrayValue;
import org.n52.shetland.ogc.om.values.TVPValue;
import org.n52.shetland.ogc.om.values.TextValue;
import org.n52.shetland.ogc.om.values.Value;
import org.n52.shetland.ogc.ows.exception.OwsExceptionReport;
import org.n52.shetland.ogc.swe.SweConstants;
import org.n52.shetland.ogc.swe.simpleType.SweQuality;
import org.n52.shetland.ogc.swe.simpleType.SweQualityHolder;
import org.n52.shetland.ogc.swe.simpleType.SweQuantity;
import org.n52.shetland.util.DateTimeFormatException;
import org.n52.shetland.w3c.W3CConstants;
import org.n52.svalbard.encode.EncodingContext;
import org.n52.svalbard.encode.WmlTmlHelper;
import org.n52.svalbard.encode.XmlBeansEncodingFlags;
import org.n52.svalbard.encode.exception.EncodingException;

import com.google.common.base.Strings;

/**
 * TODO(specki): update javadoc Implementation of {@link AbstractOmV20XmlStreamWriter} to write WaterML 2.0
 * encoded {@link OmObservation}s to stream
 *
 * @since 1.0.0
 *
 */
public class TsmlTVPEncoderv10XmlStreamWriter extends AbstractOmV20XmlStreamWriter implements WmlTmlHelper {
    public TsmlTVPEncoderv10XmlStreamWriter(EncodingContext context, OutputStream outputStream, OmObservation element)
            throws XMLStreamException {
        super(context, outputStream, element);
    }

    @Override
    protected void writeResult() throws XMLStreamException, EncodingException {
        start(OmConstants.QN_OM_20_RESULT);
        namespace(TimeseriesMLConstants.NS_TSML_10_PREFIX, TimeseriesMLConstants.NS_TSML_10);
        start(TimeseriesMLConstants.QN_MEASUREMENT_TIMESERIES);
        OmObservation observation = getElement();
        attr(GmlConstants.QN_ID_32, "timeseries." + observation.getObservationID());
        writeMeasurementTimeseriesMLMetadata(observation);
        if (observation.getValue() instanceof SingleObservationValue) {
            SingleObservationValue observationValue = (SingleObservationValue) observation.getValue();
            writeDefaultPointMetadata(observationValue, observationValue.getValue().getUnit());
            if (checkSweDataArray(observationValue.getValue())) {
                SweDataArrayValue sweDataArrayValue = (SweDataArrayValue) observationValue.getValue();
                for (List list : sweDataArrayValue.getValue().getValues()) {
                    for (int i = 0; i < list.size(); i = i + 2) {
                        writePoint(list.get(i), list.get(i + 1));
                        close();
                    }
                }
            } else {
                String time = getTimeString(observationValue.getPhenomenonTime());
                writePoint(time, observation.getValue().getValue());
                close();
            }
        } else if (observation.getValue() instanceof MultiObservationValues) {
            // XML streaming to client
            MultiObservationValues observationValue = (MultiObservationValues) observation.getValue();
            writeDefaultPointMetadata(observationValue, observationValue.getValue().getUnit());
            TVPValue tvpValue = (TVPValue) observationValue.getValue();
            List timeValuePairs = tvpValue.getValue();
            for (TimeValuePair timeValuePair : timeValuePairs) {
                if (timeValuePair != null) {
                    writePoint(getTimeString(timeValuePair.getTime()), timeValuePair.getValue());
                }
            }
            close();
        } else if (observation.getValue() instanceof StreamingValue) {
            // Database streaming + XML streaming to client
            StreamingValue observationValue = (StreamingValue) observation.getValue();
            if (observationValue.isSetUnit()) {
                writeDefaultPointMetadata(observationValue, observationValue.getUnit());
            } else if (observation.getObservationConstellation()
                    .getObservableProperty() instanceof OmObservableProperty
                    && ((OmObservableProperty) observation.getObservationConstellation().getObservableProperty())
                            .isSetUnit()) {
                writeDefaultPointMetadata(observationValue,
                        ((OmObservableProperty) observation.getObservationConstellation().getObservableProperty())
                                .getUnit());
            } else {
                writeDefaultPointMetadata(observationValue, null);
            }
            try {
                while (observationValue.hasNext()) {
                    TimeValuePair timeValuePair = observationValue.nextValue();
                    if (timeValuePair != null) {
                        writePoint(getTimeString(timeValuePair.getTime()), timeValuePair.getValue());
                    }
                }
            } catch (DateTimeFormatException | OwsExceptionReport e) {
                throw new EncodingException(e);
            }
            close();
        } else {
            super.writeResult();
        }
    }

    @Override
    protected void writeAddtitionalNamespaces() throws XMLStreamException {
        namespace(TimeseriesMLConstants.NS_TSML_10_PREFIX, TimeseriesMLConstants.NS_TSML_10);
    }

    @Override
    protected void checkAndWriteIdentifier() throws EncodingException, XMLStreamException {
        if (getElement().getObservationConstellation().isSetIdentifier()) {
            writeIdentifier(getElement().getObservationConstellation().getIdentifierCodeWithAuthority());
        } else {
            super.checkAndWriteIdentifier();
        }
    }

    @Override
    protected void checkAndWriteName() throws EncodingException, XMLStreamException {
        if (getElement().getObservationConstellation().isSetName()) {
            for (CodeType name : getElement().getObservationConstellation().getName()) {
                writeName(name);
            }
        } else {
            super.checkAndWriteName();
        }
    }

    @Override
    protected void checkAndWriteDescription() throws XMLStreamException {
        if (getElement().getObservationConstellation().isSetDescription()) {
            writeDescription(getElement().getObservationConstellation().getDescription());
        } else {
            super.checkAndWriteDescription();
        }
    }

    /**
     * Close written wml:MeasurementTimeseriesML and om:result tags
     *
     * @throws XMLStreamException
     *             If an error occurs when writing to stream
     */
    private void close() throws XMLStreamException {
        end(TimeseriesMLConstants.QN_MEASUREMENT_TIMESERIES);
        end(OmConstants.QN_OM_20_RESULT);
    }

    /**
     * Write timeseries metadata to stream
     *
     * @param o
     *            the observation
     *
     * @throws XMLStreamException
     *             If an error occurs when writing to stream
     */
    private void writeMeasurementTimeseriesMLMetadata(OmObservation o) throws XMLStreamException {
        start(TimeseriesMLConstants.QN_METADATA);
        start(TimeseriesMLConstants.QN_MEASUREMENT_TIMESERIES_METADATA);
        empty(TimeseriesMLConstants.QN_TEMPORAL_EXTENT);
        addXlinkHrefAttr("#" + o.getPhenomenonTime().getGmlId());
        if (o.isSetValue() && o.getValue().isSetMetadata() && o.getValue().getMetadata().isSetTimeseriesMetadata()
                && o.getValue().getMetadata().getTimeseriesmetadata() instanceof MeasurementTimeseriesMetadata) {
            start(TimeseriesMLConstants.QN_CUMULATIVE);
            chars(Boolean.toString(((MeasurementTimeseriesMetadata) o.getValue().getMetadata().getTimeseriesmetadata())
                    .isCumulative()));
            endInline(TimeseriesMLConstants.QN_CUMULATIVE);
        }
        end(TimeseriesMLConstants.QN_MEASUREMENT_TIMESERIES_METADATA);
        end(TimeseriesMLConstants.QN_METADATA);
    }

    /**
     * Write wml:defaultPointMetadata to stream
     *
     * @param value
     *            the observation value
     * @param unit
     *            the unit
     *
     * @throws XMLStreamException
     *             If an error occurs when writing to stream
     */
    private void writeDefaultPointMetadata(@Nullable ObservationValue value, @Nullable String unit)
            throws XMLStreamException {
        start(TimeseriesMLConstants.QN_DEFAULT_POINT_METADATA);
        start(TimeseriesMLConstants.QN_DEFAULT_TVP_MEASUREMENT_METADATA);
        writeUOM(unit);
        writeInterpolationType(value);
        writeAggregationDuration(value);
        end(TimeseriesMLConstants.QN_DEFAULT_TVP_MEASUREMENT_METADATA);
        end(TimeseriesMLConstants.QN_DEFAULT_POINT_METADATA);
    }

    /**
     * Write UOM attribute to stream
     *
     * @param code
     *            UOM code
     *
     * @throws XMLStreamException
     *             If an error occurs when writing to stream
     */
    private void writeUOM(@Nullable String code) throws XMLStreamException {
        if (code != null && !code.isEmpty()) {
            empty(TimeseriesMLConstants.UOM);
            attr("code", code);
        }
    }

    /**
     * Write wml:interpolationType to stream
     *
     * @param value
     *            the value
     *
     * @throws XMLStreamException
     *             If an error occurs when writing to stream
     */
    private void writeInterpolationType(@Nullable ObservationValue value) throws XMLStreamException {
        empty(TimeseriesMLConstants.QN_INTERPOLATION_TYPE);
        if (value != null && value.isSetMetadata()
                && value.getDefaultPointMetadata().isSetDefaultTVPMeasurementMetadata()
                && value.getDefaultPointMetadata().getDefaultTVPMeasurementMetadata().isSetInterpolationType()) {
            InterpolationType interpolationtype = (InterpolationType) value.getDefaultPointMetadata()
                    .getDefaultTVPMeasurementMetadata().getInterpolationtype();
            addXlinkHrefAttr(interpolationtype.getIdentifier());
            addXlinkTitleAttr(interpolationtype.getTitle());
        } else {
            addXlinkHrefAttr("http://www.opengis.net/def/timeseries/InterpolationCode/continuous");
            addXlinkTitleAttr("Instantaneous");
        }
    }

    private void writeAggregationDuration(ObservationValue value) throws XMLStreamException {
        if (value != null && value.isSetMetadata()
                && value.getDefaultPointMetadata().isSetDefaultTVPMeasurementMetadata()
                && value.getDefaultPointMetadata().getDefaultTVPMeasurementMetadata().isSetAggregationDuration()) {
            start(TimeseriesMLConstants.QN_AGGREGATION_DURATION);
            chars(value.getDefaultPointMetadata().getDefaultTVPMeasurementMetadata().getAggregationDuration());
            end(TimeseriesMLConstants.QN_AGGREGATION_DURATION);
        }
    }

    private void writePoint(String time, Value value) throws XMLStreamException, EncodingException {
        if (value != null) {
            if (value instanceof QuantityValue) {
                QuantityValue quantityValue = (QuantityValue) value;
                writePoint(time, quantityValue);
            } else if (value instanceof ProfileValue) {
                ProfileValue gwglcValue = (ProfileValue) value;
                if (gwglcValue.isSetValue()) {
                    writePoint(time, gwglcValue.getValue().iterator().next().getSimpleValue());
                }
            } else if (value instanceof CountValue) {
                CountValue countValue = (CountValue) value;
                writePoint(time, countValue);
            } else if (value instanceof TextValue) {
                TextValue textValue = (TextValue) value;
                String nonXmlEscapedText = textValue.getValue();
                writePoint(time, StringEscapeUtils.escapeXml(nonXmlEscapedText), textValue.getQuality());
            }
        } else {
            writePoint(time, "");
        }
    }

    private void writePoint(String time, QuantityValue value) throws XMLStreamException, EncodingException {
        if (value.isSetValue()) {
            writePoint(time, value.getValue().toPlainString(), value.getQuality());
        } else {
            if (value.isSetQuality()) {
                writePointEmptyValueWithQuality(time, value.getQuality());
            } else {
                writePoint(time, "");
            }
        }
    }

    private void writePoint(String time, CountValue value) throws XMLStreamException, EncodingException {
        writePoint(time, value.isSetValue() ? Integer.toString(value.getValue()) : "", value.getQuality());
    }

    private void writePoint(String time, String string) throws XMLStreamException, EncodingException {
        writePoint(time, string, null);
    }

    /**
     * Write wml:point to stream
     *
     * @param time
     *            time as {@link String}
     * @param value
     *            value as {@link String}
     * @param sweQualityHolder
     *            quality data
     * @throws XMLStreamException
     *             If an error occurs when writing to stream
     * @throws EncodingException
     *             If an error occurs when encoding quality
     */
    private void writePoint(String time, String value, SweQualityHolder qualityHolder)
            throws XMLStreamException, EncodingException {
        if (!Strings.isNullOrEmpty(time)) {
            start(TimeseriesMLConstants.QN_POINT);
            writeMeasurementTVP(time, value, qualityHolder);
            end(TimeseriesMLConstants.QN_POINT);
        }
    }

    /**
     * Write wml:MeasurementTVP to stream
     *
     * @param time
     *            time as {@link String}
     * @param value
     *            value as {@link String}
     * @param sweQualityHolder
     *            quality data
     * @throws XMLStreamException
     *             If an error occurs when writing to stream
     */
    private void writeMeasurementTVP(String time, String value, SweQualityHolder qualityHolder)
            throws XMLStreamException, EncodingException {
        start(TimeseriesMLConstants.QN_MEASUREMENT_TVP);
        if (qualityHolder != null && qualityHolder.isSetQuality() && checkQuality(qualityHolder)) {
            writeValueMetadata(qualityHolder);
        }
        writeTime(time);
        writeValue(value);
        end(TimeseriesMLConstants.QN_MEASUREMENT_TVP);
    }

    private boolean checkQuality(SweQualityHolder quality) {
        if (quality.isSetQuality()) {
            return quality.getQuality().stream().filter(q -> q instanceof SweQuantity).findFirst().isPresent();
        }
        return false;
    }

    /**
     * Write wml:time to stream
     *
     * @param time
     *            time to write
     *
     * @throws XMLStreamException
     *             If an error occurs when writing to stream
     */
    private void writeTime(String time) throws XMLStreamException {
        start(TimeseriesMLConstants.QN_TIME);
        chars(time);
        endInline(TimeseriesMLConstants.QN_TIME);
    }

    /**
     * Write wml:value to stream
     *
     * @param value
     *            value to write
     *
     * @throws XMLStreamException
     *             If an error occurs when writing to stream
     */
    private void writeValue(String value) throws XMLStreamException {
        if (!Strings.isNullOrEmpty(value)) {
            start(TimeseriesMLConstants.QN_VALUE);
            chars(value);
            endInline(TimeseriesMLConstants.QN_VALUE);
        } else {
            writeEmptyValue();
            writeValueMetadataMissing();
        }
    }

    private void writePointEmptyValueWithQuality(String time, SweQualityHolder qualityHolder)
            throws XMLStreamException, EncodingException {
        start(TimeseriesMLConstants.QN_POINT);
        start(TimeseriesMLConstants.QN_MEASUREMENT_TVP);
        writeValueMetadata(qualityHolder);
        writeTime(time);
        writeEmptyValue();
        end(TimeseriesMLConstants.QN_MEASUREMENT_TVP);
        end(TimeseriesMLConstants.QN_POINT);
    }

    private void writeEmptyValue() throws XMLStreamException {
        empty(TimeseriesMLConstants.QN_VALUE);
        attr(W3CConstants.QN_XSI_NIL, "true");
    }

    /**
     * Write missing value metadata to stream
     *
     * @throws XMLStreamException
     *             If an error occurs when writing to stream
     */
    private void writeValueMetadata(SweQualityHolder qualityHolder) throws XMLStreamException, EncodingException {
        start(TimeseriesMLConstants.QN_METADATA);
        start(TimeseriesMLConstants.QN_TVP_MEASUREMENT_METADATA);
        writeCensoredReason(qualityHolder);
        writeQualifier(qualityHolder);
        endInline(TimeseriesMLConstants.QN_TVP_MEASUREMENT_METADATA);
        endInline(TimeseriesMLConstants.QN_METADATA);

    }

    private void writeQualifier(SweQualityHolder qualityHolder) throws EncodingException, XMLStreamException {
        if (qualityHolder.isSetQuality()) {
            for (SweQuality quality : qualityHolder.getQuality()) {
                if (quality instanceof SweQuantity) {
                    XmlObject createdQuality = (XmlObject) getEncoder(SweConstants.NS_SWE_20, quality).encode(quality,
                            EncodingContext.of(XmlBeansEncodingFlags.DOCUMENT, true));
                    if (createdQuality != null) {
                        start(TimeseriesMLConstants.QN_QUALIFIER);
                        writeXmlObject(createdQuality);
                        end(TimeseriesMLConstants.QN_QUALIFIER);
                    }
                }
            }
        }
    }

    private void writeCensoredReason(SweQualityHolder qualityHolder) throws XMLStreamException {
        if (qualityHolder.isSetReferences()
                && qualityHolder.getReferences().containsKey(TimeseriesMLConstants.EN_CENSORED_REASON)) {
            ReferenceType reference = qualityHolder.getReferences().get(TimeseriesMLConstants.EN_CENSORED_REASON);
            empty(TimeseriesMLConstants.QN_CENSORED_REASON);
            if (reference.isSetHref()) {
                attr(W3CConstants.QN_XLINK_HREF, reference.getHref());
            }
            if (reference.isSetTitle()) {
                attr(W3CConstants.QN_XLINK_TITLE, reference.getTitle());
            }
        }
    }

    /**
     * Write missing value metadata to stream
     *
     * @throws XMLStreamException
     *             If an error occurs when writing to stream
     */
    private void writeValueMetadataMissing() throws XMLStreamException {
        start(TimeseriesMLConstants.QN_METADATA);
        start(TimeseriesMLConstants.QN_TVP_MEASUREMENT_METADATA);
        empty(TimeseriesMLConstants.QN_NIL_REASON);
        addXlinkHrefAttr("missing");
        endInline(TimeseriesMLConstants.QN_TVP_MEASUREMENT_METADATA);
        endInline(TimeseriesMLConstants.QN_METADATA);

    }

    @Override
    protected Optional getDefaultFeatureEncodingNamespace() {
        return Optional.of(TimeseriesMLConstants.NS_TSML_10);
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy