/** * Copyright (C) 2012-2017 52°North Initiative for Geospatial Open Source * Software GmbH * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. * * If the program is linked with libraries which are licensed under one of * the following licenses, the combination of the program with the linked * library is not considered a "derivative work" of the program: * * - Apache License, version 2.0 * - Apache Software License, version 1.0 * - GNU Lesser General Public License, version 3 * - Mozilla Public License, versions 1.0, 1.1 and 2.0 * - Common Development and Distribution License (CDDL), version 1.0 * * Therefore the distribution of the program linked with libraries licensed * under the aforementioned licenses, is permitted by the copyright holders * if the distribution is compliant with both the GNU General Public * License version 2 and the aforementioned licenses. * * This program 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 General * Public License for more details. */ package org.n52.sos.encode; import java.io.OutputStream; import java.math.BigInteger; import java.util.Collections; import java.util.EnumMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import javax.xml.stream.XMLStreamException; import net.opengis.om.x20.OMObservationType; import org.apache.xmlbeans.XmlBoolean; import org.apache.xmlbeans.XmlInteger; import org.apache.xmlbeans.XmlObject; import org.apache.xmlbeans.XmlString; import org.n52.sos.encode.streaming.OmV20XmlStreamWriter; import org.n52.sos.exception.ows.NoApplicableCodeException; import org.n52.sos.exception.ows.concrete.UnsupportedEncoderInputException; import org.n52.sos.ogc.gml.GmlConstants; import org.n52.sos.ogc.om.AbstractObservationValue; import org.n52.sos.ogc.om.MultiObservationValues; import org.n52.sos.ogc.om.NamedValue; import org.n52.sos.ogc.om.ObservationValue; import org.n52.sos.ogc.om.OmConstants; import org.n52.sos.ogc.om.OmObservation; import org.n52.sos.ogc.om.SingleObservationValue; import org.n52.sos.ogc.om.features.SfConstants; import org.n52.sos.ogc.om.values.BooleanValue; import org.n52.sos.ogc.om.values.CategoryValue; import org.n52.sos.ogc.om.values.CountValue; import org.n52.sos.ogc.om.values.GeometryValue; import org.n52.sos.ogc.om.values.QuantityValue; import org.n52.sos.ogc.om.values.TextValue; import org.n52.sos.ogc.ows.OwsExceptionReport; import org.n52.sos.ogc.sensorML.SensorMLConstants; import org.n52.sos.ogc.sos.ConformanceClasses; import org.n52.sos.ogc.sos.Sos2Constants; import org.n52.sos.ogc.sos.SosConstants; import org.n52.sos.ogc.sos.SosConstants.HelperValues; import org.n52.sos.ogc.swe.SweConstants; import org.n52.sos.ogc.swe.SweDataArray; import org.n52.sos.service.ServiceConstants.SupportedTypeKey; import org.n52.sos.util.CodingHelper; import org.n52.sos.util.OMHelper; import org.n52.sos.util.StringHelper; import org.n52.sos.util.SweHelper; import org.n52.sos.util.XmlOptionsHelper; import org.n52.sos.util.http.MediaType; import org.n52.sos.w3c.SchemaLocation; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.base.Joiner; import com.google.common.collect.Sets; /** * @since 4.0.0 * */ public class OmEncoderv20 extends AbstractOmEncoderv20 { /** * logger, used for logging while initializing the constants from config * file */ private static final Logger LOGGER = LoggerFactory.getLogger(OmEncoderv20.class); private static final Set<EncoderKey> ENCODER_KEYS = CodingHelper.encoderKeysForElements(OmConstants.NS_OM_2, OmObservation.class, NamedValue.class, SingleObservationValue.class, MultiObservationValues.class); // TODO: change to correct conformance class private static final Set<String> CONFORMANCE_CLASSES = Sets.newHashSet(ConformanceClasses.OM_V2_MEASUREMENT, ConformanceClasses.OM_V2_CATEGORY_OBSERVATION, ConformanceClasses.OM_V2_COUNT_OBSERVATION, ConformanceClasses.OM_V2_TRUTH_OBSERVATION, ConformanceClasses.OM_V2_GEOMETRY_OBSERVATION, ConformanceClasses.OM_V2_TEXT_OBSERVATION); private static final Map<SupportedTypeKey, Set<String>> SUPPORTED_TYPES = Collections.singletonMap( SupportedTypeKey.ObservationType, (Set<String>) Sets.newHashSet(OmConstants.OBS_TYPE_CATEGORY_OBSERVATION, OmConstants.OBS_TYPE_COUNT_OBSERVATION, OmConstants.OBS_TYPE_GEOMETRY_OBSERVATION, OmConstants.OBS_TYPE_MEASUREMENT, OmConstants.OBS_TYPE_TEXT_OBSERVATION, OmConstants.OBS_TYPE_TRUTH_OBSERVATION, OmConstants.OBS_TYPE_SWE_ARRAY_OBSERVATION)); private static final Map<String, Map<String, Set<String>>> SUPPORTED_RESPONSE_FORMATS = Collections.singletonMap( SosConstants.SOS, Collections.singletonMap(Sos2Constants.SERVICEVERSION, Collections.singleton(OmConstants.NS_OM_2))); public OmEncoderv20() { LOGGER.debug("Encoder for the following keys initialized successfully: {}!", Joiner.on(", ") .join(ENCODER_KEYS)); } @Override public Set<EncoderKey> getEncoderKeyType() { return Collections.unmodifiableSet(ENCODER_KEYS); } @Override public Map<SupportedTypeKey, Set<String>> getSupportedTypes() { return Collections.unmodifiableMap(SUPPORTED_TYPES); } @Override public Set<String> getConformanceClasses() { return Collections.unmodifiableSet(CONFORMANCE_CLASSES); } @Override public boolean isObservationAndMeasurmentV20Type() { return true; } @Override public Set<String> getSupportedResponseFormats(String service, String version) { if (SUPPORTED_RESPONSE_FORMATS.get(service) != null && SUPPORTED_RESPONSE_FORMATS.get(service).get(version) != null) { return SUPPORTED_RESPONSE_FORMATS.get(service).get(version); } return new HashSet<String>(0); } @Override public boolean shouldObservationsWithSameXBeMerged() { return false; } @Override public boolean supportsResultStreamingForMergedValues() { // TODO Auto-generated method stub return false; } @Override public MediaType getContentType() { return OmConstants.CONTENT_TYPE_OM_2; } @Override public Set<SchemaLocation> getSchemaLocations() { return Sets.newHashSet(OmConstants.OM_20_SCHEMA_LOCATION); } @Override public XmlObject encode(Object element, Map<HelperValues, String> additionalValues) throws OwsExceptionReport, UnsupportedEncoderInputException { XmlObject encodedObject = null; if (element instanceof ObservationValue) { encodedObject = encodeResult((ObservationValue<?>)element); } else { encodedObject = super.encode(element, additionalValues); } return encodedObject; } @Override public void encode(Object objectToEncode, OutputStream outputStream, EncodingValues encodingValues) throws OwsExceptionReport { encodingValues.setEncoder(this); if (objectToEncode instanceof OmObservation) { try { new OmV20XmlStreamWriter().write((OmObservation)objectToEncode, outputStream, encodingValues); } catch (XMLStreamException xmlse) { throw new NoApplicableCodeException().causedBy(xmlse).withMessage("Error while writing element to stream!"); } } else { super.encode(objectToEncode, outputStream, encodingValues); } } @Override protected XmlObject createResult(OmObservation sosObservation) throws OwsExceptionReport { // TODO if OM_SWEArrayObservation and get ResultEncoding and // ResultStructure exists, if (sosObservation.getValue() instanceof AbstractObservationValue) { ((AbstractObservationValue<?>)sosObservation.getValue()).setValuesForResultEncoding(sosObservation); return encodeResult(sosObservation.getValue()); } else { if (sosObservation.getValue() instanceof SingleObservationValue) { return createSingleObservationToResult(sosObservation); } else if (sosObservation.getValue() instanceof MultiObservationValues) { return createMultiObservationValueToResult(sosObservation); } } return null; } @Override protected XmlObject encodeResult(ObservationValue<?> observationValue) throws OwsExceptionReport { if (observationValue instanceof SingleObservationValue) { return createSingleObservationToResult((SingleObservationValue<?>)observationValue); } else if (observationValue instanceof MultiObservationValues) { return createMultiObservationValueToResult((MultiObservationValues<?>)observationValue); } return null; } @Override protected void addObservationType(OMObservationType xbObservation, String observationType) { if (StringHelper.isNotEmpty(observationType)) { xbObservation.addNewType().setHref(observationType); } } @Override public String getDefaultFeatureEncodingNamespace() { return SfConstants.NS_SAMS; } @Override protected String getDefaultProcedureEncodingNamspace() { return SensorMLConstants.NS_SML; } @Override protected boolean convertEncodedProcedure() { return false; } // FIXME String.equals(QName)!? /** * Create a om:result content XmlBeans object from a SOS single value * observation object * * @param sosObservation * SOS observation * @return XmlBeans object for om:result * @throws OwsExceptionReport * If an error occurs */ @Deprecated private XmlObject createSingleObservationToResult(OmObservation sosObservation) throws OwsExceptionReport { SingleObservationValue<?> observationValue = (SingleObservationValue<?>) sosObservation.getValue(); final String observationType; if (sosObservation.getObservationConstellation().isSetObservationType()) { observationType = sosObservation.getObservationConstellation().getObservationType(); } else { observationType = OMHelper.getObservationTypeFor(observationValue.getValue()); } if ((observationType.equals(OmConstants.OBS_TYPE_MEASUREMENT)) && observationValue.getValue() instanceof QuantityValue) { QuantityValue quantityValue = (QuantityValue) observationValue.getValue(); return CodingHelper.encodeObjectToXml(GmlConstants.NS_GML_32, quantityValue); } else if ((observationType.equals(OmConstants.OBS_TYPE_COUNT_OBSERVATION)) && observationValue.getValue() instanceof CountValue) { CountValue countValue = (CountValue) observationValue.getValue(); XmlInteger xbInteger = XmlInteger.Factory.newInstance(XmlOptionsHelper.getInstance().getXmlOptions()); if (countValue.getValue() != null && countValue.getValue() != Integer.MIN_VALUE) { xbInteger.setBigIntegerValue(new BigInteger(countValue.getValue().toString())); } else { xbInteger.setNil(); } return xbInteger; } else if ((observationType.equals(OmConstants.OBS_TYPE_TEXT_OBSERVATION)) && observationValue.getValue() instanceof TextValue) { TextValue textValue = (TextValue) observationValue.getValue(); XmlString xbString = XmlString.Factory.newInstance(XmlOptionsHelper.getInstance().getXmlOptions()); if (textValue.getValue() != null && !textValue.getValue().isEmpty()) { xbString.setStringValue(textValue.getValue()); } else { xbString.setNil(); } return xbString; } else if ((observationType.equals(OmConstants.OBS_TYPE_TRUTH_OBSERVATION)) && observationValue.getValue() instanceof BooleanValue) { BooleanValue booleanValue = (BooleanValue) observationValue.getValue(); XmlBoolean xbBoolean = XmlBoolean.Factory.newInstance(XmlOptionsHelper.getInstance().getXmlOptions()); if (booleanValue.getValue() != null) { xbBoolean.setBooleanValue(booleanValue.getValue()); } else { xbBoolean.setNil(); } return xbBoolean; } else if ((observationType.equals(OmConstants.OBS_TYPE_CATEGORY_OBSERVATION)) && observationValue.getValue() instanceof CategoryValue) { CategoryValue categoryValue = (CategoryValue) observationValue.getValue(); if (categoryValue.getValue() != null && !categoryValue.getValue().isEmpty()) { Map<HelperValues, String> additionalValue = new EnumMap<HelperValues, String>(HelperValues.class); additionalValue .put(HelperValues.GMLID, SosConstants.OBS_ID_PREFIX + sosObservation.getObservationID()); XmlObject xmlObject = CodingHelper.encodeObjectToXml(GmlConstants.NS_GML_32, categoryValue, additionalValue); return xmlObject; } else { return null; } } else if ((observationType.equals(OmConstants.OBS_TYPE_GEOMETRY_OBSERVATION)) && observationValue.getValue() instanceof GeometryValue) { GeometryValue geometryValue = (GeometryValue) observationValue.getValue(); if (geometryValue.getValue() != null) { Map<HelperValues, String> additionalValue = new EnumMap<HelperValues, String>(HelperValues.class); additionalValue .put(HelperValues.GMLID, SosConstants.OBS_ID_PREFIX + sosObservation.getObservationID()); additionalValue.put(HelperValues.PROPERTY_TYPE, null); XmlObject xmlObject = CodingHelper.encodeObjectToXml(GmlConstants.NS_GML_32, geometryValue.getValue(), additionalValue); return xmlObject; } else { return null; } } else if (observationType.equals(OmConstants.OBS_TYPE_SWE_ARRAY_OBSERVATION)) { // TODO create SosSweDataArray SweDataArray dataArray = SweHelper.createSosSweDataArray(sosObservation); Map<HelperValues, String> additionalValues = new EnumMap<SosConstants.HelperValues, String>(SosConstants.HelperValues.class); additionalValues.put(HelperValues.FOR_OBSERVATION, null); // TODO create SosSweDataArray Object encodedObj = CodingHelper.encodeObjectToXml(SweConstants.NS_SWE_20, dataArray, additionalValues); if (encodedObj instanceof XmlObject) { return (XmlObject) encodedObj; } else { throw new NoApplicableCodeException().withMessage( "Encoding of observation value of type \"%s\" failed. Result: %s", observationValue.getValue() != null ? observationValue.getValue().getClass().getName() : observationValue.getValue(), encodedObj != null ? encodedObj.getClass().getName() : encodedObj); } } return null; } /** * Create a om:result content XmlBeans object from a SOS multi value * observation object * * @param sosObservation * SOS observation * @return XmlBeans object for om:result * @throws OwsExceptionReport * If an error occurs */ @Deprecated private XmlObject createMultiObservationValueToResult(OmObservation sosObservation) throws OwsExceptionReport { MultiObservationValues<?> observationValue = (MultiObservationValues<?>) sosObservation.getValue(); // TODO create SosSweDataArray SweDataArray dataArray = SweHelper.createSosSweDataArray(sosObservation); Map<HelperValues, String> additionalValues = new EnumMap<SosConstants.HelperValues, String>(SosConstants.HelperValues.class); additionalValues.put(HelperValues.FOR_OBSERVATION, null); Object encodedObj = CodingHelper.encodeObjectToXml(SweConstants.NS_SWE_20, dataArray, additionalValues); if (encodedObj instanceof XmlObject) { return (XmlObject) encodedObj; } else { throw new NoApplicableCodeException().withMessage( "Encoding of observation value of type \"%s\" failed. Result: %s", observationValue.getValue() != null ? observationValue.getValue().getClass().getName() : observationValue.getValue(), encodedObj != null ? encodedObj.getClass().getName() : encodedObj); } } private XmlObject createSingleObservationToResult(SingleObservationValue<?> observationValue) throws OwsExceptionReport { final String observationType; if (observationValue.isSetObservationType()) { observationType = observationValue.getObservationType(); } else { observationType = OMHelper.getObservationTypeFor(observationValue.getValue()); } if ((observationType.equals(OmConstants.OBS_TYPE_MEASUREMENT)) && observationValue.getValue() instanceof QuantityValue) { QuantityValue quantityValue = (QuantityValue) observationValue.getValue(); return CodingHelper.encodeObjectToXml(GmlConstants.NS_GML_32, quantityValue); } else if ((observationType.equals(OmConstants.OBS_TYPE_COUNT_OBSERVATION)) && observationValue.getValue() instanceof CountValue) { CountValue countValue = (CountValue) observationValue.getValue(); XmlInteger xbInteger = XmlInteger.Factory.newInstance(XmlOptionsHelper.getInstance().getXmlOptions()); if (countValue.getValue() != null && countValue.getValue() != Integer.MIN_VALUE) { xbInteger.setBigIntegerValue(new BigInteger(countValue.getValue().toString())); } else { xbInteger.setNil(); } return xbInteger; } else if ((observationType.equals(OmConstants.OBS_TYPE_TEXT_OBSERVATION)) && observationValue.getValue() instanceof TextValue) { TextValue textValue = (TextValue) observationValue.getValue(); XmlString xbString = XmlString.Factory.newInstance(XmlOptionsHelper.getInstance().getXmlOptions()); if (textValue.getValue() != null && !textValue.getValue().isEmpty()) { xbString.setStringValue(textValue.getValue()); } else { xbString.setNil(); } return xbString; } else if ((observationType.equals(OmConstants.OBS_TYPE_TRUTH_OBSERVATION)) && observationValue.getValue() instanceof BooleanValue) { BooleanValue booleanValue = (BooleanValue) observationValue.getValue(); XmlBoolean xbBoolean = XmlBoolean.Factory.newInstance(XmlOptionsHelper.getInstance().getXmlOptions()); if (booleanValue.getValue() != null) { xbBoolean.setBooleanValue(booleanValue.getValue()); } else { xbBoolean.setNil(); } return xbBoolean; } else if ((observationType.equals(OmConstants.OBS_TYPE_CATEGORY_OBSERVATION)) && observationValue.getValue() instanceof CategoryValue) { CategoryValue categoryValue = (CategoryValue) observationValue.getValue(); if (categoryValue.getValue() != null && !categoryValue.getValue().isEmpty()) { Map<HelperValues, String> additionalValue = new EnumMap<HelperValues, String>(HelperValues.class); additionalValue .put(HelperValues.GMLID, SosConstants.OBS_ID_PREFIX + observationValue.getObservationID()); XmlObject xmlObject = CodingHelper.encodeObjectToXml(GmlConstants.NS_GML_32, categoryValue, additionalValue); return xmlObject; } else { return null; } } else if ((observationType.equals(OmConstants.OBS_TYPE_GEOMETRY_OBSERVATION)) && observationValue.getValue() instanceof GeometryValue) { GeometryValue geometryValue = (GeometryValue) observationValue.getValue(); if (geometryValue.getValue() != null) { Map<HelperValues, String> additionalValue = new EnumMap<HelperValues, String>(HelperValues.class); additionalValue .put(HelperValues.GMLID, SosConstants.OBS_ID_PREFIX + observationValue.getObservationID()); additionalValue.put(HelperValues.PROPERTY_TYPE, null); XmlObject xmlObject = CodingHelper.encodeObjectToXml(GmlConstants.NS_GML_32, geometryValue.getValue(), additionalValue); return xmlObject; } else { return null; } } else if (observationType.equals(OmConstants.OBS_TYPE_SWE_ARRAY_OBSERVATION)) { // TODO create SosSweDataArray SweDataArray dataArray = SweHelper.createSosSweDataArray(observationValue); Map<HelperValues, String> additionalValues = new EnumMap<SosConstants.HelperValues, String>(SosConstants.HelperValues.class); additionalValues.put(HelperValues.FOR_OBSERVATION, null); // TODO create SosSweDataArray Object encodedObj = CodingHelper.encodeObjectToXml(SweConstants.NS_SWE_20, dataArray, additionalValues); if (encodedObj instanceof XmlObject) { return (XmlObject) encodedObj; } else { throw new NoApplicableCodeException().withMessage( "Encoding of observation value of type \"%s\" failed. Result: %s", observationValue.getValue() != null ? observationValue.getValue().getClass().getName() : observationValue.getValue(), encodedObj != null ? encodedObj.getClass().getName() : encodedObj); } } return null; } private XmlObject createMultiObservationValueToResult(MultiObservationValues<?> observationValue) throws OwsExceptionReport { // TODO create SosSweDataArray SweDataArray dataArray = SweHelper.createSosSweDataArray(observationValue); Map<HelperValues, String> additionalValues = new EnumMap<SosConstants.HelperValues, String>(SosConstants.HelperValues.class); additionalValues.put(HelperValues.FOR_OBSERVATION, null); Object encodedObj = CodingHelper.encodeObjectToXml(SweConstants.NS_SWE_20, dataArray, additionalValues); if (encodedObj instanceof XmlObject) { return (XmlObject) encodedObj; } else { throw new NoApplicableCodeException().withMessage( "Encoding of observation value of type \"%s\" failed. Result: %s", observationValue.getValue() != null ? observationValue.getValue().getClass().getName() : observationValue.getValue(), encodedObj != null ? encodedObj.getClass().getName() : encodedObj); } } }