diff --git a/lib-ogc/swe-common-core/src/main/java/org/vast/swe/fast/CotDataReader.java b/lib-ogc/swe-common-core/src/main/java/org/vast/swe/fast/CotDataReader.java new file mode 100644 index 0000000000..827e088043 --- /dev/null +++ b/lib-ogc/swe-common-core/src/main/java/org/vast/swe/fast/CotDataReader.java @@ -0,0 +1,64 @@ +/***************************** BEGIN LICENSE BLOCK *************************** + +The contents of this file are subject to the Mozilla Public License, v. 2.0. +If a copy of the MPL was not distributed with this file, You can obtain one +at http://mozilla.org/MPL/2.0/. + +Software distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +for the specific language governing rights and limitations under the License. + +Copyright (C) 2012-2015 Sensia Software LLC. All Rights Reserved. + +******************************* END LICENSE BLOCK ***************************/ + +package org.vast.swe.fast; + +import com.ctc.wstx.api.WstxOutputProperties; +import com.google.gson.FormattingStyle; +import com.google.gson.Strictness; +import net.opengis.swe.v20.*; +import net.opengis.swe.v20.Boolean; +import org.vast.data.AbstractArrayImpl; +import org.vast.data.XMLEncodingImpl; +import org.vast.swe.SWEDataTypeUtils; +import org.vast.util.DateTimeFormat; +import org.vast.util.WriterException; + +import javax.xml.namespace.NamespaceContext; +import javax.xml.namespace.QName; +import javax.xml.stream.*; +import java.io.IOException; +import java.io.OutputStream; +import java.io.Reader; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +/** + *

+ * New implementation of XML data writer with better efficiency since the + * write tree is pre-computed during init instead of being re-evaluated + * while iterating through the component tree. + *

+ * + * @author Ashley Poteau + * @since Dec 2, 2025 + */ + +public class CotDataReader extends XmlDataParser { + static final String COT_ERROR = "Error writing XML stream for "; + private final Reader in; + + protected XMLStreamReader xmlReader; + protected XMLStreamWriter xmlWriter; + protected String namespace; + protected String prefix; + protected Map countWriters = new HashMap<>(); + + public CotDataReader(Reader in) { + this.in = Objects.requireNonNull(in, "in == null"); + } + + +} diff --git a/lib-ogc/swe-common-core/src/main/java/org/vast/swe/fast/CotDataWriter.java b/lib-ogc/swe-common-core/src/main/java/org/vast/swe/fast/CotDataWriter.java new file mode 100644 index 0000000000..21fb273e9f --- /dev/null +++ b/lib-ogc/swe-common-core/src/main/java/org/vast/swe/fast/CotDataWriter.java @@ -0,0 +1,149 @@ +/***************************** BEGIN LICENSE BLOCK *************************** + +The contents of this file are subject to the Mozilla Public License, v. 2.0. +If a copy of the MPL was not distributed with this file, You can obtain one +at http://mozilla.org/MPL/2.0/. + +Software distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +for the specific language governing rights and limitations under the License. + +Copyright (C) 2012-2015 Sensia Software LLC. All Rights Reserved. + +******************************* END LICENSE BLOCK ***************************/ + +package org.vast.swe.fast; + +import com.ctc.wstx.api.WstxOutputProperties; +import com.google.gson.FormattingStyle; +import com.google.gson.Strictness; +import net.opengis.swe.v20.*; +import net.opengis.swe.v20.Boolean; +import org.vast.data.AbstractArrayImpl; +import org.vast.data.XMLEncodingImpl; +import org.vast.swe.SWEDataTypeUtils; +import org.vast.util.DateTimeFormat; +import org.vast.util.WriterException; + +import javax.xml.namespace.NamespaceContext; +import javax.xml.stream.XMLOutputFactory; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; +import java.io.IOException; +import java.io.OutputStream; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Set; + + +/** + *

+ * New implementation of XML data writer with better efficiency since the + * write tree is pre-computed during init instead of being re-evaluated + * while iterating through the component tree. + *

+ * + * @author Ashley Poteau + * @since Oct 31, 2025 + */ +public class CotDataWriter extends XmlDataWriter { + static final String COT_ERROR = "Error writing XML stream for "; + + protected String namespace; + protected String prefix; + protected Map countWriters = new HashMap<>(); + private boolean serializeNulls = true; + private FormattingStyle formattingStyle; + // These fields cache data derived from the formatting style, to avoid having to + // re-evaluate it every time something is written + private String formattedColon; + private String formattedComma; + private boolean usesEmptyNewlineAndIndent; + + + public void writeStartElement(String namespaceURI, String localName) throws XMLStreamException { + xmlWriter.writeStartElement(namespaceURI, localName); + } + + public void writeCotCharacters(String text) throws XMLStreamException { + if (xmlWriter == null) { + throw new IllegalStateException("XMLStreamWriter not initialized. Call setOutput() first."); + } + xmlWriter.writeCharacters(text); + } + + public void writeCotStartElement(String text) throws XMLStreamException { + if (xmlWriter == null) { + throw new IllegalStateException("XMLStreamWriter not initialized. Call setOutput() first."); + } + xmlWriter.writeStartElement(text); + } + + public void writeCotAttribute(String var1, String var2) throws XMLStreamException { + if (xmlWriter == null) { + throw new IllegalStateException("XMLStreamWriter not initialized. Call setOutput() first."); + } + xmlWriter.writeAttribute(var1, var2); + } + + @Override + public void startStream(boolean addWrapper) throws IOException + { + try + { + if (addWrapper) + xmlWriter.writeStartElement("event"); + } + catch (XMLStreamException e) + { + throw new IOException(e.getMessage(), e.getCause()); + } + } + + public void writeCotEndElement() throws XMLStreamException { + xmlWriter.writeEndElement(); + } + + public final void setSerializeNulls(boolean serializeNulls) { + + this.serializeNulls = serializeNulls; + } + + /** + * Returns true if object members are serialized when their value is null. This has no impact on + * array elements. The default is true. + */ + public final boolean getSerializeNulls() { + return serializeNulls; + } + +// public final void setFormattingStyle(FormattingStyle formattingStyle) { +// this.formattingStyle = Objects.requireNonNull(formattingStyle); +// +// this.formattedComma = ","; +// if (this.formattingStyle.usesSpaceAfterSeparators()) { +// this.formattedColon = ": "; +// +// // Only add space if no newline is written +// if (this.formattingStyle.getNewline().isEmpty()) { +// this.formattedComma = ", "; +// } +// } else { +// this.formattedColon = ":"; +// } +// +// this.usesEmptyNewlineAndIndent = +// this.formattingStyle.getNewline().isEmpty() && this.formattingStyle.getIndent().isEmpty(); +// } +// +// +// public final void setIndent(String indent) { +// if (indent.isEmpty()) { +// setFormattingStyle(FormattingStyle.COMPACT); +// } else { +// setFormattingStyle(FormattingStyle.PRETTY.withIndent(indent)); +// } +// } + +} diff --git a/lib-ogc/swe-common-core/src/main/java/org/vast/swe/fast/XmlDataWriter.java b/lib-ogc/swe-common-core/src/main/java/org/vast/swe/fast/XmlDataWriter.java index bb58502b7e..18171b9fb8 100644 --- a/lib-ogc/swe-common-core/src/main/java/org/vast/swe/fast/XmlDataWriter.java +++ b/lib-ogc/swe-common-core/src/main/java/org/vast/swe/fast/XmlDataWriter.java @@ -322,7 +322,7 @@ public int process(DataBlock data, int index) throws IOException } - protected void writeStartElement(String eltName) throws XMLStreamException + public void writeStartElement(String eltName) throws XMLStreamException { if (namespace != null) { diff --git a/lib-ogc/swe-common-core/src/main/java/org/vast/swe/helper/CoTHelper.java b/lib-ogc/swe-common-core/src/main/java/org/vast/swe/helper/CoTHelper.java new file mode 100644 index 0000000000..ac8b746437 --- /dev/null +++ b/lib-ogc/swe-common-core/src/main/java/org/vast/swe/helper/CoTHelper.java @@ -0,0 +1,735 @@ +/***************************** BEGIN LICENSE BLOCK *************************** + +The contents of this file are subject to the Mozilla Public License, v. 2.0. +If a copy of the MPL was not distributed with this file, You can obtain one +at http://mozilla.org/MPL/2.0/. + +Software distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +for the specific language governing rights and limitations under the License. + +The Initial Developer is Botts Innovative Research Inc. Portions created by the Initial +Developer are Copyright (C) 2016 the Initial Developer. All Rights Reserved. + +******************************* END LICENSE BLOCK ***************************/ + +package org.vast.swe.helper; + +import net.opengis.swe.v20.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.vast.swe.SWEBuilders.QuantityBuilder; +import org.vast.swe.SWEBuilders.VectorBuilder; +import org.vast.swe.SWEConstants; +import org.vast.swe.SWEHelper; + + +/** + *

+ * Helper class to create SWE structures used for geo-positioning
+ * This includes location and attitude but also linear velocity, angular rate, + * and linear acceleration + *

+ * + * @author Ashley Poteau + * @since December 11, 2025 + */ +public class CoTHelper extends VectorHelper +{ + + private static final Logger logger = LoggerFactory.getLogger(CoTHelper.class); + + public static final String DEF_LATITUDE_GEODETIC = SWEHelper.getPropertyUri("GeodeticLatitude"); + public static final String DEF_LONGITUDE = SWEHelper.getPropertyUri("Longitude"); + public static final String DEF_ALTITUDE_ELLIPSOID = SWEHelper.getPropertyUri("HeightAboveEllipsoid"); + public static final String DEF_ALTITUDE_MSL = SWEHelper.getPropertyUri("HeightAboveMSL"); + public static final String DEF_ALTITUDE_GROUND = SWEHelper.getPropertyUri("HeightAboveGround"); + public static final String DEF_ALTITUDE_BAROMETRIC = SWEHelper.getPropertyUri("BarometricAltitude"); + public static final String DEF_HEADING_TRUE = SWEHelper.getPropertyUri("TrueHeading"); + public static final String DEF_HEADING_MAGNETIC = SWEHelper.getPropertyUri("MagneticHeading"); + public static final String DEF_YAW_ANGLE = SWEHelper.getPropertyUri("YawAngle"); + public static final String DEF_PITCH_ANGLE = SWEHelper.getPropertyUri("PitchAngle"); + public static final String DEF_ROLL_ANGLE = SWEHelper.getPropertyUri("RollAngle"); + public static final String DEF_AZIMUTH_ANGLE = SWEHelper.getPropertyUri("AzimuthAngle"); + public static final String DEF_ELEVATION_ANGLE = SWEHelper.getPropertyUri("ElevationAngle"); + + public Time createPrecisionTimeStamp(){ + return createTime() + .asSamplingTimeIsoUTC() + .name("time") + .description("time stamp: when the event was generated") + .build(); + } + + public Quantity createCoTVersion(){ + return createQuantity() + .name("version") + .label("Version") + .definition(SWEHelper.getPropertyUri("cot-version")) + .description("Schema version of this event instance (e.g. 2.0)") + .build(); + } + public Category createUID(){ + return createCategory() + .name("uid") + .label("UID") + .definition(SWEHelper.getPropertyUri("id")) + .description("Globally unique name for this information on this event") + .build(); + } + + public Category createType(){ + return createCategory() + .name("type") + .label("Type") + .definition(SWEHelper.getPropertyUri("cot-type")) + .description("Hierarchically organized hint about event type") + .build(); + } + + public Time createStartTime(){ + return createTime() + .asSamplingTimeIsoUTC() + .name("start-time") + .label("Start Time") + .definition(SWEHelper.getPropertyUri("start-time")) + .description("starting time when an event should be considered valid") + .build(); + } + + public Time createStaleTime(){ + return createTime() + .asSamplingTimeIsoUTC() + .name("stale-time") + .label("Stale Time") + .definition(SWEHelper.getPropertyUri("stale-time")) + .description("ending time when an event should no longer be considered valid") + .build(); + } + public Text createHow(){ + return createText() + .name("how") + .label("How") + .definition(SWEHelper.getPropertyUri("cot-how")) + .description("Gives a hint about how the coordinates were generated") + .build(); + } + + public Quantity createCE(){ + return createQuantity() + .name("ce") + .label("Radius") + .definition(SWEHelper.getPropertyUri("cot-ce")) + .description("Circular 1-sigma or a circular area about the point in meters") + .uomCode("m") + .build(); + } + public Quantity createLE(){ + return createQuantity() + .name("le") + .label("Height") + .definition(SWEHelper.getPropertyUri("cot-le")) + .description("Linear 1-sigma error or an altitude range about the point in meters") + .uomCode("m") + .build(); + } + + public Text createRmkSrc(){ + return createText() + .name("source") + .label("Source") + .definition(SWEHelper.getPropertyUri("Remarks Source")) + .description("OpenSensorHub") + .build(); + } + + /** + * Creates a geodetic latitude field (WGS84 datum, degrees) + * @return A builder to set other options and build the final quantity + */ + public QuantityBuilder createLatitude() + { + return createQuantity() + .definition(DEF_LATITUDE_GEODETIC) + .refFrame(SWEConstants.REF_FRAME_4326) + .label("Geodetic Latitude") + .axisId("Lat") + .uomCode("deg"); + } + + + /** + * Creates a longitude field (WGS84 datum, degrees) + * @return A builder to set other options and build the final quantity + */ + public QuantityBuilder createLongitude() + { + return createQuantity() + .definition(DEF_LONGITUDE) + .refFrame(SWEConstants.REF_FRAME_4326) + .label("Longitude") + .axisId("Lon") + .uomCode("deg"); + } + + + /** + * Creates an ellipsoidal height field, also called altitude above ellipsoid (WGS84 datum, meters) + * @return A builder to set other options and build the final quantity + */ + public QuantityBuilder createAltitudeWGS84() + { + return createQuantity() + .definition(DEF_ALTITUDE_ELLIPSOID) + .refFrame(SWEConstants.REF_FRAME_WGS84_HAE) + .label("Ellipsoidal Height") + .description("Altitude above WGS84 ellipsoid") + .uom("m"); + } + + + /** + * Creates an MSL altitude field (approximate MSL datum, meters) + * @return A builder to set other options and build the final quantity + */ + public QuantityBuilder createAltitudeMSL() + { + return createQuantity() + .definition(DEF_ALTITUDE_MSL) + .refFrame(SWEConstants.VERTICAL_CRS_MSL_HEIGHT) + .label("MSL Height") + .description("Altitude above mean sea level (approximate datum)") + .uom("m"); + } + + + /** + * Creates a 3D location vector with latitude/longitude/altitude axes and WGS84 datum (EPSG 4979) + * @return A builder to set other options and build the final vector + */ + public VectorBuilder createLocationVectorLLA() + { + return createVector() + .definition(DEF_LOCATION) + .refFrame(SWEConstants.REF_FRAME_WGS84_HAE) + .addCoordinate("lat", createLatitude() + .refFrame(null)) + .addCoordinate("lon", createLongitude() + .refFrame(null)) + .addCoordinate("alt", createAltitudeWGS84() + .refFrame(null) + .axisId("h")); + } + + + /** + * Creates a 3D location vector with latitude/longitude/altitude axes and WGS84 datum (EPSG 4979) + * @param def semantic definition of location vector (if null, {@link #DEF_LOCATION} is used) + * @return the new Vector component object + */ + public Vector newLocationVectorLLA(String def) + { + return createLocationVectorLLA() + .definition(def != null ? def : DEF_LOCATION) + .build(); + } + + + /** + * Creates a 3D location vector with latitude/longitude on WGS84 datum (EPSG 4326) + * and MSL altitude (EPSG 5714) + * @return A builder to set other options and build the final vector + */ + public VectorBuilder createLocationVectorLLA_MSL() + { + return createVector() + .definition(DEF_LOCATION) + .refFrame(SWEConstants.REF_FRAME_WGS84_MSL) + .addCoordinate("lat", createLatitude() + .refFrame(null)) + .addCoordinate("lon", createLongitude() + .refFrame(null)) + .addCoordinate("alt", createAltitudeMSL() + .refFrame(null) + .axisId("h")); + } + + + /** + * Creates a 3D location vector with latitude/longitude on WGS84 datum (EPSG 4326) + * and MSL altitude (EPSG 5714) + * @param def semantic definition of location vector (if null, {@link #DEF_LOCATION} is used) + * @return the new Vector component object + */ + public Vector newLocationVectorLLA_MSL(String def) + { + return createLocationVectorLLA_MSL() + .definition(def != null ? def : DEF_LOCATION) + .build(); + } + + + /** + * Creates a 2D location vector with latitude/longitude axes (EPSG 4326) + * @return A builder to set other options and build the final vector + */ + public VectorBuilder createLocationVectorLatLon() + { + return createVector() + .definition(DEF_LOCATION) + .refFrame(SWEConstants.REF_FRAME_4326) + .addCoordinate("lat", createLatitude() + .refFrame(null)) + .addCoordinate("lon", createLongitude() + .refFrame(null)); + } + + + /** + * @see #createLocationVectorLatLon(String) + * @param def semantic definition of location vector (if null, {@link #DEF_LOCATION} is used) + * @return the new Vector component object + */ + public Vector newLocationVectorLatLon(String def) + { + return createLocationVectorLatLon() + .definition(def != null ? def : DEF_LOCATION) + .build(); + } + + + /** + * Creates a 3D location vector with ECEF X/Y/Z axes (EPSG 4978) + * @param uomCode unit of distance to use on all 3 axes + * @return A builder to set other options and build the final vector + */ + public VectorBuilder createLocationVectorECEF(String uomCode) + { + return createLocationVectorXYZ(uomCode) + .refFrame(SWEConstants.REF_FRAME_WGS84_ECEF); + } + + + /** + * Creates a 3D location vector with ECEF X/Y/Z axes (EPSG 4978) + * @param def semantic definition of location vector (if null, {@link #DEF_LOCATION} is used) + * @param uomCode unit of distance to use on all 3 axes + * @return the new Vector component object + */ + public Vector newLocationVectorECEF(String def, String uomCode) + { + return newLocationVectorXYZ(def, SWEConstants.REF_FRAME_WGS84_ECEF, "m"); + } + + + /** + * Creates a 3D location vector with ECEF X/Y/Z axes (EPSG 4978), measured in meters + * @param def semantic definition of location vector (if null, {@link #DEF_LOCATION} is used) + * @return the new Vector component object + */ + public Vector newLocationVectorECEF(String def) + { + return newLocationVectorECEF(def, "m"); + } + + + /** + * Creates a 3D velocity vector with ECEF X/Y/Z axes (EPSG 4978) + * @param uomCode unit of velocity to use on all 3 axes + * @return A builder to set other options and build the final vector + */ + public VectorBuilder createVelocityVectorECEF(String uomCode) + { + return createVelocityVector(uomCode) + .refFrame(SWEConstants.REF_FRAME_WGS84_ECEF); + } + + + /** + * Creates a 3D velocity with ECEF X/Y/Z axes (EPSG 4978) + * @param def semantic definition of velocity vector (if null, {@link #DEF_VELOCITY} is used) + * @param uomCode unit of velocity to use on all 3 axes + * @return the new Vector component object + */ + public Vector newVelocityVectorECEF(String def, String uomCode) + { + return newVelocityVector(def, SWEConstants.REF_FRAME_WGS84_ECEF, uomCode); + } + + + /** + * Creates a 3D velocity vector with ENU X/Y/Z axes + * @param uomCode unit of velocity to use on all 3 axes + * @return A builder to set other options and build the final vector + */ + public VectorBuilder createVelocityVectorENU(String uomCode) + { + return createVelocityVector(uomCode) + .refFrame(SWEConstants.REF_FRAME_ENU); + } + + + /** + * Creates a 3D velocity with ENU X/Y/Z axes + * @param def semantic definition of velocity vector (if null, {@link #DEF_VELOCITY} is used) + * @param uomCode unit of velocity to use on all 3 axes + * @return the new Vector component object + */ + public Vector newVelocityVectorENU(String def, String uomCode) + { + return newVelocityVector(def, SWEConstants.REF_FRAME_ENU, uomCode); + } + + + /** + * Creates a 3D velocity vector with NED X/Y/Z axes + * @param uomCode unit of velocity to use on all 3 axes + * @return A builder to set other options and build the final vector + */ + public VectorBuilder createVelocityVectorNED(String uomCode) + { + return createVelocityVector(uomCode) + .refFrame(SWEConstants.REF_FRAME_NED); + } + + + /** + * Creates a 3D velocity with NED X/Y/Z axes + * @param def semantic definition of velocity vector (if null, {@link #DEF_VELOCITY} is used) + * @param uomCode unit of velocity to use on all 3 axes + * @return the new Vector component object + */ + public Vector newVelocityVectorNED(String def, String uomCode) + { + return newVelocityVector(def, SWEConstants.REF_FRAME_NED, uomCode); + } + + + /** + * Creates a 3D orientation vector composed of 3 Euler angles expressed in a local + * frame (order of rotations is yaw/Z, pitch/X, roll/Y in rotating frame) + * @param uomCode angular unit to use on all 3 axes + * @return A builder to set other options and build the final vector + */ + public VectorBuilder createEulerOrientationYPR(String uomCode) + { + if (uomCode == null) + uomCode = "deg"; + + return createVector() + .definition(DEF_ORIENTATION_EULER) + .description("Euler angles with order of rotation yaw/pitch/roll in rotating frame") + .dataType(DataType.FLOAT) + .addCoordinate("yaw", createQuantity() + .definition(DEF_YAW_ANGLE) + .label("Yaw Angle") + .uomCode(uomCode) + .axisId("Z") + .build()) + .addCoordinate("pitch", createQuantity() + .definition(DEF_PITCH_ANGLE) + .label("Pitch Angle") + .uomCode(uomCode) + .axisId("X") + .build()) + .addCoordinate("roll", createQuantity() + .definition(DEF_ROLL_ANGLE) + .label("Roll Angle") + .uomCode(uomCode) + .axisId("Y") + .build()); + } + + + /** + * Creates a 3D orientation vector composed of 3 Euler angles expressed in local + * East-North-Up (ENU) frame (order of rotations is heading/Z, pitch/X, roll/Y in rotating frame) + * @param uomCode angular unit to use on all 3 axes + * @return A builder to set other options and build the final vector + */ + public VectorBuilder createEulerOrientationENU(String uomCode) + { + if (uomCode == null) + uomCode = "deg"; + + return createVector() + .definition(DEF_ORIENTATION_EULER) + .description("Euler angles with order of rotation heading/pitch/roll in rotating frame") + .refFrame(SWEConstants.REF_FRAME_ENU) + .dataType(DataType.FLOAT) + .addCoordinate("heading", createQuantity() + .definition(DEF_HEADING_TRUE) + .label("Heading Angle") + .description("Heading angle from east direction, measured counter clockwise") + .uomCode(uomCode) + .axisId("Z") + .build()) + .addCoordinate("pitch", createQuantity() + .definition(DEF_PITCH_ANGLE) + .label("Pitch Angle") + .description("Rotation around the lateral axis, up/down from the local horizontal plane (positive when pointing up)") + .uomCode(uomCode) + .axisId("X") + .build()) + .addCoordinate("roll", createQuantity() + .definition(DEF_ROLL_ANGLE) + .label("Roll Angle") + .description("Rotation around the longitudinal axis") + .uomCode(uomCode) + .axisId("Y") + .build()); + } + + + /** + * Creates a 3D orientation vector composed of 3 Euler angles expressed in local + * East-North-Up (ENU) frame (order of rotations is heading/Z, pitch/X, roll/Y in rotating frame) + * @param def semantic definition of orientation vector (if null, {@link #DEF_ORIENTATION_EULER} is used) + * @param uomCode angular unit to use on all 3 axes + * @return the new Vector component object + */ + public Vector newEulerOrientationENU(String def, String uomCode) + { + return createEulerOrientationENU(uomCode) + .definition(def != null ? def : DEF_ORIENTATION_EULER) + .build(); + } + + + /** + * Creates a 3D orientation vector composed of 3 Euler angles expressed in local + * North-East-Down (NED) frame (order of rotations is heading/Z, pitch/Y, roll/X in rotating frame) + * @param uomCode angular unit to use on all 3 axes + * @return A builder to set other options and build the final vector + */ + public VectorBuilder createEulerOrientationNED(String uomCode) + { + if (uomCode == null) + uomCode = "deg"; + + return createVector() + .definition(DEF_ORIENTATION_EULER) + .description("Euler angles with order of rotation heading/pitch/roll in rotating frame") + .refFrame(SWEConstants.REF_FRAME_NED) + .dataType(DataType.FLOAT) + .addCoordinate("heading", createQuantity() + .definition(DEF_HEADING_TRUE) + .label("Heading Angle") + .description("Heading angle from true north, measured clockwise") + .uomCode(uomCode) + .axisId("Z") + .build()) + .addCoordinate("pitch", createQuantity() + .definition(DEF_PITCH_ANGLE) + .label("Pitch Angle") + .description("Rotation around the lateral axis, up/down from the local horizontal plane (positive when pointing up)") + .uomCode(uomCode) + .axisId("Y") + .build()) + .addCoordinate("roll", createQuantity() + .definition(DEF_ROLL_ANGLE) + .label("Roll Angle") + .description("Rotation around the longitudinal axis") + .uomCode(uomCode) + .axisId("X") + .build()); + } + + + /** + * Creates a 3D orientation vector composed of 3 Euler angles expressed in local + * North-East-Down (NED) frame (order of rotations is heading/Z, pitch/Y, roll/X in rotating frame) + * @param def semantic definition of orientation vector (if null, {@link #DEF_ORIENTATION_EULER} is used) + * @param uomCode angular unit to use on all 3 axes + * @return the new Vector component object + */ + public Vector newEulerOrientationNED(String def, String uomCode) + { + return createEulerOrientationNED(uomCode) + .definition(def != null ? def : DEF_ORIENTATION_EULER) + .build(); + } + + + /** + * Default version of {@link #newEulerOrientationNED(String, String)} with + * units set to degrees + * @param def + * @return the new Vector component object + */ + public Vector newEulerOrientationNED(String def) + { + return newEulerOrientationNED(def, "deg"); + } + + + /** + * Creates an orientation vector component composed of 3 Euler angles expressed in + * Earth-Centered-Earth-Fixed (ECEF) frame (order of rotations is X, Y, Z) + * @param uomCode angular unit to use on all 3 axes + * @return A builder to set other options and build the final vector + */ + public VectorBuilder createEulerOrientationECEF(String uomCode) + { + if (uomCode == null) + uomCode = "deg"; + + return createVector() + .definition(DEF_ORIENTATION_EULER) + .description("Euler angles with order of rotation Z/Y/X in rotating frame") + .refFrame(SWEConstants.REF_FRAME_NED) + .dataType(DataType.FLOAT) + .addCoordinate("rz", createQuantity() + .definition(DEF_ANGLE) + .label("Z Rotation") + .uomCode(uomCode) + .axisId("Z") + .build()) + .addCoordinate("ry", createQuantity() + .definition(DEF_ANGLE) + .label("Y Rotation") + .uomCode(uomCode) + .axisId("Y") + .build()) + .addCoordinate("rx", createQuantity() + .definition(DEF_ANGLE) + .label("X Rotation") + .uomCode(uomCode) + .axisId("X") + .build()); + } + + + /** + * Creates an orientation vector component composed of 3 Euler angles expressed in + * Earth-Centered-Earth-Fixed (ECEF) frame (order of rotations is X, Y, Z) + * @param def semantic definition of orientation vector (if null, {@link #DEF_ORIENTATION_EULER} is used) + * @param uomCode angular unit to use on all 3 axes + * @return the new Vector component object + */ + public Vector newEulerOrientationECEF(String def, String uomCode) + { + return createEulerOrientationECEF(uomCode) + .definition(def != null ? def : DEF_ORIENTATION_EULER) + .build(); + } + + + /** + * Creates a 4d vector representing an orientation quaternion expressed in the given frame (scalar comes last). + * @param def semantic definition of orientation vector (if null, {@link #DEF_ORIENTATION_QUAT} is used) + * @param refFrame reference frame with respect to which the coordinates of this quaternion are expressed + * @return A builder to set other options and build the final vector + */ + public VectorBuilder createQuatOrientation() + { + return createVector() + .definition(DEF_ORIENTATION_QUAT) + .description("Orientation quaternion, usually normalized") + .dataType(DataType.FLOAT) + .addCoordinate("qx", createQuantity() + .definition(SWEConstants.DEF_COEF) + .label("X Component") + .uomCode("1") + .axisId("X") + .build()) + .addCoordinate("qy", createQuantity() + .definition(SWEConstants.DEF_COEF) + .label("Y Component") + .uomCode("1") + .axisId("Y") + .build()) + .addCoordinate("qz", createQuantity() + .definition(SWEConstants.DEF_COEF) + .label("Z Component") + .uomCode("1") + .axisId("Z") + .build()) + .addCoordinate("q0", createQuantity() + .definition(SWEConstants.DEF_COEF) + .label("Scalar Component") + .uomCode("1") + .build()); + } + + + /** + * Creates a 4d vector representing an orientation quaternion expressed in the given frame (scalar comes last). + * @param def semantic definition of orientation vector (if null, {@link #DEF_ORIENTATION_QUAT} is used) + * @param refFrame reference frame with respect to which the coordinates of this quaternion are expressed + * @return the new Vector component object + */ + public Vector newQuatOrientation(String def, String refFrame) + { + return createQuatOrientation() + .definition(def != null ? def : DEF_ORIENTATION_QUAT) + .refFrame(refFrame) + .build(); + } + + + /** + * Creates a 4d vector representing an orientation quaternion expressed in ENU frame. + * @return A builder to set other options and build the final vector + */ + public VectorBuilder createQuatOrientationENU() + { + return createQuatOrientation() + .refFrame(SWEConstants.REF_FRAME_ENU); + } + + + /** + * Creates a 4d vector representing an orientation quaternion expressed in ENU frame. + * @param def semantic definition of orientation vector (if null, {@link #DEF_ORIENTATION_QUAT} is used) + * @return the new Vector component object + */ + public Vector newQuatOrientationENU(String def) + { + return newQuatOrientation(def, SWEConstants.REF_FRAME_ENU); + } + + + /** + * Creates a 4d vector representing an orientation quaternion expressed in NED frame. + * @return A builder to set other options and build the final vector + */ + public VectorBuilder createQuatOrientationNED() + { + return createQuatOrientation() + .refFrame(SWEConstants.REF_FRAME_NED); + } + + + /** + * Creates a 4d vector representing an orientation quaternion expressed in NED frame. + * @param def semantic definition of orientation vector (if null, {@link #DEF_ORIENTATION_QUAT} is used) + * @return the new Vector component object + */ + public Vector newQuatOrientationNED(String def) + { + return newQuatOrientation(def, SWEConstants.REF_FRAME_NED); + } + + + /** + * Creates a 4d vector representing an orientation quaternion expressed in ECEF frame. + * @return A builder to set other options and build the final vector + */ + public VectorBuilder createQuatOrientationECEF() + { + return createQuatOrientation() + .refFrame(SWEConstants.REF_FRAME_WGS84_ECEF); + } + + + /** + * Creates a 4d vector representing an orientation quaternion expressed in ECEF frame. + * @param def semantic definition of orientation vector (if null, {@link #DEF_ORIENTATION_QUAT} is used) + * @return the new Vector component object + */ + public Vector newQuatOrientationECEF(String def) + { + return newQuatOrientation(def, SWEConstants.REF_FRAME_WGS84_ECEF); + } +} diff --git a/sensorhub-service-consys/build.gradle b/sensorhub-service-consys/build.gradle index a9fbdf7c01..68adc7882f 100644 --- a/sensorhub-service-consys/build.gradle +++ b/sensorhub-service-consys/build.gradle @@ -10,6 +10,7 @@ dependencies { testImplementation project(':sensorhub-datastore-h2') testImplementation 'commons-io:commons-io:1.3.2' testImplementation 'org.jglue.fluent-json:fluent-json:2.0.3' + implementation 'com.google.protobuf:protobuf-java:3.25.1' } test { diff --git a/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/RootHandler.java b/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/RootHandler.java index eaccc5636a..28156cd249 100644 --- a/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/RootHandler.java +++ b/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/RootHandler.java @@ -19,6 +19,8 @@ import org.sensorhub.impl.service.consys.resource.IResourceHandler; import org.sensorhub.impl.service.consys.resource.RequestContext; +import javax.xml.stream.XMLStreamException; + public class RootHandler extends BaseHandler { @@ -36,8 +38,7 @@ public RootHandler(HomePageHandler homePage, boolean readOnly) @Override - public void doGet(RequestContext ctx) throws IOException - { + public void doGet(RequestContext ctx) throws IOException, XMLStreamException { IResourceHandler resource = ctx.isEndOfPath() ? homePage : getSubResource(ctx); diff --git a/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/SWECommonUtils.java b/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/SWECommonUtils.java index e5d2f4c8ff..8cb7c1a616 100644 --- a/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/SWECommonUtils.java +++ b/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/SWECommonUtils.java @@ -102,7 +102,7 @@ else if (format.isOneOf(ResourceFormat.SWE_TEXT, ResourceFormat.TEXT_PLAIN, Reso { return new TextEncodingImpl(); } - else if (format.isOneOf(ResourceFormat.SWE_XML, ResourceFormat.TEXT_XML)) + else if (format.isOneOf(ResourceFormat.SWE_XML, ResourceFormat.TEXT_XML, ResourceFormat.COT_XML)) { return new XMLEncodingImpl(); } @@ -118,7 +118,7 @@ else if (format.isOneOf(ResourceFormat.SWE_TEXT, ResourceFormat.TEXT_PLAIN, Reso { return defaultEncoding instanceof TextEncoding ? defaultEncoding : new TextEncodingImpl(); } - else if (format.isOneOf(ResourceFormat.SWE_XML, ResourceFormat.TEXT_XML)) + else if (format.isOneOf(ResourceFormat.SWE_XML, ResourceFormat.TEXT_XML, ResourceFormat.COT_XML)) { return new XMLEncodingImpl(); } @@ -216,7 +216,11 @@ public static Collection getAvailableFormats(IDataStreamInfo dsInfo, Map formatList.add(ResourceFormat.SWE_JSON.getMimeType()); formatList.add(ResourceFormat.SWE_TEXT.getMimeType()); formatList.add(ResourceFormat.SWE_XML.getMimeType()); + formatList.add(ResourceFormat.COT_XML.getMimeType()); } + formatList.add(ResourceFormat.PROTOBUF.getMimeType()); + + formatList.add(ResourceFormat.GEO_JSON.getMimeType()); formatList.add(ResourceFormat.SWE_BINARY.getMimeType()); diff --git a/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/feature/AbstractFeatureHistoryHandler.java b/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/feature/AbstractFeatureHistoryHandler.java index 35c0685b14..44e4ceda97 100644 --- a/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/feature/AbstractFeatureHistoryHandler.java +++ b/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/feature/AbstractFeatureHistoryHandler.java @@ -36,6 +36,8 @@ import org.slf4j.LoggerFactory; import org.vast.ogc.gml.IFeature; +import javax.xml.stream.XMLStreamException; + public abstract class AbstractFeatureHistoryHandler< V extends IFeature, @@ -70,8 +72,7 @@ public void doPut(RequestContext ctx) throws IOException @Override - protected void getById(final RequestContext ctx, final String id) throws IOException - { + protected void getById(final RequestContext ctx, final String id) throws IOException, XMLStreamException { // check permissions var parentId = ctx.getParentRef().id; ctx.getSecurityHandler().checkParentPermission(permissions.get, parentId); diff --git a/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/home/CollectionHandler.java b/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/home/CollectionHandler.java index e2c6499434..52d67bcf1e 100644 --- a/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/home/CollectionHandler.java +++ b/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/home/CollectionHandler.java @@ -34,6 +34,8 @@ import org.sensorhub.impl.service.consys.system.SystemHandler; import org.vast.swe.SWEConstants; +import javax.xml.stream.XMLStreamException; + public class CollectionHandler extends BaseHandler { @@ -117,8 +119,7 @@ public String[] getNames() @Override - public void doGet(RequestContext ctx) throws InvalidRequestException, IOException, SecurityException - { + public void doGet(RequestContext ctx) throws InvalidRequestException, IOException, SecurityException, XMLStreamException { // check permissions //ctx.getSecurityHandler().checkPermission(permissions.read); @@ -183,8 +184,7 @@ protected void addItemsLink(String title, String path, Set links) } - void list(RequestContext ctx) throws IOException - { + void list(RequestContext ctx) throws IOException, XMLStreamException { var binding = getBinding(ctx, false); binding.startCollection(); @@ -222,8 +222,7 @@ void list(RequestContext ctx) throws IOException } - void getById(RequestContext ctx, String id) throws IOException - { + void getById(RequestContext ctx, String id) throws IOException, XMLStreamException { var binding = getBinding(ctx, false); var col = allCollections.get(id); diff --git a/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/obs/DataStreamSchemaHandler.java b/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/obs/DataStreamSchemaHandler.java index e648673a13..9c2c478ec0 100644 --- a/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/obs/DataStreamSchemaHandler.java +++ b/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/obs/DataStreamSchemaHandler.java @@ -32,6 +32,8 @@ import org.sensorhub.impl.service.consys.resource.RequestContext.ResourceRef; import org.vast.util.Asserts; +import javax.xml.stream.XMLStreamException; + public class DataStreamSchemaHandler extends ResourceHandler { @@ -98,8 +100,7 @@ public void doDelete(final RequestContext ctx) throws IOException @Override - public void doGet(RequestContext ctx) throws IOException - { + public void doGet(RequestContext ctx) throws IOException, XMLStreamException { if (ctx.isEndOfPath()) getById(ctx, ""); else @@ -108,8 +109,7 @@ public void doGet(RequestContext ctx) throws IOException @Override - protected void getById(final RequestContext ctx, final String id) throws IOException - { + protected void getById(final RequestContext ctx, final String id) throws IOException, XMLStreamException { // check permissions var parentId = ctx.getParentRef().id; ctx.getSecurityHandler().checkParentPermission(permissions.get, parentId); diff --git a/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/obs/ObsBindingCotXml.java b/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/obs/ObsBindingCotXml.java new file mode 100644 index 0000000000..3374343ac4 --- /dev/null +++ b/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/obs/ObsBindingCotXml.java @@ -0,0 +1,296 @@ +/***************************** BEGIN LICENSE BLOCK *************************** + +The contents of this file are subject to the Mozilla Public License, v. 2.0. +If a copy of the MPL was not distributed with this file, You can obtain one +at http://mozilla.org/MPL/2.0/. + +Software distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +for the specific language governing rights and limitations under the License. + +Copyright (C) 2020 Sensia Software LLC. All Rights Reserved. + +******************************* END LICENSE BLOCK ***************************/ + +package org.sensorhub.impl.service.consys.obs; + +import com.google.common.collect.Sets; +import net.opengis.OgcPropertyList; +import net.opengis.swe.v20.DataComponent; +import org.sensorhub.api.common.BigId; +import org.sensorhub.api.common.IdEncoders; +import org.sensorhub.api.data.IDataStreamInfo; +import org.sensorhub.api.data.IObsData; +import org.sensorhub.api.data.ObsData; +import org.sensorhub.api.datastore.obs.DataStreamKey; +import org.sensorhub.api.datastore.obs.IObsStore; +import org.sensorhub.impl.service.consys.obs.ObsHandler.ObsHandlerContextData; +import org.sensorhub.impl.service.consys.resource.*; +import org.sensorhub.utils.SWEDataUtils; +import org.vast.data.AbstractDataBlock; +import org.vast.data.DataBlockMixed; +import org.vast.data.DataRecordImpl; +import org.vast.data.XMLEncodingImpl; +import org.vast.swe.SWEConstants; +import org.vast.swe.ScalarIndexer; +import org.vast.swe.fast.*; +import org.vast.swe.helper.GeoPosHelper; +import org.vast.xml.DOMHelper; +import net.opengis.swe.v20.DataRecord; +import javax.xml.stream.XMLOutputFactory; +import javax.xml.stream.XMLStreamException; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.time.OffsetDateTime; +import java.util.*; + +import static org.sensorhub.impl.service.consys.SWECommonUtils.OM_COMPONENTS_FILTER; + + +public class ObsBindingCotXml extends ResourceBindingCotXml +{ + ObsHandlerContextData contextData; + IObsStore obsStore; + XmlDataParser resultReader; + Map resultWriters; + DOMHelper dom; + ScalarIndexer timeStampIndexer; + XMLOutputFactory factory = XMLOutputFactory.newInstance(); + OutputStream os = ctx.getOutputStream(); + protected DataRecord dataRec; + + private static final Set LOCATION_DEFINITIONS = Sets.newHashSet( + SWEConstants.DEF_SENSOR_LOC, + SWEConstants.DEF_PLATFORM_LOC, + SWEConstants.DEF_SAMPLING_LOC, + GeoPosHelper.DEF_LOCATION + ); + + protected ObsBindingCotXml(RequestContext ctx, IdEncoders idEncoders, boolean forReading, IObsStore obsStore) throws IOException, XMLStreamException { + super(ctx, idEncoders, forReading); + this.contextData = (ObsHandlerContextData)ctx.getData(); + this.obsStore = obsStore; + + dom = new DOMHelper(); + + if (forReading) + { + var inputStream = ctx.getInputStream(); + resultReader = getSweCommonParser(contextData.dsInfo, inputStream); + resultReader.setRenewDataBlock(true); + timeStampIndexer = SWEDataUtils.getTimeStampIndexer(contextData.dsInfo.getRecordStructure()); + + } + else + { + this.resultWriters = new HashMap<>(); + + // init result writer only in case of single datastream + // otherwise we'll do it later + if (contextData != null && contextData.dsInfo != null) + { + var resultWriter = getSweCommonWriter(contextData.dsInfo, os); + resultWriters.put(ctx.getParentID(), resultWriter); + } + } + } + + @Override + public IObsData deserialize(CotDataReader xmlReader) throws IOException { + var obs = new ObsData.Builder() + .withDataStream(contextData.dsID); + var newObs = obs.build(); + return newObs; + } + + @Override + public void serialize(BigId key, IObsData obs, boolean showLinks, CotDataWriter xmlWriter) throws IOException, XMLStreamException { + Set locationComponents = new HashSet<>(); + var dataStream = this.obsStore.getDataStreams().get(new DataStreamKey(obs.getDataStreamID())); + + OgcPropertyList recordStruct = null; + AbstractDataBlock[] resultBlock = null; + + + for (int i = 0; i < dataStream.getRecordStructure().getComponentCount(); i++) { + var component = dataStream.getRecordStructure().getComponent(i); + if (LOCATION_DEFINITIONS.contains(component.getDefinition())) { + // This is how we know we have location components in the data structure + // So we can save this and parse specifically the location components into GeoJSON + locationComponents.add(i); + } + } + + recordStruct = ((DataRecordImpl) dataStream.getRecordStructure()).getFieldList(); + + resultBlock = ((DataBlockMixed) obs.getResult()).getUnderlyingObject(); + + int i = 0; + + Map unmatchedData = new HashMap<>(); + Map pointData = new HashMap<>(); + Map eventData = new HashMap<>(); + Map remarksData = new HashMap<>(); + + xmlWriter.writeCotAttribute("version", "2.0"); + + for (AbstractDataBlock abstractResultBlock : resultBlock) { + String value = abstractResultBlock.getStringValue(); + String fieldName = recordStruct.get(i).getName(); + + OffsetDateTime timeResult = null; + + switch (fieldName) { + case "version": // event + eventData.put("version", "2.0"); + break; + case "type": // event + eventData.put("type", value); + break; + case "uuid", "uid": // event + eventData.put("uid", value); + break; + case "time": // event + timeResult = abstractResultBlock.getDateTime(); + eventData.put("time", timeResult.toString()); + break; + case "start": // event + timeResult = abstractResultBlock.getDateTime(); + eventData.put("start time", timeResult.toString()); + break; + case "stale": // event + timeResult = abstractResultBlock.getDateTime().plusYears(1); + eventData.put("stale time", timeResult.toString()); + break; + case "how": // event + eventData.put("how", value); + break; + case "ce": // point + pointData.put("ce", value); + break; + case "hae": // point + pointData.put("hae", value); + break; + case "le": // point + pointData.put("le", value); + break; + case "source": // remarks + remarksData.put("source", value); + break; + case "location": // point + var locationBlockCount = abstractResultBlock.getAtomCount(); + String lat, lon, alt; + if (locationBlockCount == 2) { + lat = resultBlock[i].getStringValue(0); + lon = resultBlock[i].getStringValue(1); + + pointData.put("lat", lat); + pointData.put("lon", lon); + break; + } else if (locationBlockCount == 3) { + lat = resultBlock[i].getStringValue(0); + lon = resultBlock[i].getStringValue(0); + alt = resultBlock[i].getStringValue(0); + + pointData.put("lat", lat); + pointData.put("lon", lon); + pointData.put("alt", alt); + break; + } else { + break; + } + default: + unmatchedData.put(fieldName, value); + } + i++; + } + + eventData.entrySet().forEach(entry -> { + try { + xmlWriter.writeCotAttribute(entry.getKey(), entry.getValue()); + } catch (XMLStreamException e) { + throw new RuntimeException(e); + } + }); + + cotWriter.writeCotStartElement("detail"); + unmatchedData.entrySet().forEach(entry -> { + try { + xmlWriter.writeCotAttribute(entry.getKey(), entry.getValue()); + } catch (XMLStreamException e) { + throw new RuntimeException(e); + } + }); + + cotWriter.writeCotStartElement("remarks"); + remarksData.entrySet().forEach(entry -> { + try { + xmlWriter.writeCotAttribute(entry.getKey(), entry.getValue()); + } catch (XMLStreamException e) { + throw new RuntimeException(e); + } + }); + cotWriter.writeCotEndElement(); + + cotWriter.writeCotEndElement(); + + cotWriter.writeCotStartElement("point"); + pointData.entrySet().forEach(entry -> { + try { + xmlWriter.writeCotAttribute(entry.getKey(), entry.getValue()); + } catch (XMLStreamException e) { + throw new RuntimeException(e); + } + }); + cotWriter.writeCotEndElement(); + + cotWriter.endStream(); + } + + + protected CotDataWriter getCotWriter(OutputStream os) throws IOException { + var writer = super.getCotWriter(os); + writer.setSerializeNulls(true); + return writer; + } + + protected AbstractDataWriter getSweCommonWriter(BigId dsID, OutputStream os) throws IOException { + var dsInfo = obsStore.getDataStreams().get(new DataStreamKey(dsID)); + + return getSweCommonWriter(dsInfo, os); + } + + protected AbstractDataWriter getSweCommonWriter(IDataStreamInfo dsInfo, OutputStream os) throws IOException { + CotDataWriter dataWriter = new CotDataWriter(); + + dataWriter.setDataEncoding(new XMLEncodingImpl()); + dataWriter.setOutput(os); + dataWriter.setDataComponents(dsInfo.getRecordStructure()); + + // filter out components that are already included in O&M + dataWriter.setDataComponentFilter(OM_COMPONENTS_FILTER); + return dataWriter; + } + + protected XmlDataParser getSweCommonParser(IDataStreamInfo dsInfo, InputStream is) throws IOException { + // create XML SWE parser + var sweParser = new XmlDataParser(); + sweParser.setDataComponents(dsInfo.getRecordStructure()); + + // filter out components that are already included in O&M + sweParser.setDataComponentFilter(OM_COMPONENTS_FILTER); + sweParser.setInput(is); + return sweParser; + } + + @Override + public void startCollection() throws XMLStreamException, IOException { + super.startCollection(); + } + + @Override + public void endCollection(Collection links) throws IOException, XMLStreamException { + super.endCollection(links); + } +} diff --git a/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/obs/ObsBindingGeoJson.java b/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/obs/ObsBindingGeoJson.java new file mode 100644 index 0000000000..4e132d2451 --- /dev/null +++ b/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/obs/ObsBindingGeoJson.java @@ -0,0 +1,322 @@ +/***************************** BEGIN LICENSE BLOCK *************************** + +The contents of this file are subject to the Mozilla Public License, v. 2.0. +If a copy of the MPL was not distributed with this file, You can obtain one +at http://mozilla.org/MPL/2.0/. + +Software distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +for the specific language governing rights and limitations under the License. + +Copyright (C) 2020 Sensia Software LLC. All Rights Reserved. + +******************************* END LICENSE BLOCK ***************************/ + +package org.sensorhub.impl.service.consys.obs; + +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonToken; +import com.google.gson.stream.JsonWriter; +import org.sensorhub.api.common.BigId; +import org.sensorhub.api.common.IdEncoders; +import org.sensorhub.api.data.IDataStreamInfo; +import org.sensorhub.api.data.IObsData; +import org.sensorhub.api.data.ObsData; +import org.sensorhub.api.datastore.obs.DataStreamKey; +import org.sensorhub.api.datastore.obs.IObsStore; +import org.sensorhub.impl.service.consys.ResourceParseException; +import org.sensorhub.impl.service.consys.SWECommonUtils; +import org.sensorhub.impl.service.consys.ServiceErrors; +import org.sensorhub.impl.service.consys.obs.ObsHandler.ObsHandlerContextData; +import org.sensorhub.impl.service.consys.resource.PropertyFilter; +import org.sensorhub.impl.service.consys.resource.RequestContext; +import org.sensorhub.impl.service.consys.resource.ResourceBindingJson; +import org.sensorhub.impl.service.consys.resource.ResourceLink; +import org.sensorhub.utils.SWEDataUtils; +import org.sensorhub.api.datastore.feature.IFoiStore; +import org.vast.data.DataBlockMixed; +import org.vast.ogc.gml.IFeature; + +import org.vast.cdm.common.DataStreamWriter; +import org.vast.swe.BinaryDataWriter; +import org.vast.swe.SWEConstants; +import org.vast.swe.ScalarIndexer; +import org.vast.swe.fast.JsonDataParserGson; +import org.vast.swe.fast.JsonDataWriterGson; +import org.vast.swe.helper.GeoPosHelper; +import org.vast.util.ReaderException; + +import java.io.IOException; +import java.io.OutputStream; +import java.time.OffsetDateTime; +import java.time.format.DateTimeParseException; +import java.util.*; + +import org.locationtech.jts.geom.Geometry; +import org.locationtech.jts.geom.Point; +import org.locationtech.jts.geom.Coordinate; + +import org.sensorhub.api.datastore.EmptyFilterIntersection; +import com.google.common.collect.Sets; + + +import static org.sensorhub.impl.service.consys.SWECommonUtils.OM_COMPONENTS_FILTER; + + +public class ObsBindingGeoJson extends ResourceBindingJson +{ + ObsHandlerContextData contextData; + IObsStore obsStore; + JsonDataParserGson resultReader; + Map resultWriters; + ScalarIndexer timeStampIndexer; + + IFoiStore foiStore; + + private static final Set LOCATION_DEFINITIONS = Sets.newHashSet( + SWEConstants.DEF_SENSOR_LOC, + SWEConstants.DEF_PLATFORM_LOC, + SWEConstants.DEF_SAMPLING_LOC, + GeoPosHelper.DEF_LOCATION + ); + + + public ObsBindingGeoJson(RequestContext ctx, IdEncoders idEncoders, boolean forReading, IObsStore obsStore) throws IOException + { + super(ctx, idEncoders, forReading); + this.contextData = (ObsHandlerContextData)ctx.getData(); + this.obsStore = obsStore; + + if (forReading) + { + resultReader = getSweCommonParser(contextData.dsInfo, reader); + resultReader.setRenewDataBlock(true); + timeStampIndexer = SWEDataUtils.getTimeStampIndexer(contextData.dsInfo.getRecordStructure()); + } + else + { + this.resultWriters = new HashMap<>(); + + // init result writer only in case of single datastream + // otherwise we'll do it later + if (contextData != null && contextData.dsInfo != null) + { + var resultWriter = getSweCommonWriter(contextData.dsInfo, writer, ctx.getPropertyFilter()); + resultWriters.put(ctx.getParentID(), resultWriter); + } + } + } + + + @Override + public IObsData deserialize(JsonReader reader) throws IOException + { + // if array, prepare to parse first element + if (reader.peek() == JsonToken.BEGIN_ARRAY) + reader.beginArray(); + + if (reader.peek() == JsonToken.END_DOCUMENT || !reader.hasNext()) + return null; + + var obs = new ObsData.Builder() + .withDataStream(contextData.dsID); + + try + { + reader.beginObject(); + + while (reader.hasNext()) + { + var propName = reader.nextName(); + + if ("phenomenonTime".equals(propName)) + obs.withPhenomenonTime(OffsetDateTime.parse(reader.nextString()).toInstant()); + else if ("resultTime".equals(propName)) + obs.withResultTime(OffsetDateTime.parse(reader.nextString()).toInstant()); + else if ("foi@id".equals(propName)) + { + try + { + var foiID = idEncoders.getFoiIdEncoder().decodeID(reader.nextString()); + obs.withFoi(foiID); + } + catch (IllegalArgumentException e) + { + throw ServiceErrors.badRequest("Invalid FOI ID"); + } + } + else if ("result".equals(propName)) + { + var result = resultReader.parseNextBlock(); + obs.withResult(result); + } + else + reader.skipValue(); + } + + reader.endObject(); + } + catch (DateTimeParseException e) + { + throw new ResourceParseException(INVALID_JSON_ERROR_MSG + "Invalid ISO8601 date/time at " + reader.getPath()); + } + catch (IllegalStateException | ReaderException e) + { + throw new ResourceParseException(INVALID_JSON_ERROR_MSG + e.getMessage()); + } + + if (contextData.foiId != null && contextData.foiId != BigId.NONE) + obs.withFoi(contextData.foiId); + + var newObs = obs.build(); + + // set timestamp in result data if present in schema + if (timeStampIndexer != null) + { + var phenomenonTimeIdx = timeStampIndexer.getDataIndex(newObs.getResult()); + newObs.getResult().setDoubleValue(phenomenonTimeIdx, newObs.getPhenomenonTime().toEpochMilli() / 1000.0); + } + + return newObs; + } + + // only shows anything if theres any lon/lat data + @Override + public void serialize(BigId key, IObsData obs, boolean showLinks, JsonWriter writer) throws IOException { + + Set locationComponents = new HashSet<>(); + + var dataStream = this.obsStore.getDataStreams().get(new DataStreamKey(obs.getDataStreamID())); + for (int i = 0; i < dataStream.getRecordStructure().getComponentCount(); i++) { + var component = dataStream.getRecordStructure().getComponent(i); + if (LOCATION_DEFINITIONS.contains(component.getDefinition())) { + // This is how we know we have location components in the data structure + // So we can save this and parse specifically the location components into GeoJSON + locationComponents.add(i); + } + } + + double altitude = 0; + double longitude = 0; + double latitude = 0; + + for (int index : locationComponents) { + var locationDataBlock = ((DataBlockMixed) obs.getResult()).getUnderlyingObject()[index]; + // You'll still need to check if these are real values and not null + latitude = locationDataBlock.getDoubleValue(0); + longitude = locationDataBlock.getDoubleValue(1); + altitude = locationDataBlock.getDoubleValue(2); //geojson format doesnt seem to have alt :? + } + + var obsId = idEncoders.getObsIdEncoder().encodeID(key); + + var resultWriter = resultWriters.computeIfAbsent(obs.getDataStreamID(), + k -> getSweCommonWriter(k, writer, ctx.getPropertyFilter()) ); + + var obsRes = obs.getResult().toString(); + + var obsName = dataStream.getOutputName(); + + if (!(longitude == 0.0 && latitude == 0.0)) { + writer.beginObject(); + writer.name("type").value("Feature"); + + writer.name("geometry"); + writer.beginObject(); + writer.name("type").value("Point"); + + writer.name("coordinates").value("[" + longitude + ", " + latitude + "]"); + + + writer.name("properties"); + // name, id, timestamp, whatever else + + writer.beginObject(); + writer.name("name").value(obsName); + writer.name("id").value(obsId); + writer.name("phenomenonTime").value(obs.getPhenomenonTime().toString()); + writer.name("resultTime").value(obs.getResultTime().toString()); + + // write if JSON is supported, otherwise print warning message +// if (resultWriter instanceof JsonDataWriterGson) +// resultWriter.write(obs.getResult()); +// else +// writer.value("Compressed binary result not shown in JSON"); + + writer.endObject(); + writer.endObject(); + writer.endObject(); + writer.flush(); + } + } + + + protected JsonWriter getJsonWriter(OutputStream os, PropertyFilter propFilter) throws IOException + { + var writer = super.getJsonWriter(os, propFilter); + writer.setSerializeNulls(true); + return writer; + } + + + protected DataStreamWriter getSweCommonWriter(BigId dsID, JsonWriter writer, PropertyFilter propFilter) + { + var dsInfo = obsStore.getDataStreams().get(new DataStreamKey(dsID)); + return getSweCommonWriter(dsInfo, writer, propFilter); + } + + + protected DataStreamWriter getSweCommonWriter(IDataStreamInfo dsInfo, JsonWriter writer, PropertyFilter propFilter) + { + if (!SWECommonUtils.allowNonBinaryFormat(dsInfo.getRecordStructure(), dsInfo.getRecordEncoding())) + return new BinaryDataWriter(); + + // create JSON SWE writer + var sweWriter = new JsonDataWriterGson(writer); + sweWriter.setDataComponents(dsInfo.getRecordStructure()); + + // filter out components that are already included in O&M + sweWriter.setDataComponentFilter(OM_COMPONENTS_FILTER); + return sweWriter; + } + + + protected JsonDataParserGson getSweCommonParser(IDataStreamInfo dsInfo, JsonReader reader) + { + // create JSON SWE parser + var sweParser = new JsonDataParserGson(reader); + sweParser.setDataComponents(dsInfo.getRecordStructure()); + + // filter out components that are already included in O&M + sweParser.setDataComponentFilter(OM_COMPONENTS_FILTER); + return sweParser; + } + + + @Override + public void startCollection() throws IOException + { + if (reader != null) { + // if we're reading, just skip to the items array + // calls to deserialize() will take it from there + // TODO generalize this to all bindings + reader.beginObject(); + while (reader.hasNext()) { + var propName = reader.nextName(); + if (propName.equals(getItemsPropertyName())) + return; + else + reader.skipValue(); + } + } + else + startJsonCollection(writer); + } + + + @Override + public void endCollection(Collection links) throws IOException + { + endJsonCollection(writer, links); + } +} diff --git a/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/obs/ObsBindingProtobuf.java b/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/obs/ObsBindingProtobuf.java new file mode 100644 index 0000000000..f2bc8c6046 --- /dev/null +++ b/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/obs/ObsBindingProtobuf.java @@ -0,0 +1,277 @@ +/***************************** BEGIN LICENSE BLOCK *************************** + + The contents of this file are subject to the Mozilla Public License, v. 2.0. + If a copy of the MPL was not distributed with this file, You can obtain one + at http://mozilla.org/MPL/2.0/. + + Software distributed under the License is distributed on an "AS IS" basis, + WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + for the specific language governing rights and limitations under the License. + + Copyright (C) 2020 Sensia Software LLC. All Rights Reserved. + + ******************************* END LICENSE BLOCK ***************************/ + +package org.sensorhub.impl.service.consys.obs; + +import com.google.common.collect.Sets; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonToken; +import com.google.gson.stream.JsonWriter; +import org.sensorhub.api.common.BigId; +import org.sensorhub.api.common.IdEncoders; +import org.sensorhub.api.data.IDataStreamInfo; +import org.sensorhub.api.data.IObsData; +import org.sensorhub.api.data.ObsData; +import org.sensorhub.api.datastore.feature.IFoiStore; +import org.sensorhub.api.datastore.obs.DataStreamKey; +import org.sensorhub.api.datastore.obs.IObsStore; +import org.sensorhub.impl.service.consys.ResourceParseException; +import org.sensorhub.impl.service.consys.SWECommonUtils; +import org.sensorhub.impl.service.consys.ServiceErrors; +import org.sensorhub.impl.service.consys.obs.ObsHandler.ObsHandlerContextData; +import org.sensorhub.impl.service.consys.resource.PropertyFilter; +import org.sensorhub.impl.service.consys.resource.RequestContext; +import org.sensorhub.impl.service.consys.resource.ResourceBindingJson; +import org.sensorhub.impl.service.consys.resource.ResourceLink; +import org.sensorhub.utils.SWEDataUtils; +import org.vast.cdm.common.DataStreamWriter; +import org.vast.data.DataBlockMixed; +import org.vast.data.DataRecordImpl; +import org.vast.swe.BinaryDataWriter; +import org.vast.swe.SWEConstants; +import org.vast.swe.ScalarIndexer; +import org.vast.swe.fast.JsonDataParserGson; +import org.vast.swe.fast.JsonDataWriterGson; +import org.vast.swe.helper.GeoPosHelper; +import org.vast.util.ReaderException; +import org.sensorhub.impl.service.consys.obs.proto.Observation.OshObservation; +import org.sensorhub.impl.service.consys.obs.proto.Observation.Results; +import org.vast.data.DataRecordImpl; + +import java.io.IOException; +import java.io.OutputStream; +import java.time.OffsetDateTime; +import java.time.format.DateTimeParseException; +import java.util.*; + + +import static org.sensorhub.impl.service.consys.SWECommonUtils.OM_COMPONENTS_FILTER; + + +public class ObsBindingProtobuf extends ResourceBindingJson +{ + ObsHandlerContextData contextData; + IObsStore obsStore; + JsonDataParserGson resultReader; + Map resultWriters; + ScalarIndexer timeStampIndexer; + IFoiStore foiStore; + + + private static final Set LOCATION_DEFINITIONS = Sets.newHashSet( + SWEConstants.DEF_SENSOR_LOC, + SWEConstants.DEF_PLATFORM_LOC, + SWEConstants.DEF_SAMPLING_LOC, + GeoPosHelper.DEF_LOCATION + ); + + + public ObsBindingProtobuf(RequestContext ctx, IdEncoders idEncoders, boolean forReading, IObsStore obsStore) throws IOException + { + super(ctx, idEncoders, forReading); + this.contextData = (ObsHandlerContextData)ctx.getData(); + this.obsStore = obsStore; + + if (forReading) + { + resultReader = getSweCommonParser(contextData.dsInfo, reader); + resultReader.setRenewDataBlock(true); + timeStampIndexer = SWEDataUtils.getTimeStampIndexer(contextData.dsInfo.getRecordStructure()); + } + else + { + this.resultWriters = new HashMap<>(); + + // init result writer only in case of single datastream + // otherwise we'll do it later + if (contextData != null && contextData.dsInfo != null) + { + var resultWriter = getSweCommonWriter(contextData.dsInfo, writer, ctx.getPropertyFilter()); + resultWriters.put(ctx.getParentID(), resultWriter); + } + } + } + + + @Override + public IObsData deserialize(JsonReader reader) throws IOException + { + // if array, prepare to parse first element + if (reader.peek() == JsonToken.BEGIN_ARRAY) + reader.beginArray(); + + if (reader.peek() == JsonToken.END_DOCUMENT || !reader.hasNext()) + return null; + + var obs = new ObsData.Builder() + .withDataStream(contextData.dsID); + + try + { + reader.beginObject(); + + while (reader.hasNext()) + { + var propName = reader.nextName(); + + if ("phenomenonTime".equals(propName)) + obs.withPhenomenonTime(OffsetDateTime.parse(reader.nextString()).toInstant()); + else if ("resultTime".equals(propName)) + obs.withResultTime(OffsetDateTime.parse(reader.nextString()).toInstant()); + else if ("foi@id".equals(propName)) + { + try + { + var foiID = idEncoders.getFoiIdEncoder().decodeID(reader.nextString()); + obs.withFoi(foiID); + } + catch (IllegalArgumentException e) + { + throw ServiceErrors.badRequest("Invalid FOI ID"); + } + } + else if ("result".equals(propName)) + { + var result = resultReader.parseNextBlock(); + obs.withResult(result); + } + else + reader.skipValue(); + } + + reader.endObject(); + } + catch (DateTimeParseException e) + { + throw new ResourceParseException(INVALID_JSON_ERROR_MSG + "Invalid ISO8601 date/time at " + reader.getPath()); + } + catch (IllegalStateException | ReaderException e) + { + throw new ResourceParseException(INVALID_JSON_ERROR_MSG + e.getMessage()); + } + + if (contextData.foiId != null && contextData.foiId != BigId.NONE) + obs.withFoi(contextData.foiId); + + var newObs = obs.build(); + + // set timestamp in result data if present in schema + if (timeStampIndexer != null) + { + var phenomenonTimeIdx = timeStampIndexer.getDataIndex(newObs.getResult()); + newObs.getResult().setDoubleValue(phenomenonTimeIdx, newObs.getPhenomenonTime().toEpochMilli() / 1000.0); + } + + return newObs; + } + + @Override + public void serialize(BigId key, IObsData obs, boolean showLinks, JsonWriter writer) throws IOException { + + + var dataStream = this.obsStore.getDataStreams().get(new DataStreamKey(obs.getDataStreamID())); + var recordStruct = ((DataRecordImpl) dataStream.getRecordStructure()).getFieldList(); + var resultBlock = ((DataBlockMixed) obs.getResult()).getUnderlyingObject(); + + // map osh fields to proto fields + Results.Builder resultsBuilder = Results.newBuilder(); + for (int i = 0; i < resultBlock.length; i++) { + String fieldName = recordStruct.get(i).getName(); + String value = resultBlock[i].getStringValue(); + resultsBuilder.putValues(fieldName, value); + } + + OshObservation protoObs = OshObservation.newBuilder() + .setId(idEncoders.getObsIdEncoder().encodeID(key)) + .setDatastreamId(idEncoders.getDataStreamIdEncoder().encodeID(obs.getDataStreamID())) + .setFoiId(obs.getFoiID() != null + ? idEncoders.getFoiIdEncoder().encodeID(obs.getFoiID()) + : "") + .setPhenomenonTime(String.valueOf(obs.getPhenomenonTime().toEpochMilli())) + .setResultTime(String.valueOf(obs.getResultTime().toEpochMilli())) + .setResults(resultsBuilder.build()) + .build(); + + // serialize to bytes and write to output + byte[] bytes = protoObs.toByteArray(); + ctx.getOutputStream().write(bytes); + ctx.getOutputStream().flush(); + + } + + + protected JsonWriter getJsonWriter(OutputStream os, PropertyFilter propFilter) throws IOException + { + var writer = super.getJsonWriter(os, propFilter); + writer.setSerializeNulls(true); + return writer; + } + + + protected DataStreamWriter getSweCommonWriter(BigId dsID, JsonWriter writer, PropertyFilter propFilter) + { + var dsInfo = obsStore.getDataStreams().get(new DataStreamKey(dsID)); + return getSweCommonWriter(dsInfo, writer, propFilter); + } + + + protected DataStreamWriter getSweCommonWriter(IDataStreamInfo dsInfo, JsonWriter writer, PropertyFilter propFilter) + { + if (!SWECommonUtils.allowNonBinaryFormat(dsInfo.getRecordStructure(), dsInfo.getRecordEncoding())) + return new BinaryDataWriter(); + + // create JSON SWE writer + var sweWriter = new JsonDataWriterGson(writer); + sweWriter.setDataComponents(dsInfo.getRecordStructure()); + + // filter out components that are already included in O&M + sweWriter.setDataComponentFilter(OM_COMPONENTS_FILTER); + return sweWriter; + } + + + protected JsonDataParserGson getSweCommonParser(IDataStreamInfo dsInfo, JsonReader reader) + { + // create JSON SWE parser + var sweParser = new JsonDataParserGson(reader); + sweParser.setDataComponents(dsInfo.getRecordStructure()); + + // filter out components that are already included in O&M + sweParser.setDataComponentFilter(OM_COMPONENTS_FILTER); + return sweParser; + } + + + @Override + public void startCollection() throws IOException + { + if (reader != null) { + reader.beginObject(); + while (reader.hasNext()) { + var propName = reader.nextName(); + if (propName.equals(getItemsPropertyName())) + return; + else + reader.skipValue(); + } + } + } + + + @Override + public void endCollection(Collection links) throws IOException + { + //endJsonCollection(writer, links); + } +} diff --git a/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/obs/ObsBindingSweCommon.java b/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/obs/ObsBindingSweCommon.java index 71234e3e6b..e360809b68 100644 --- a/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/obs/ObsBindingSweCommon.java +++ b/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/obs/ObsBindingSweCommon.java @@ -72,6 +72,8 @@ public ObsBindingSweCommon(RequestContext ctx, IdEncoders idEncoders, boolean fo ctx.setResponseContentType(ResourceFormat.TEXT_PLAIN.getMimeType()); else if (ctx.getFormat().equals(ResourceFormat.SWE_XML)) ctx.setResponseContentType(ResourceFormat.APPLI_XML.getMimeType()); + else if (ctx.getFormat().equals(ResourceFormat.COT_XML)) + ctx.setResponseContentType(ResourceFormat.APPLI_XML.getMimeType()); else ctx.setResponseContentType(ctx.getFormat().getMimeType()); } diff --git a/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/obs/ObsHandler.java b/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/obs/ObsHandler.java index 7081ff9757..6000a8cb70 100644 --- a/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/obs/ObsHandler.java +++ b/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/obs/ObsHandler.java @@ -57,6 +57,8 @@ import com.google.common.base.Objects; import net.opengis.swe.v20.BinaryEncoding; +import javax.xml.stream.XMLStreamException; + public class ObsHandler extends BaseResourceHandler { @@ -92,8 +94,7 @@ public ObsHandler(HandlerContext ctx, ScheduledExecutorService threadPool, Resou @Override - protected ResourceBinding getBinding(RequestContext ctx, boolean forReading) throws IOException - { + protected ResourceBinding getBinding(RequestContext ctx, boolean forReading) throws IOException, XMLStreamException { var contextData = new ObsHandlerContextData(); ctx.setData(contextData); @@ -147,9 +148,15 @@ protected ResourceBinding getBinding(RequestContext ctx, boolea format = ResourceFormat.JSON; ctx.setFormat(format); } - + if (format.isOneOf(ResourceFormat.JSON, ResourceFormat.OM_JSON)) return new ObsBindingOmJson(ctx, idEncoders, forReading, dataStore); + else if (format.equals(ResourceFormat.GEO_JSON)) + return new ObsBindingGeoJson(ctx, idEncoders, forReading, dataStore); + else if (format.equals(ResourceFormat.COT_XML)) + return new ObsBindingCotXml(ctx, idEncoders, forReading, dataStore); + else if (format.equals(ResourceFormat.PROTOBUF)) + return new ObsBindingProtobuf(ctx, idEncoders, forReading, dataStore); else return new ObsBindingSweCommon(ctx, idEncoders, forReading, dataStore); } @@ -256,7 +263,7 @@ protected void subscribe(final RequestContext ctx) throws InvalidRequestExceptio else startReplayStream(ctx, dsID, filter, replaySpeed, binding); } - catch (IOException e) + catch (IOException | XMLStreamException e) { throw new IllegalStateException("Error initializing binding", e); } @@ -340,6 +347,8 @@ protected void sendObs(IObsData obs) { subscription.cancel(); throw new CallbackException(e); + } catch (XMLStreamException e) { + throw new RuntimeException(e); } } @@ -446,7 +455,7 @@ protected void startReplayStream(final RequestContext ctx, final BigId dsID, fin ctx.getLogger().debug("Ending obs replay stream #{}", System.identityHashCode(streamHandler)); } } - catch (IOException e) + catch (IOException | XMLStreamException e) { throw new CompletionException(e); } diff --git a/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/obs/ObsStatsHandler.java b/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/obs/ObsStatsHandler.java index 6c4b3a8125..d8675ed82b 100644 --- a/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/obs/ObsStatsHandler.java +++ b/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/obs/ObsStatsHandler.java @@ -37,6 +37,8 @@ import org.sensorhub.impl.service.consys.resource.RequestContext.ResourceRef; import org.sensorhub.impl.system.DataStreamTransactionHandler; +import javax.xml.stream.XMLStreamException; + public class ObsStatsHandler extends BaseHandler { @@ -76,8 +78,7 @@ protected ResourceBinding getBinding(RequestContext ctx) throws @Override - public void doGet(final RequestContext ctx) throws IOException - { + public void doGet(final RequestContext ctx) throws IOException, XMLStreamException { // check permissions var parentId = ctx.getParentRef().id; ctx.getSecurityHandler().checkParentPermission(permissions.get, parentId); diff --git a/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/obs/proto/Observation.java b/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/obs/proto/Observation.java new file mode 100644 index 0000000000..362a734ceb --- /dev/null +++ b/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/obs/proto/Observation.java @@ -0,0 +1,2140 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: include/osh-core/sensorhub-service-consys/src/main/proto/observation.proto + +package org.sensorhub.impl.service.consys.obs.proto; + +public final class Observation { + private Observation() {} + public static void registerAllExtensions( + com.google.protobuf.ExtensionRegistryLite registry) { + } + + public static void registerAllExtensions( + com.google.protobuf.ExtensionRegistry registry) { + registerAllExtensions( + (com.google.protobuf.ExtensionRegistryLite) registry); + } + public interface OshObservationOrBuilder extends + // @@protoc_insertion_point(interface_extends:obs.OshObservation) + com.google.protobuf.MessageOrBuilder { + + /** + * string id = 1; + * @return The id. + */ + java.lang.String getId(); + /** + * string id = 1; + * @return The bytes for id. + */ + com.google.protobuf.ByteString + getIdBytes(); + + /** + * string datastreamId = 2; + * @return The datastreamId. + */ + java.lang.String getDatastreamId(); + /** + * string datastreamId = 2; + * @return The bytes for datastreamId. + */ + com.google.protobuf.ByteString + getDatastreamIdBytes(); + + /** + * string foiId = 3; + * @return The foiId. + */ + java.lang.String getFoiId(); + /** + * string foiId = 3; + * @return The bytes for foiId. + */ + com.google.protobuf.ByteString + getFoiIdBytes(); + + /** + * string phenomenonTime = 4; + * @return The phenomenonTime. + */ + java.lang.String getPhenomenonTime(); + /** + * string phenomenonTime = 4; + * @return The bytes for phenomenonTime. + */ + com.google.protobuf.ByteString + getPhenomenonTimeBytes(); + + /** + * string resultTime = 5; + * @return The resultTime. + */ + java.lang.String getResultTime(); + /** + * string resultTime = 5; + * @return The bytes for resultTime. + */ + com.google.protobuf.ByteString + getResultTimeBytes(); + + /** + * .obs.Results results = 6; + * @return Whether the results field is set. + */ + boolean hasResults(); + /** + * .obs.Results results = 6; + * @return The results. + */ + org.sensorhub.impl.service.consys.obs.proto.Observation.Results getResults(); + /** + * .obs.Results results = 6; + */ + org.sensorhub.impl.service.consys.obs.proto.Observation.ResultsOrBuilder getResultsOrBuilder(); + } + /** + * Protobuf type {@code obs.OshObservation} + */ + public static final class OshObservation extends + com.google.protobuf.GeneratedMessageV3 implements + // @@protoc_insertion_point(message_implements:obs.OshObservation) + OshObservationOrBuilder { + private static final long serialVersionUID = 0L; + // Use OshObservation.newBuilder() to construct. + private OshObservation(com.google.protobuf.GeneratedMessageV3.Builder builder) { + super(builder); + } + private OshObservation() { + id_ = ""; + datastreamId_ = ""; + foiId_ = ""; + phenomenonTime_ = ""; + resultTime_ = ""; + } + + @java.lang.Override + @SuppressWarnings({"unused"}) + protected java.lang.Object newInstance( + UnusedPrivateParameter unused) { + return new OshObservation(); + } + + @java.lang.Override + public final com.google.protobuf.UnknownFieldSet + getUnknownFields() { + return this.unknownFields; + } + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.sensorhub.impl.service.consys.obs.proto.Observation.internal_static_obs_OshObservation_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.sensorhub.impl.service.consys.obs.proto.Observation.internal_static_obs_OshObservation_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.sensorhub.impl.service.consys.obs.proto.Observation.OshObservation.class, org.sensorhub.impl.service.consys.obs.proto.Observation.OshObservation.Builder.class); + } + + public static final int ID_FIELD_NUMBER = 1; + @SuppressWarnings("serial") + private volatile java.lang.Object id_ = ""; + /** + * string id = 1; + * @return The id. + */ + @java.lang.Override + public java.lang.String getId() { + java.lang.Object ref = id_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + id_ = s; + return s; + } + } + /** + * string id = 1; + * @return The bytes for id. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getIdBytes() { + java.lang.Object ref = id_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + id_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int DATASTREAMID_FIELD_NUMBER = 2; + @SuppressWarnings("serial") + private volatile java.lang.Object datastreamId_ = ""; + /** + * string datastreamId = 2; + * @return The datastreamId. + */ + @java.lang.Override + public java.lang.String getDatastreamId() { + java.lang.Object ref = datastreamId_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + datastreamId_ = s; + return s; + } + } + /** + * string datastreamId = 2; + * @return The bytes for datastreamId. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getDatastreamIdBytes() { + java.lang.Object ref = datastreamId_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + datastreamId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int FOIID_FIELD_NUMBER = 3; + @SuppressWarnings("serial") + private volatile java.lang.Object foiId_ = ""; + /** + * string foiId = 3; + * @return The foiId. + */ + @java.lang.Override + public java.lang.String getFoiId() { + java.lang.Object ref = foiId_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + foiId_ = s; + return s; + } + } + /** + * string foiId = 3; + * @return The bytes for foiId. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getFoiIdBytes() { + java.lang.Object ref = foiId_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + foiId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int PHENOMENONTIME_FIELD_NUMBER = 4; + @SuppressWarnings("serial") + private volatile java.lang.Object phenomenonTime_ = ""; + /** + * string phenomenonTime = 4; + * @return The phenomenonTime. + */ + @java.lang.Override + public java.lang.String getPhenomenonTime() { + java.lang.Object ref = phenomenonTime_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + phenomenonTime_ = s; + return s; + } + } + /** + * string phenomenonTime = 4; + * @return The bytes for phenomenonTime. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getPhenomenonTimeBytes() { + java.lang.Object ref = phenomenonTime_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + phenomenonTime_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int RESULTTIME_FIELD_NUMBER = 5; + @SuppressWarnings("serial") + private volatile java.lang.Object resultTime_ = ""; + /** + * string resultTime = 5; + * @return The resultTime. + */ + @java.lang.Override + public java.lang.String getResultTime() { + java.lang.Object ref = resultTime_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + resultTime_ = s; + return s; + } + } + /** + * string resultTime = 5; + * @return The bytes for resultTime. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getResultTimeBytes() { + java.lang.Object ref = resultTime_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + resultTime_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int RESULTS_FIELD_NUMBER = 6; + private org.sensorhub.impl.service.consys.obs.proto.Observation.Results results_; + /** + * .obs.Results results = 6; + * @return Whether the results field is set. + */ + @java.lang.Override + public boolean hasResults() { + return results_ != null; + } + /** + * .obs.Results results = 6; + * @return The results. + */ + @java.lang.Override + public org.sensorhub.impl.service.consys.obs.proto.Observation.Results getResults() { + return results_ == null ? org.sensorhub.impl.service.consys.obs.proto.Observation.Results.getDefaultInstance() : results_; + } + /** + * .obs.Results results = 6; + */ + @java.lang.Override + public org.sensorhub.impl.service.consys.obs.proto.Observation.ResultsOrBuilder getResultsOrBuilder() { + return results_ == null ? org.sensorhub.impl.service.consys.obs.proto.Observation.Results.getDefaultInstance() : results_; + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(id_)) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 1, id_); + } + if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(datastreamId_)) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 2, datastreamId_); + } + if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(foiId_)) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 3, foiId_); + } + if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(phenomenonTime_)) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 4, phenomenonTime_); + } + if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(resultTime_)) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 5, resultTime_); + } + if (results_ != null) { + output.writeMessage(6, getResults()); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(id_)) { + size += com.google.protobuf.GeneratedMessageV3.computeStringSize(1, id_); + } + if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(datastreamId_)) { + size += com.google.protobuf.GeneratedMessageV3.computeStringSize(2, datastreamId_); + } + if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(foiId_)) { + size += com.google.protobuf.GeneratedMessageV3.computeStringSize(3, foiId_); + } + if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(phenomenonTime_)) { + size += com.google.protobuf.GeneratedMessageV3.computeStringSize(4, phenomenonTime_); + } + if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(resultTime_)) { + size += com.google.protobuf.GeneratedMessageV3.computeStringSize(5, resultTime_); + } + if (results_ != null) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(6, getResults()); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.sensorhub.impl.service.consys.obs.proto.Observation.OshObservation)) { + return super.equals(obj); + } + org.sensorhub.impl.service.consys.obs.proto.Observation.OshObservation other = (org.sensorhub.impl.service.consys.obs.proto.Observation.OshObservation) obj; + + if (!getId() + .equals(other.getId())) return false; + if (!getDatastreamId() + .equals(other.getDatastreamId())) return false; + if (!getFoiId() + .equals(other.getFoiId())) return false; + if (!getPhenomenonTime() + .equals(other.getPhenomenonTime())) return false; + if (!getResultTime() + .equals(other.getResultTime())) return false; + if (hasResults() != other.hasResults()) return false; + if (hasResults()) { + if (!getResults() + .equals(other.getResults())) return false; + } + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + ID_FIELD_NUMBER; + hash = (53 * hash) + getId().hashCode(); + hash = (37 * hash) + DATASTREAMID_FIELD_NUMBER; + hash = (53 * hash) + getDatastreamId().hashCode(); + hash = (37 * hash) + FOIID_FIELD_NUMBER; + hash = (53 * hash) + getFoiId().hashCode(); + hash = (37 * hash) + PHENOMENONTIME_FIELD_NUMBER; + hash = (53 * hash) + getPhenomenonTime().hashCode(); + hash = (37 * hash) + RESULTTIME_FIELD_NUMBER; + hash = (53 * hash) + getResultTime().hashCode(); + if (hasResults()) { + hash = (37 * hash) + RESULTS_FIELD_NUMBER; + hash = (53 * hash) + getResults().hashCode(); + } + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.sensorhub.impl.service.consys.obs.proto.Observation.OshObservation parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.sensorhub.impl.service.consys.obs.proto.Observation.OshObservation parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.sensorhub.impl.service.consys.obs.proto.Observation.OshObservation parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.sensorhub.impl.service.consys.obs.proto.Observation.OshObservation parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.sensorhub.impl.service.consys.obs.proto.Observation.OshObservation parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.sensorhub.impl.service.consys.obs.proto.Observation.OshObservation parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.sensorhub.impl.service.consys.obs.proto.Observation.OshObservation parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + public static org.sensorhub.impl.service.consys.obs.proto.Observation.OshObservation parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + public static org.sensorhub.impl.service.consys.obs.proto.Observation.OshObservation parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input); + } + public static org.sensorhub.impl.service.consys.obs.proto.Observation.OshObservation parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.sensorhub.impl.service.consys.obs.proto.Observation.OshObservation parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + public static org.sensorhub.impl.service.consys.obs.proto.Observation.OshObservation parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.sensorhub.impl.service.consys.obs.proto.Observation.OshObservation prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + * Protobuf type {@code obs.OshObservation} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageV3.Builder implements + // @@protoc_insertion_point(builder_implements:obs.OshObservation) + org.sensorhub.impl.service.consys.obs.proto.Observation.OshObservationOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.sensorhub.impl.service.consys.obs.proto.Observation.internal_static_obs_OshObservation_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.sensorhub.impl.service.consys.obs.proto.Observation.internal_static_obs_OshObservation_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.sensorhub.impl.service.consys.obs.proto.Observation.OshObservation.class, org.sensorhub.impl.service.consys.obs.proto.Observation.OshObservation.Builder.class); + } + + // Construct using org.sensorhub.impl.service.consys.obs.proto.Observation.OshObservation.newBuilder() + private Builder() { + + } + + private Builder( + com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { + super(parent); + + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + id_ = ""; + datastreamId_ = ""; + foiId_ = ""; + phenomenonTime_ = ""; + resultTime_ = ""; + results_ = null; + if (resultsBuilder_ != null) { + resultsBuilder_.dispose(); + resultsBuilder_ = null; + } + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.sensorhub.impl.service.consys.obs.proto.Observation.internal_static_obs_OshObservation_descriptor; + } + + @java.lang.Override + public org.sensorhub.impl.service.consys.obs.proto.Observation.OshObservation getDefaultInstanceForType() { + return org.sensorhub.impl.service.consys.obs.proto.Observation.OshObservation.getDefaultInstance(); + } + + @java.lang.Override + public org.sensorhub.impl.service.consys.obs.proto.Observation.OshObservation build() { + org.sensorhub.impl.service.consys.obs.proto.Observation.OshObservation result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.sensorhub.impl.service.consys.obs.proto.Observation.OshObservation buildPartial() { + org.sensorhub.impl.service.consys.obs.proto.Observation.OshObservation result = new org.sensorhub.impl.service.consys.obs.proto.Observation.OshObservation(this); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartial0(org.sensorhub.impl.service.consys.obs.proto.Observation.OshObservation result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.id_ = id_; + } + if (((from_bitField0_ & 0x00000002) != 0)) { + result.datastreamId_ = datastreamId_; + } + if (((from_bitField0_ & 0x00000004) != 0)) { + result.foiId_ = foiId_; + } + if (((from_bitField0_ & 0x00000008) != 0)) { + result.phenomenonTime_ = phenomenonTime_; + } + if (((from_bitField0_ & 0x00000010) != 0)) { + result.resultTime_ = resultTime_; + } + if (((from_bitField0_ & 0x00000020) != 0)) { + result.results_ = resultsBuilder_ == null + ? results_ + : resultsBuilder_.build(); + } + } + + @java.lang.Override + public Builder clone() { + return super.clone(); + } + @java.lang.Override + public Builder setField( + com.google.protobuf.Descriptors.FieldDescriptor field, + java.lang.Object value) { + return super.setField(field, value); + } + @java.lang.Override + public Builder clearField( + com.google.protobuf.Descriptors.FieldDescriptor field) { + return super.clearField(field); + } + @java.lang.Override + public Builder clearOneof( + com.google.protobuf.Descriptors.OneofDescriptor oneof) { + return super.clearOneof(oneof); + } + @java.lang.Override + public Builder setRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + int index, java.lang.Object value) { + return super.setRepeatedField(field, index, value); + } + @java.lang.Override + public Builder addRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + java.lang.Object value) { + return super.addRepeatedField(field, value); + } + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.sensorhub.impl.service.consys.obs.proto.Observation.OshObservation) { + return mergeFrom((org.sensorhub.impl.service.consys.obs.proto.Observation.OshObservation)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.sensorhub.impl.service.consys.obs.proto.Observation.OshObservation other) { + if (other == org.sensorhub.impl.service.consys.obs.proto.Observation.OshObservation.getDefaultInstance()) return this; + if (!other.getId().isEmpty()) { + id_ = other.id_; + bitField0_ |= 0x00000001; + onChanged(); + } + if (!other.getDatastreamId().isEmpty()) { + datastreamId_ = other.datastreamId_; + bitField0_ |= 0x00000002; + onChanged(); + } + if (!other.getFoiId().isEmpty()) { + foiId_ = other.foiId_; + bitField0_ |= 0x00000004; + onChanged(); + } + if (!other.getPhenomenonTime().isEmpty()) { + phenomenonTime_ = other.phenomenonTime_; + bitField0_ |= 0x00000008; + onChanged(); + } + if (!other.getResultTime().isEmpty()) { + resultTime_ = other.resultTime_; + bitField0_ |= 0x00000010; + onChanged(); + } + if (other.hasResults()) { + mergeResults(other.getResults()); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + id_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000001; + break; + } // case 10 + case 18: { + datastreamId_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000002; + break; + } // case 18 + case 26: { + foiId_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000004; + break; + } // case 26 + case 34: { + phenomenonTime_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000008; + break; + } // case 34 + case 42: { + resultTime_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000010; + break; + } // case 42 + case 50: { + input.readMessage( + getResultsFieldBuilder().getBuilder(), + extensionRegistry); + bitField0_ |= 0x00000020; + break; + } // case 50 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private java.lang.Object id_ = ""; + /** + * string id = 1; + * @return The id. + */ + public java.lang.String getId() { + java.lang.Object ref = id_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + id_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * string id = 1; + * @return The bytes for id. + */ + public com.google.protobuf.ByteString + getIdBytes() { + java.lang.Object ref = id_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + id_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * string id = 1; + * @param value The id to set. + * @return This builder for chaining. + */ + public Builder setId( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + id_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + * string id = 1; + * @return This builder for chaining. + */ + public Builder clearId() { + id_ = getDefaultInstance().getId(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + return this; + } + /** + * string id = 1; + * @param value The bytes for id to set. + * @return This builder for chaining. + */ + public Builder setIdBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + id_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + private java.lang.Object datastreamId_ = ""; + /** + * string datastreamId = 2; + * @return The datastreamId. + */ + public java.lang.String getDatastreamId() { + java.lang.Object ref = datastreamId_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + datastreamId_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * string datastreamId = 2; + * @return The bytes for datastreamId. + */ + public com.google.protobuf.ByteString + getDatastreamIdBytes() { + java.lang.Object ref = datastreamId_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + datastreamId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * string datastreamId = 2; + * @param value The datastreamId to set. + * @return This builder for chaining. + */ + public Builder setDatastreamId( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + datastreamId_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + * string datastreamId = 2; + * @return This builder for chaining. + */ + public Builder clearDatastreamId() { + datastreamId_ = getDefaultInstance().getDatastreamId(); + bitField0_ = (bitField0_ & ~0x00000002); + onChanged(); + return this; + } + /** + * string datastreamId = 2; + * @param value The bytes for datastreamId to set. + * @return This builder for chaining. + */ + public Builder setDatastreamIdBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + datastreamId_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + + private java.lang.Object foiId_ = ""; + /** + * string foiId = 3; + * @return The foiId. + */ + public java.lang.String getFoiId() { + java.lang.Object ref = foiId_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + foiId_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * string foiId = 3; + * @return The bytes for foiId. + */ + public com.google.protobuf.ByteString + getFoiIdBytes() { + java.lang.Object ref = foiId_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + foiId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * string foiId = 3; + * @param value The foiId to set. + * @return This builder for chaining. + */ + public Builder setFoiId( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + foiId_ = value; + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + /** + * string foiId = 3; + * @return This builder for chaining. + */ + public Builder clearFoiId() { + foiId_ = getDefaultInstance().getFoiId(); + bitField0_ = (bitField0_ & ~0x00000004); + onChanged(); + return this; + } + /** + * string foiId = 3; + * @param value The bytes for foiId to set. + * @return This builder for chaining. + */ + public Builder setFoiIdBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + foiId_ = value; + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + + private java.lang.Object phenomenonTime_ = ""; + /** + * string phenomenonTime = 4; + * @return The phenomenonTime. + */ + public java.lang.String getPhenomenonTime() { + java.lang.Object ref = phenomenonTime_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + phenomenonTime_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * string phenomenonTime = 4; + * @return The bytes for phenomenonTime. + */ + public com.google.protobuf.ByteString + getPhenomenonTimeBytes() { + java.lang.Object ref = phenomenonTime_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + phenomenonTime_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * string phenomenonTime = 4; + * @param value The phenomenonTime to set. + * @return This builder for chaining. + */ + public Builder setPhenomenonTime( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + phenomenonTime_ = value; + bitField0_ |= 0x00000008; + onChanged(); + return this; + } + /** + * string phenomenonTime = 4; + * @return This builder for chaining. + */ + public Builder clearPhenomenonTime() { + phenomenonTime_ = getDefaultInstance().getPhenomenonTime(); + bitField0_ = (bitField0_ & ~0x00000008); + onChanged(); + return this; + } + /** + * string phenomenonTime = 4; + * @param value The bytes for phenomenonTime to set. + * @return This builder for chaining. + */ + public Builder setPhenomenonTimeBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + phenomenonTime_ = value; + bitField0_ |= 0x00000008; + onChanged(); + return this; + } + + private java.lang.Object resultTime_ = ""; + /** + * string resultTime = 5; + * @return The resultTime. + */ + public java.lang.String getResultTime() { + java.lang.Object ref = resultTime_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + resultTime_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * string resultTime = 5; + * @return The bytes for resultTime. + */ + public com.google.protobuf.ByteString + getResultTimeBytes() { + java.lang.Object ref = resultTime_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + resultTime_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * string resultTime = 5; + * @param value The resultTime to set. + * @return This builder for chaining. + */ + public Builder setResultTime( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + resultTime_ = value; + bitField0_ |= 0x00000010; + onChanged(); + return this; + } + /** + * string resultTime = 5; + * @return This builder for chaining. + */ + public Builder clearResultTime() { + resultTime_ = getDefaultInstance().getResultTime(); + bitField0_ = (bitField0_ & ~0x00000010); + onChanged(); + return this; + } + /** + * string resultTime = 5; + * @param value The bytes for resultTime to set. + * @return This builder for chaining. + */ + public Builder setResultTimeBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + resultTime_ = value; + bitField0_ |= 0x00000010; + onChanged(); + return this; + } + + private org.sensorhub.impl.service.consys.obs.proto.Observation.Results results_; + private com.google.protobuf.SingleFieldBuilderV3< + org.sensorhub.impl.service.consys.obs.proto.Observation.Results, org.sensorhub.impl.service.consys.obs.proto.Observation.Results.Builder, org.sensorhub.impl.service.consys.obs.proto.Observation.ResultsOrBuilder> resultsBuilder_; + /** + * .obs.Results results = 6; + * @return Whether the results field is set. + */ + public boolean hasResults() { + return ((bitField0_ & 0x00000020) != 0); + } + /** + * .obs.Results results = 6; + * @return The results. + */ + public org.sensorhub.impl.service.consys.obs.proto.Observation.Results getResults() { + if (resultsBuilder_ == null) { + return results_ == null ? org.sensorhub.impl.service.consys.obs.proto.Observation.Results.getDefaultInstance() : results_; + } else { + return resultsBuilder_.getMessage(); + } + } + /** + * .obs.Results results = 6; + */ + public Builder setResults(org.sensorhub.impl.service.consys.obs.proto.Observation.Results value) { + if (resultsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + results_ = value; + } else { + resultsBuilder_.setMessage(value); + } + bitField0_ |= 0x00000020; + onChanged(); + return this; + } + /** + * .obs.Results results = 6; + */ + public Builder setResults( + org.sensorhub.impl.service.consys.obs.proto.Observation.Results.Builder builderForValue) { + if (resultsBuilder_ == null) { + results_ = builderForValue.build(); + } else { + resultsBuilder_.setMessage(builderForValue.build()); + } + bitField0_ |= 0x00000020; + onChanged(); + return this; + } + /** + * .obs.Results results = 6; + */ + public Builder mergeResults(org.sensorhub.impl.service.consys.obs.proto.Observation.Results value) { + if (resultsBuilder_ == null) { + if (((bitField0_ & 0x00000020) != 0) && + results_ != null && + results_ != org.sensorhub.impl.service.consys.obs.proto.Observation.Results.getDefaultInstance()) { + getResultsBuilder().mergeFrom(value); + } else { + results_ = value; + } + } else { + resultsBuilder_.mergeFrom(value); + } + bitField0_ |= 0x00000020; + onChanged(); + return this; + } + /** + * .obs.Results results = 6; + */ + public Builder clearResults() { + bitField0_ = (bitField0_ & ~0x00000020); + results_ = null; + if (resultsBuilder_ != null) { + resultsBuilder_.dispose(); + resultsBuilder_ = null; + } + onChanged(); + return this; + } + /** + * .obs.Results results = 6; + */ + public org.sensorhub.impl.service.consys.obs.proto.Observation.Results.Builder getResultsBuilder() { + bitField0_ |= 0x00000020; + onChanged(); + return getResultsFieldBuilder().getBuilder(); + } + /** + * .obs.Results results = 6; + */ + public org.sensorhub.impl.service.consys.obs.proto.Observation.ResultsOrBuilder getResultsOrBuilder() { + if (resultsBuilder_ != null) { + return resultsBuilder_.getMessageOrBuilder(); + } else { + return results_ == null ? + org.sensorhub.impl.service.consys.obs.proto.Observation.Results.getDefaultInstance() : results_; + } + } + /** + * .obs.Results results = 6; + */ + private com.google.protobuf.SingleFieldBuilderV3< + org.sensorhub.impl.service.consys.obs.proto.Observation.Results, org.sensorhub.impl.service.consys.obs.proto.Observation.Results.Builder, org.sensorhub.impl.service.consys.obs.proto.Observation.ResultsOrBuilder> + getResultsFieldBuilder() { + if (resultsBuilder_ == null) { + resultsBuilder_ = new com.google.protobuf.SingleFieldBuilderV3< + org.sensorhub.impl.service.consys.obs.proto.Observation.Results, org.sensorhub.impl.service.consys.obs.proto.Observation.Results.Builder, org.sensorhub.impl.service.consys.obs.proto.Observation.ResultsOrBuilder>( + getResults(), + getParentForChildren(), + isClean()); + results_ = null; + } + return resultsBuilder_; + } + @java.lang.Override + public final Builder setUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return super.setUnknownFields(unknownFields); + } + + @java.lang.Override + public final Builder mergeUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return super.mergeUnknownFields(unknownFields); + } + + + // @@protoc_insertion_point(builder_scope:obs.OshObservation) + } + + // @@protoc_insertion_point(class_scope:obs.OshObservation) + private static final org.sensorhub.impl.service.consys.obs.proto.Observation.OshObservation DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.sensorhub.impl.service.consys.obs.proto.Observation.OshObservation(); + } + + public static org.sensorhub.impl.service.consys.obs.proto.Observation.OshObservation getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public OshObservation parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.sensorhub.impl.service.consys.obs.proto.Observation.OshObservation getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + + } + + public interface ResultsOrBuilder extends + // @@protoc_insertion_point(interface_extends:obs.Results) + com.google.protobuf.MessageOrBuilder { + + /** + * map<string, string> values = 1; + */ + int getValuesCount(); + /** + * map<string, string> values = 1; + */ + boolean containsValues( + java.lang.String key); + /** + * Use {@link #getValuesMap()} instead. + */ + @java.lang.Deprecated + java.util.Map + getValues(); + /** + * map<string, string> values = 1; + */ + java.util.Map + getValuesMap(); + /** + * map<string, string> values = 1; + */ + /* nullable */ +java.lang.String getValuesOrDefault( + java.lang.String key, + /* nullable */ +java.lang.String defaultValue); + /** + * map<string, string> values = 1; + */ + java.lang.String getValuesOrThrow( + java.lang.String key); + } + /** + * Protobuf type {@code obs.Results} + */ + public static final class Results extends + com.google.protobuf.GeneratedMessageV3 implements + // @@protoc_insertion_point(message_implements:obs.Results) + ResultsOrBuilder { + private static final long serialVersionUID = 0L; + // Use Results.newBuilder() to construct. + private Results(com.google.protobuf.GeneratedMessageV3.Builder builder) { + super(builder); + } + private Results() { + } + + @java.lang.Override + @SuppressWarnings({"unused"}) + protected java.lang.Object newInstance( + UnusedPrivateParameter unused) { + return new Results(); + } + + @java.lang.Override + public final com.google.protobuf.UnknownFieldSet + getUnknownFields() { + return this.unknownFields; + } + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.sensorhub.impl.service.consys.obs.proto.Observation.internal_static_obs_Results_descriptor; + } + + @SuppressWarnings({"rawtypes"}) + @java.lang.Override + protected com.google.protobuf.MapField internalGetMapField( + int number) { + switch (number) { + case 1: + return internalGetValues(); + default: + throw new RuntimeException( + "Invalid map field number: " + number); + } + } + @java.lang.Override + protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.sensorhub.impl.service.consys.obs.proto.Observation.internal_static_obs_Results_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.sensorhub.impl.service.consys.obs.proto.Observation.Results.class, org.sensorhub.impl.service.consys.obs.proto.Observation.Results.Builder.class); + } + + public static final int VALUES_FIELD_NUMBER = 1; + private static final class ValuesDefaultEntryHolder { + static final com.google.protobuf.MapEntry< + java.lang.String, java.lang.String> defaultEntry = + com.google.protobuf.MapEntry + .newDefaultInstance( + org.sensorhub.impl.service.consys.obs.proto.Observation.internal_static_obs_Results_ValuesEntry_descriptor, + com.google.protobuf.WireFormat.FieldType.STRING, + "", + com.google.protobuf.WireFormat.FieldType.STRING, + ""); + } + @SuppressWarnings("serial") + private com.google.protobuf.MapField< + java.lang.String, java.lang.String> values_; + private com.google.protobuf.MapField + internalGetValues() { + if (values_ == null) { + return com.google.protobuf.MapField.emptyMapField( + ValuesDefaultEntryHolder.defaultEntry); + } + return values_; + } + public int getValuesCount() { + return internalGetValues().getMap().size(); + } + /** + * map<string, string> values = 1; + */ + @java.lang.Override + public boolean containsValues( + java.lang.String key) { + if (key == null) { throw new NullPointerException("map key"); } + return internalGetValues().getMap().containsKey(key); + } + /** + * Use {@link #getValuesMap()} instead. + */ + @java.lang.Override + @java.lang.Deprecated + public java.util.Map getValues() { + return getValuesMap(); + } + /** + * map<string, string> values = 1; + */ + @java.lang.Override + public java.util.Map getValuesMap() { + return internalGetValues().getMap(); + } + /** + * map<string, string> values = 1; + */ + @java.lang.Override + public /* nullable */ +java.lang.String getValuesOrDefault( + java.lang.String key, + /* nullable */ +java.lang.String defaultValue) { + if (key == null) { throw new NullPointerException("map key"); } + java.util.Map map = + internalGetValues().getMap(); + return map.containsKey(key) ? map.get(key) : defaultValue; + } + /** + * map<string, string> values = 1; + */ + @java.lang.Override + public java.lang.String getValuesOrThrow( + java.lang.String key) { + if (key == null) { throw new NullPointerException("map key"); } + java.util.Map map = + internalGetValues().getMap(); + if (!map.containsKey(key)) { + throw new java.lang.IllegalArgumentException(); + } + return map.get(key); + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + com.google.protobuf.GeneratedMessageV3 + .serializeStringMapTo( + output, + internalGetValues(), + ValuesDefaultEntryHolder.defaultEntry, + 1); + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + for (java.util.Map.Entry entry + : internalGetValues().getMap().entrySet()) { + com.google.protobuf.MapEntry + values__ = ValuesDefaultEntryHolder.defaultEntry.newBuilderForType() + .setKey(entry.getKey()) + .setValue(entry.getValue()) + .build(); + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(1, values__); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.sensorhub.impl.service.consys.obs.proto.Observation.Results)) { + return super.equals(obj); + } + org.sensorhub.impl.service.consys.obs.proto.Observation.Results other = (org.sensorhub.impl.service.consys.obs.proto.Observation.Results) obj; + + if (!internalGetValues().equals( + other.internalGetValues())) return false; + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + if (!internalGetValues().getMap().isEmpty()) { + hash = (37 * hash) + VALUES_FIELD_NUMBER; + hash = (53 * hash) + internalGetValues().hashCode(); + } + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.sensorhub.impl.service.consys.obs.proto.Observation.Results parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.sensorhub.impl.service.consys.obs.proto.Observation.Results parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.sensorhub.impl.service.consys.obs.proto.Observation.Results parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.sensorhub.impl.service.consys.obs.proto.Observation.Results parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.sensorhub.impl.service.consys.obs.proto.Observation.Results parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.sensorhub.impl.service.consys.obs.proto.Observation.Results parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.sensorhub.impl.service.consys.obs.proto.Observation.Results parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + public static org.sensorhub.impl.service.consys.obs.proto.Observation.Results parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + public static org.sensorhub.impl.service.consys.obs.proto.Observation.Results parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input); + } + public static org.sensorhub.impl.service.consys.obs.proto.Observation.Results parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.sensorhub.impl.service.consys.obs.proto.Observation.Results parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + public static org.sensorhub.impl.service.consys.obs.proto.Observation.Results parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.sensorhub.impl.service.consys.obs.proto.Observation.Results prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + * Protobuf type {@code obs.Results} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageV3.Builder implements + // @@protoc_insertion_point(builder_implements:obs.Results) + org.sensorhub.impl.service.consys.obs.proto.Observation.ResultsOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.sensorhub.impl.service.consys.obs.proto.Observation.internal_static_obs_Results_descriptor; + } + + @SuppressWarnings({"rawtypes"}) + protected com.google.protobuf.MapField internalGetMapField( + int number) { + switch (number) { + case 1: + return internalGetValues(); + default: + throw new RuntimeException( + "Invalid map field number: " + number); + } + } + @SuppressWarnings({"rawtypes"}) + protected com.google.protobuf.MapField internalGetMutableMapField( + int number) { + switch (number) { + case 1: + return internalGetMutableValues(); + default: + throw new RuntimeException( + "Invalid map field number: " + number); + } + } + @java.lang.Override + protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.sensorhub.impl.service.consys.obs.proto.Observation.internal_static_obs_Results_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.sensorhub.impl.service.consys.obs.proto.Observation.Results.class, org.sensorhub.impl.service.consys.obs.proto.Observation.Results.Builder.class); + } + + // Construct using org.sensorhub.impl.service.consys.obs.proto.Observation.Results.newBuilder() + private Builder() { + + } + + private Builder( + com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { + super(parent); + + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + internalGetMutableValues().clear(); + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.sensorhub.impl.service.consys.obs.proto.Observation.internal_static_obs_Results_descriptor; + } + + @java.lang.Override + public org.sensorhub.impl.service.consys.obs.proto.Observation.Results getDefaultInstanceForType() { + return org.sensorhub.impl.service.consys.obs.proto.Observation.Results.getDefaultInstance(); + } + + @java.lang.Override + public org.sensorhub.impl.service.consys.obs.proto.Observation.Results build() { + org.sensorhub.impl.service.consys.obs.proto.Observation.Results result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.sensorhub.impl.service.consys.obs.proto.Observation.Results buildPartial() { + org.sensorhub.impl.service.consys.obs.proto.Observation.Results result = new org.sensorhub.impl.service.consys.obs.proto.Observation.Results(this); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartial0(org.sensorhub.impl.service.consys.obs.proto.Observation.Results result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.values_ = internalGetValues(); + result.values_.makeImmutable(); + } + } + + @java.lang.Override + public Builder clone() { + return super.clone(); + } + @java.lang.Override + public Builder setField( + com.google.protobuf.Descriptors.FieldDescriptor field, + java.lang.Object value) { + return super.setField(field, value); + } + @java.lang.Override + public Builder clearField( + com.google.protobuf.Descriptors.FieldDescriptor field) { + return super.clearField(field); + } + @java.lang.Override + public Builder clearOneof( + com.google.protobuf.Descriptors.OneofDescriptor oneof) { + return super.clearOneof(oneof); + } + @java.lang.Override + public Builder setRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + int index, java.lang.Object value) { + return super.setRepeatedField(field, index, value); + } + @java.lang.Override + public Builder addRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + java.lang.Object value) { + return super.addRepeatedField(field, value); + } + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.sensorhub.impl.service.consys.obs.proto.Observation.Results) { + return mergeFrom((org.sensorhub.impl.service.consys.obs.proto.Observation.Results)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.sensorhub.impl.service.consys.obs.proto.Observation.Results other) { + if (other == org.sensorhub.impl.service.consys.obs.proto.Observation.Results.getDefaultInstance()) return this; + internalGetMutableValues().mergeFrom( + other.internalGetValues()); + bitField0_ |= 0x00000001; + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + com.google.protobuf.MapEntry + values__ = input.readMessage( + ValuesDefaultEntryHolder.defaultEntry.getParserForType(), extensionRegistry); + internalGetMutableValues().getMutableMap().put( + values__.getKey(), values__.getValue()); + bitField0_ |= 0x00000001; + break; + } // case 10 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private com.google.protobuf.MapField< + java.lang.String, java.lang.String> values_; + private com.google.protobuf.MapField + internalGetValues() { + if (values_ == null) { + return com.google.protobuf.MapField.emptyMapField( + ValuesDefaultEntryHolder.defaultEntry); + } + return values_; + } + private com.google.protobuf.MapField + internalGetMutableValues() { + if (values_ == null) { + values_ = com.google.protobuf.MapField.newMapField( + ValuesDefaultEntryHolder.defaultEntry); + } + if (!values_.isMutable()) { + values_ = values_.copy(); + } + bitField0_ |= 0x00000001; + onChanged(); + return values_; + } + public int getValuesCount() { + return internalGetValues().getMap().size(); + } + /** + * map<string, string> values = 1; + */ + @java.lang.Override + public boolean containsValues( + java.lang.String key) { + if (key == null) { throw new NullPointerException("map key"); } + return internalGetValues().getMap().containsKey(key); + } + /** + * Use {@link #getValuesMap()} instead. + */ + @java.lang.Override + @java.lang.Deprecated + public java.util.Map getValues() { + return getValuesMap(); + } + /** + * map<string, string> values = 1; + */ + @java.lang.Override + public java.util.Map getValuesMap() { + return internalGetValues().getMap(); + } + /** + * map<string, string> values = 1; + */ + @java.lang.Override + public /* nullable */ +java.lang.String getValuesOrDefault( + java.lang.String key, + /* nullable */ +java.lang.String defaultValue) { + if (key == null) { throw new NullPointerException("map key"); } + java.util.Map map = + internalGetValues().getMap(); + return map.containsKey(key) ? map.get(key) : defaultValue; + } + /** + * map<string, string> values = 1; + */ + @java.lang.Override + public java.lang.String getValuesOrThrow( + java.lang.String key) { + if (key == null) { throw new NullPointerException("map key"); } + java.util.Map map = + internalGetValues().getMap(); + if (!map.containsKey(key)) { + throw new java.lang.IllegalArgumentException(); + } + return map.get(key); + } + public Builder clearValues() { + bitField0_ = (bitField0_ & ~0x00000001); + internalGetMutableValues().getMutableMap() + .clear(); + return this; + } + /** + * map<string, string> values = 1; + */ + public Builder removeValues( + java.lang.String key) { + if (key == null) { throw new NullPointerException("map key"); } + internalGetMutableValues().getMutableMap() + .remove(key); + return this; + } + /** + * Use alternate mutation accessors instead. + */ + @java.lang.Deprecated + public java.util.Map + getMutableValues() { + bitField0_ |= 0x00000001; + return internalGetMutableValues().getMutableMap(); + } + /** + * map<string, string> values = 1; + */ + public Builder putValues( + java.lang.String key, + java.lang.String value) { + if (key == null) { throw new NullPointerException("map key"); } + if (value == null) { throw new NullPointerException("map value"); } + internalGetMutableValues().getMutableMap() + .put(key, value); + bitField0_ |= 0x00000001; + return this; + } + /** + * map<string, string> values = 1; + */ + public Builder putAllValues( + java.util.Map values) { + internalGetMutableValues().getMutableMap() + .putAll(values); + bitField0_ |= 0x00000001; + return this; + } + @java.lang.Override + public final Builder setUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return super.setUnknownFields(unknownFields); + } + + @java.lang.Override + public final Builder mergeUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return super.mergeUnknownFields(unknownFields); + } + + + // @@protoc_insertion_point(builder_scope:obs.Results) + } + + // @@protoc_insertion_point(class_scope:obs.Results) + private static final org.sensorhub.impl.service.consys.obs.proto.Observation.Results DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.sensorhub.impl.service.consys.obs.proto.Observation.Results(); + } + + public static org.sensorhub.impl.service.consys.obs.proto.Observation.Results getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public Results parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.sensorhub.impl.service.consys.obs.proto.Observation.Results getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + + } + + private static final com.google.protobuf.Descriptors.Descriptor + internal_static_obs_OshObservation_descriptor; + private static final + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internal_static_obs_OshObservation_fieldAccessorTable; + private static final com.google.protobuf.Descriptors.Descriptor + internal_static_obs_Results_descriptor; + private static final + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internal_static_obs_Results_fieldAccessorTable; + private static final com.google.protobuf.Descriptors.Descriptor + internal_static_obs_Results_ValuesEntry_descriptor; + private static final + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internal_static_obs_Results_ValuesEntry_fieldAccessorTable; + + public static com.google.protobuf.Descriptors.FileDescriptor + getDescriptor() { + return descriptor; + } + private static com.google.protobuf.Descriptors.FileDescriptor + descriptor; + static { + java.lang.String[] descriptorData = { + "\nJinclude/osh-core/sensorhub-service-con" + + "sys/src/main/proto/observation.proto\022\003ob" + + "s\"\214\001\n\016OshObservation\022\n\n\002id\030\001 \001(\t\022\024\n\014data" + + "streamId\030\002 \001(\t\022\r\n\005foiId\030\003 \001(\t\022\026\n\016phenome" + + "nonTime\030\004 \001(\t\022\022\n\nresultTime\030\005 \001(\t\022\035\n\007res" + + "ults\030\006 \001(\0132\014.obs.Results\"b\n\007Results\022(\n\006v" + + "alues\030\001 \003(\0132\030.obs.Results.ValuesEntry\032-\n" + + "\013ValuesEntry\022\013\n\003key\030\001 \001(\t\022\r\n\005value\030\002 \001(\t" + + ":\0028\001B:\n+org.sensorhub.impl.service.consy" + + "s.obs.protoB\013Observationb\006proto3" + }; + descriptor = com.google.protobuf.Descriptors.FileDescriptor + .internalBuildGeneratedFileFrom(descriptorData, + new com.google.protobuf.Descriptors.FileDescriptor[] { + }); + internal_static_obs_OshObservation_descriptor = + getDescriptor().getMessageTypes().get(0); + internal_static_obs_OshObservation_fieldAccessorTable = new + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( + internal_static_obs_OshObservation_descriptor, + new java.lang.String[] { "Id", "DatastreamId", "FoiId", "PhenomenonTime", "ResultTime", "Results", }); + internal_static_obs_Results_descriptor = + getDescriptor().getMessageTypes().get(1); + internal_static_obs_Results_fieldAccessorTable = new + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( + internal_static_obs_Results_descriptor, + new java.lang.String[] { "Values", }); + internal_static_obs_Results_ValuesEntry_descriptor = + internal_static_obs_Results_descriptor.getNestedTypes().get(0); + internal_static_obs_Results_ValuesEntry_fieldAccessorTable = new + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( + internal_static_obs_Results_ValuesEntry_descriptor, + new java.lang.String[] { "Key", "Value", }); + } + + // @@protoc_insertion_point(outer_class_scope) +} diff --git a/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/resource/BaseResourceHandler.java b/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/resource/BaseResourceHandler.java index a79de70239..d4a51533f6 100644 --- a/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/resource/BaseResourceHandler.java +++ b/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/resource/BaseResourceHandler.java @@ -39,6 +39,8 @@ import org.sensorhub.impl.service.consys.resource.RequestContext.ResourceRef; import org.vast.util.Asserts; +import javax.xml.stream.XMLStreamException; + /** *

@@ -77,7 +79,7 @@ protected BaseResourceHandler(S dataStore, IdEncoder idEncoder, HandlerContext c } - protected abstract ResourceBinding getBinding(RequestContext ctx, boolean forReading) throws IOException; + protected abstract ResourceBinding getBinding(RequestContext ctx, boolean forReading) throws IOException, XMLStreamException; protected abstract K getKey(final RequestContext ctx, final String id) throws InvalidRequestException; protected abstract String encodeKey(final RequestContext ctx, K key); protected abstract F getFilter(final ResourceRef parent, final Map queryParams, long offset, long limit) throws InvalidRequestException; @@ -86,8 +88,7 @@ protected BaseResourceHandler(S dataStore, IdEncoder idEncoder, HandlerContext c @Override - public void doGet(final RequestContext ctx) throws IOException - { + public void doGet(final RequestContext ctx) throws IOException, XMLStreamException { // if requesting from this resource collection if (ctx.isEndOfPath()) { @@ -201,8 +202,7 @@ protected void subscribeToEvents(final RequestContext ctx) throws IOException } - protected void getById(final RequestContext ctx, final String id) throws IOException - { + protected void getById(final RequestContext ctx, final String id) throws IOException, XMLStreamException { // check permissions ctx.getSecurityHandler().checkResourcePermission(permissions.get, id); @@ -215,8 +215,7 @@ protected void getById(final RequestContext ctx, final String id) throws IOExcep } - protected void getByKey(final RequestContext ctx, K key) throws IOException - { + protected void getByKey(final RequestContext ctx, K key) throws IOException, XMLStreamException { // fetch from data store final V res = dataStore.get(key); if (res != null) @@ -237,8 +236,7 @@ protected void getByKey(final RequestContext ctx, K key) throws IOException } - protected void list(final RequestContext ctx) throws IOException - { + protected void list(final RequestContext ctx) throws IOException, XMLStreamException { // check permissions var parentId = ctx.getParentRef().id; ctx.getSecurityHandler().checkParentPermission(permissions.list, parentId); @@ -260,8 +258,10 @@ protected void list(final RequestContext ctx) throws IOException ctx.setFormatOptions(responseFormat, parseSelectArg(queryParams)); // set default content type - ctx.setResponseContentType(ResourceFormat.JSON.getMimeType()); - + + ctx.setResponseContentType(responseFormat.getMimeType()); + + // stream and serialize all resources to servlet output var binding = getBinding(ctx, false); binding.startCollection(); @@ -348,8 +348,10 @@ protected void create(final RequestContext ctx) throws IOException catch (DataStoreException e) { throw ServiceErrors.requestRejected("Ingest Error: " + e.getMessage()); + } catch (XMLStreamException e) { + throw new RuntimeException(e); } - + if (count == 0) throw ServiceErrors.invalidPayload("No data provided"); } @@ -397,7 +399,7 @@ protected void update(final RequestContext ctx, final String id) throws IOExcept validate(res); } - catch (ResourceParseException e) + catch (ResourceParseException | XMLStreamException e) { throw ServiceErrors.invalidPayload("Invalid payload: " + e.getMessage()); } diff --git a/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/resource/IResourceHandler.java b/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/resource/IResourceHandler.java index 3d481fd633..674d4086c2 100644 --- a/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/resource/IResourceHandler.java +++ b/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/resource/IResourceHandler.java @@ -17,6 +17,8 @@ import java.io.IOException; import org.sensorhub.impl.service.consys.InvalidRequestException; +import javax.xml.stream.XMLStreamException; + public interface IResourceHandler { @@ -24,7 +26,7 @@ public interface IResourceHandler String[] getNames(); - void doGet(RequestContext ctx) throws InvalidRequestException, IOException, SecurityException; + void doGet(RequestContext ctx) throws InvalidRequestException, IOException, SecurityException, XMLStreamException; void doPost(RequestContext ctx) throws InvalidRequestException, IOException, SecurityException; diff --git a/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/resource/ResourceBinding.java b/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/resource/ResourceBinding.java index 436141532c..3d0f87cbb0 100644 --- a/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/resource/ResourceBinding.java +++ b/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/resource/ResourceBinding.java @@ -20,6 +20,8 @@ import org.sensorhub.impl.common.IdEncodersBase32; import org.vast.util.Asserts; +import javax.xml.stream.XMLStreamException; + /** *

@@ -49,9 +51,9 @@ protected ResourceBinding(RequestContext ctx, IdEncoders idEncoders) public abstract V deserialize() throws IOException; - public abstract void serialize(K key, V res, boolean showLinks) throws IOException; - public abstract void startCollection() throws IOException; - public abstract void endCollection(Collection links) throws IOException; + public abstract void serialize(K key, V res, boolean showLinks) throws IOException, XMLStreamException; + public abstract void startCollection() throws IOException, XMLStreamException; + public abstract void endCollection(Collection links) throws IOException, XMLStreamException; protected String getAbsoluteHref(String href) diff --git a/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/resource/ResourceBindingCotXml.java b/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/resource/ResourceBindingCotXml.java new file mode 100644 index 0000000000..4cfeece7fe --- /dev/null +++ b/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/resource/ResourceBindingCotXml.java @@ -0,0 +1,132 @@ +/***************************** BEGIN LICENSE BLOCK *************************** + +The contents of this file are subject to the Mozilla Public License, v. 2.0. +If a copy of the MPL was not distributed with this file, You can obtain one +at http://mozilla.org/MPL/2.0/. + +Software distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +for the specific language governing rights and limitations under the License. + +Copyright (C) 2020 Sensia Software LLC. All Rights Reserved. + +******************************* END LICENSE BLOCK ***************************/ + +package org.sensorhub.impl.service.consys.resource; + +import org.sensorhub.api.common.IdEncoders; +import org.vast.swe.fast.CotDataReader; +import org.vast.swe.fast.CotDataWriter; +import org.vast.xml.XMLImplFinder; + +import javax.xml.stream.XMLStreamException; +import java.io.*; +import java.nio.charset.StandardCharsets; +import java.util.Collection; +import java.util.Set; + + +/** + *

+ * Base class for all XML resource formatters + *

+ * + * @param Resource Key + * @param Resource Object + * + * @author Ashley Poteau + * @since Dec 3, 2025 + */ +public abstract class ResourceBindingCotXml extends ResourceBinding +{ + public static final String INVALID_XML_ERROR_MSG = "Invalid XML: "; + public static final String MISSING_PROP_ERROR_MSG = "Missing property: "; + + + protected final CotDataReader cotReader; + protected final CotDataWriter cotWriter; + + protected boolean isCollection; + + Set excludedProps; + Set includedProps; + + protected ResourceBindingCotXml(RequestContext ctx, IdEncoders idEncoders, boolean forReading) throws IOException + { + super(ctx, idEncoders); + + try + { + if (forReading) + { + var is = new BufferedInputStream(ctx.getInputStream()); + cotReader = getCotReader(is); + cotWriter = null; + } + else + { + var os = ctx.getOutputStream(); + cotWriter = getCotWriter(os); + cotReader = null; + } + } + catch (Exception e) + { + throw new IOException("Error initializing COT XML bindings", e); + } + } + + public abstract V deserialize(CotDataReader xmlReader) throws IOException; + public abstract void serialize(K key, V res, boolean showLinks, CotDataWriter xmlWriter) throws IOException, XMLStreamException; + + + protected CotDataReader getCotReader(InputStream is) throws IOException + { + var osr = new InputStreamReader(is, StandardCharsets.UTF_8); + return new CotDataReader(osr); + } + + protected CotDataWriter getCotWriter(OutputStream os) throws IOException + { + try { + CotDataWriter writer = new CotDataWriter(); + writer.setOutput(os); + return writer; + } catch (Exception e) { + throw new IOException("Error creating COT writer", e); + } + } + + @Override + public V deserialize() throws IOException + { + return deserialize(this.cotReader); + } + + @Override + public void serialize(K key, V res, boolean showLinks) throws IOException, XMLStreamException { + serialize(key, res, showLinks, this.cotWriter); + } + + @Override + public void startCollection() throws IOException, XMLStreamException { + isCollection = true; + if (cotWriter != null) { + cotWriter.startStream(true); + } + } + + @Override + public void endCollection(Collection links) throws IOException, XMLStreamException { + if (cotWriter != null) { + cotWriter.endStream(); + cotWriter.flush(); + } + } + + protected String getItemsPropertyName() + { + return "items"; + } + +} \ No newline at end of file diff --git a/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/resource/ResourceFormat.java b/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/resource/ResourceFormat.java index 352e6424f4..c07b69b560 100644 --- a/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/resource/ResourceFormat.java +++ b/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/resource/ResourceFormat.java @@ -28,6 +28,9 @@ public class ResourceFormat public static String SHORT_SMLJSON = "sml3"; public static String SHORT_SMLXML = "sml2"; public static String SHORT_HTML = "html"; + private static String SHORT_GEO_JSON = "geo_json"; + public static String SHORT_COTXML = "cot"; + public static String SHORT_PROTOBUF = "proto"; public static ResourceFormat HTML = new ResourceFormat("text/html", SHORT_HTML); public static ResourceFormat JSON = new ResourceFormat("application/json", SHORT_JSON); @@ -35,7 +38,13 @@ public class ResourceFormat public static ResourceFormat SML_JSON = new ResourceFormat("application/sml+json", SHORT_SMLJSON); public static ResourceFormat SML_XML = new ResourceFormat("application/sml+xml", SHORT_SMLXML); - + + public static ResourceFormat GEO_JSON = new ResourceFormat("application/geo+json", SHORT_GEO_JSON); + + public static ResourceFormat COT_XML = new ResourceFormat("application/cot+xml", SHORT_COTXML); + + public static ResourceFormat PROTOBUF = new ResourceFormat("application/protobuf", SHORT_PROTOBUF); + public static ResourceFormat OM_JSON = new ResourceFormat("application/om+json", SHORT_JSON); public static ResourceFormat OM_XML = new ResourceFormat("application/om+xml"); @@ -72,10 +81,16 @@ public static ResourceFormat fromShortName(String format) return ResourceFormat.JSON; else if (SHORT_GEOJSON.equals(format)) return ResourceFormat.GEOJSON; + else if (SHORT_GEO_JSON.equals(format)) + return ResourceFormat.GEO_JSON; + else if (SHORT_PROTOBUF.equals(format)) + return ResourceFormat.PROTOBUF; else if (SHORT_SMLJSON.equals(format)) return ResourceFormat.SML_JSON; else if (SHORT_SMLXML.equals(format)) return ResourceFormat.SML_XML; + else if (SHORT_COTXML.equals(format)) + return ResourceFormat.COT_XML; else if (SHORT_HTML.equals(format)) return ResourceFormat.HTML; else diff --git a/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/task/CommandBindingSweCommon.java b/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/task/CommandBindingSweCommon.java index 98cfdaf7a7..e3b90e42b8 100644 --- a/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/task/CommandBindingSweCommon.java +++ b/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/task/CommandBindingSweCommon.java @@ -76,6 +76,8 @@ public CommandBindingSweCommon(RequestContext ctx, IdEncoders idEncoders, boolea ctx.setResponseContentType(ResourceFormat.TEXT_PLAIN.getMimeType()); else if (ctx.getFormat().equals(ResourceFormat.SWE_XML)) ctx.setResponseContentType(ResourceFormat.APPLI_XML.getMimeType()); + else if (ctx.getFormat().equals(ResourceFormat.COT_XML)) + ctx.setResponseContentType(ResourceFormat.APPLI_XML.getMimeType()); else ctx.setResponseContentType(ctx.getFormat().getMimeType()); } diff --git a/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/task/CommandHandler.java b/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/task/CommandHandler.java index b4006ec316..6ff2c99ae6 100644 --- a/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/task/CommandHandler.java +++ b/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/task/CommandHandler.java @@ -57,6 +57,8 @@ import org.sensorhub.utils.CallbackException; import org.vast.util.Asserts; +import javax.xml.stream.XMLStreamException; + public class CommandHandler extends BaseResourceHandler { @@ -249,6 +251,8 @@ public void onNext(CommandEvent event) { subscription.cancel(); throw new CallbackException(e); + } catch (XMLStreamException e) { + throw new RuntimeException(e); } } diff --git a/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/task/CommandResultBindingSweCommon.java b/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/task/CommandResultBindingSweCommon.java index 9120e206b2..1143c95d39 100644 --- a/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/task/CommandResultBindingSweCommon.java +++ b/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/task/CommandResultBindingSweCommon.java @@ -71,6 +71,8 @@ public CommandResultBindingSweCommon(RequestContext ctx, IdEncoders idEncoders, ctx.setResponseContentType(ResourceFormat.TEXT_PLAIN.getMimeType()); else if (ctx.getFormat().equals(ResourceFormat.SWE_XML)) ctx.setResponseContentType(ResourceFormat.APPLI_XML.getMimeType()); + else if (ctx.getFormat().equals(ResourceFormat.COT_XML)) + ctx.setResponseContentType(ResourceFormat.APPLI_XML.getMimeType()); else ctx.setResponseContentType(ctx.getFormat().getMimeType()); } diff --git a/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/task/CommandStatusHandler.java b/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/task/CommandStatusHandler.java index c7cf1be540..7537f480cf 100644 --- a/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/task/CommandStatusHandler.java +++ b/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/task/CommandStatusHandler.java @@ -48,6 +48,8 @@ import org.sensorhub.utils.CallbackException; import org.vast.util.Asserts; +import javax.xml.stream.XMLStreamException; + public class CommandStatusHandler extends BaseResourceHandler { @@ -201,6 +203,8 @@ public void onNext(CommandStatusEvent event) { subscription.cancel(); throw new CallbackException(e); + } catch (XMLStreamException e) { + throw new RuntimeException(e); } } diff --git a/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/task/CommandStreamBindingJson.java b/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/task/CommandStreamBindingJson.java index b57b19d185..b4fee8b692 100644 --- a/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/task/CommandStreamBindingJson.java +++ b/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/task/CommandStreamBindingJson.java @@ -287,6 +287,7 @@ public void serialize(CommandStreamKey key, ICommandStreamInfo csInfo, boolean s writer.value(ResourceFormat.SWE_JSON.getMimeType()); writer.value(ResourceFormat.SWE_TEXT.getMimeType()); writer.value(ResourceFormat.SWE_XML.getMimeType()); + writer.value(ResourceFormat.COT_XML.getMimeType()); } writer.value(ResourceFormat.SWE_BINARY.getMimeType()); writer.endArray(); diff --git a/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/task/CommandStreamSchemaHandler.java b/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/task/CommandStreamSchemaHandler.java index 86c4f533df..92f3773615 100644 --- a/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/task/CommandStreamSchemaHandler.java +++ b/sensorhub-service-consys/src/main/java/org/sensorhub/impl/service/consys/task/CommandStreamSchemaHandler.java @@ -32,6 +32,8 @@ import org.sensorhub.impl.service.consys.resource.RequestContext.ResourceRef; import org.vast.util.Asserts; +import javax.xml.stream.XMLStreamException; + public class CommandStreamSchemaHandler extends ResourceHandler { @@ -96,8 +98,7 @@ public void doDelete(final RequestContext ctx) throws IOException @Override - public void doGet(RequestContext ctx) throws IOException - { + public void doGet(RequestContext ctx) throws IOException, XMLStreamException { if (ctx.isEndOfPath()) getById(ctx, ""); else @@ -106,8 +107,7 @@ public void doGet(RequestContext ctx) throws IOException @Override - protected void getById(final RequestContext ctx, final String id) throws IOException - { + protected void getById(final RequestContext ctx, final String id) throws IOException, XMLStreamException { // check permissions var parentId = ctx.getParentRef().id; ctx.getSecurityHandler().checkParentPermission(permissions.get, parentId); diff --git a/sensorhub-service-consys/src/main/proto/observation.proto b/sensorhub-service-consys/src/main/proto/observation.proto new file mode 100644 index 0000000000..132546c83a --- /dev/null +++ b/sensorhub-service-consys/src/main/proto/observation.proto @@ -0,0 +1,24 @@ +syntax = "proto3"; + +package obs; + +option java_package = "org.sensorhub.impl.service.consys.obs.proto"; +option java_outer_classname = "Observation"; + +message OshObservation { + + string id = 1; + string datastreamId = 2; + string foiId = 3; + string phenomenonTime = 4; + string resultTime = 5; + + Results results = 6; + +} + +message Results { + + map values = 1; + +}