org.n52.svalbard.encode.GmlEncoderv311 Maven / Gradle / Ivy
The newest version!
/*
* Copyright (C) 2015-2022 52°North Spatial Information Research GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.n52.svalbard.encode;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.Set;
import javax.xml.namespace.QName;
import org.apache.xmlbeans.XmlCursor;
import org.apache.xmlbeans.XmlObject;
import org.apache.xmlbeans.XmlRuntimeException;
import org.apache.xmlbeans.impl.values.XmlValueDisconnectedException;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.LineString;
import org.locationtech.jts.geom.Point;
import org.locationtech.jts.geom.Polygon;
import org.locationtech.jts.geom.util.PolygonExtracter;
import org.n52.faroe.annotation.Configurable;
import org.n52.faroe.annotation.Setting;
import org.n52.shetland.ogc.HasDefaultEncoding;
import org.n52.shetland.ogc.gml.AbstractFeature;
import org.n52.shetland.ogc.gml.CodeWithAuthority;
import org.n52.shetland.ogc.gml.GenericMetaData;
import org.n52.shetland.ogc.gml.GmlConstants;
import org.n52.shetland.ogc.gml.time.IndeterminateValue;
import org.n52.shetland.ogc.gml.time.Time;
import org.n52.shetland.ogc.gml.time.TimeInstant;
import org.n52.shetland.ogc.gml.time.TimePeriod;
import org.n52.shetland.ogc.gml.time.TimePosition;
import org.n52.shetland.ogc.om.features.FeatureCollection;
import org.n52.shetland.ogc.om.features.SfConstants;
import org.n52.shetland.ogc.om.features.samplingFeatures.SamplingFeature;
import org.n52.shetland.ogc.om.values.CategoryValue;
import org.n52.shetland.ogc.om.values.QuantityValue;
import org.n52.shetland.ogc.swe.SweConstants;
import org.n52.shetland.util.CRSHelper;
import org.n52.shetland.util.DateTimeFormatException;
import org.n52.shetland.util.DateTimeHelper;
import org.n52.shetland.util.EnvelopeOrGeometry;
import org.n52.shetland.util.IdGenerator;
import org.n52.shetland.util.JTSHelper;
import org.n52.shetland.util.MinMax;
import org.n52.shetland.util.ReferencedEnvelope;
import org.n52.shetland.w3c.SchemaLocation;
import org.n52.svalbard.CodingSettings;
import org.n52.svalbard.encode.exception.EncodingException;
import org.n52.svalbard.encode.exception.UnsupportedEncoderInputException;
import org.n52.svalbard.util.CodingHelper;
import org.n52.svalbard.util.XmlHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.base.Joiner;
import com.google.common.collect.Sets;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import net.opengis.gml.AbstractFeatureCollectionType;
import net.opengis.gml.AbstractRingPropertyType;
import net.opengis.gml.AbstractRingType;
import net.opengis.gml.CodeType;
import net.opengis.gml.DirectPositionListType;
import net.opengis.gml.DirectPositionType;
import net.opengis.gml.EnvelopeType;
import net.opengis.gml.FeatureCollectionDocument2;
import net.opengis.gml.FeaturePropertyType;
import net.opengis.gml.LineStringType;
import net.opengis.gml.LinearRingType;
import net.opengis.gml.MeasureType;
import net.opengis.gml.PointType;
import net.opengis.gml.PolygonType;
import net.opengis.gml.ReferenceType;
import net.opengis.gml.TimeIndeterminateValueType;
import net.opengis.gml.TimeInstantDocument;
import net.opengis.gml.TimeInstantType;
import net.opengis.gml.TimePeriodDocument;
import net.opengis.gml.TimePeriodType;
import net.opengis.gml.TimePositionType;
/**
* @since 1.0.0
*
*/
@Configurable
public class GmlEncoderv311
extends AbstractXmlEncoder {
private static final Logger LOGGER = LoggerFactory.getLogger(GmlEncoderv311.class);
private static final Set ENCODER_KEYS = CodingHelper.encoderKeysForElements(GmlConstants.NS_GML,
org.n52.shetland.ogc.gml.time.Time.class, org.locationtech.jts.geom.Geometry.class,
org.n52.shetland.ogc.om.values.CategoryValue.class, org.n52.shetland.ogc.gml.ReferenceType.class,
org.n52.shetland.ogc.om.values.QuantityValue.class, org.n52.shetland.ogc.gml.CodeWithAuthority.class,
org.n52.shetland.ogc.gml.CodeType.class, AbstractFeature.class, GenericMetaData.class,
org.n52.shetland.util.ReferencedEnvelope.class, org.n52.shetland.util.EnvelopeOrGeometry.class);
private String srsNamePrefix = "urn:ogc:def:crs:EPSG::";
public GmlEncoderv311() {
LOGGER.debug("Encoder for the following keys initialized successfully: {}!",
Joiner.on(", ").join(ENCODER_KEYS));
}
@Setting(value = CodingSettings.SRS_NAME_PREFIX_URN, required = false)
public void setSrsNamePrefix(String prefix) {
srsNamePrefix = CRSHelper.asUrnPrefix(prefix);
}
@Override
public Set getKeys() {
return Collections.unmodifiableSet(ENCODER_KEYS);
}
@Override
public void addNamespacePrefixToMap(Map nameSpacePrefixMap) {
nameSpacePrefixMap.put(GmlConstants.NS_GML, GmlConstants.NS_GML_PREFIX);
}
@Override
public Set getSchemaLocations() {
return Sets.newHashSet(GmlConstants.GML_311_SCHEMAL_LOCATION);
}
@Override
public XmlObject encode(Object element, EncodingContext ctx) throws EncodingException {
XmlObject encodedObject = null;
if (element instanceof Time) {
encodedObject = createTime((Time) element, ctx);
} else if (element instanceof Geometry) {
encodedObject = createPosition((Geometry) element, ctx.get(XmlBeansEncodingFlags.GMLID));
} else if (element instanceof CategoryValue) {
encodedObject = createReferenceTypeForCategroyValue((CategoryValue) element);
} else if (element instanceof org.n52.shetland.ogc.gml.ReferenceType) {
encodedObject = createReferencType((org.n52.shetland.ogc.gml.ReferenceType) element);
} else if (element instanceof CodeWithAuthority) {
encodedObject = createCodeWithAuthorityType((CodeWithAuthority) element);
} else if (element instanceof QuantityValue) {
encodedObject = createMeasureType((QuantityValue) element);
} else if (element instanceof org.n52.shetland.ogc.gml.CodeType) {
encodedObject = createCodeType((org.n52.shetland.ogc.gml.CodeType) element);
} else if (element instanceof AbstractFeature) {
encodedObject = createFeature((AbstractFeature) element);
} else if (element instanceof ReferencedEnvelope) {
encodedObject = createEnvelope((ReferencedEnvelope) element);
} else if (element instanceof EnvelopeOrGeometry) {
EnvelopeOrGeometry geom = (EnvelopeOrGeometry) element;
if (geom.getGeometry().isPresent()) {
encodedObject = createPosition(geom.getGeometry().get(), ctx.get(XmlBeansEncodingFlags.GMLID));
} else if (geom.getEnvelope().isPresent()) {
encodedObject = createEnvelope(geom.getEnvelope().get());
} else {
throw new UnsupportedEncoderInputException(this, element);
}
} else if (element instanceof GenericMetaData) {
encodedObject = createGenericMetaData((GenericMetaData) element, ctx);
} else {
throw new UnsupportedEncoderInputException(this, element);
}
XmlHelper.validateDocument(encodedObject, EncodingException::new);
return encodedObject;
}
private XmlObject createTime(Time time, EncodingContext ctx) throws EncodingException {
if (time != null) {
if (time instanceof TimeInstant) {
if (ctx.has(XmlBeansEncodingFlags.DOCUMENT)) {
return createTimeInstantDocument((TimeInstant) time);
} else {
return createTimeInstantType((TimeInstant) time, null);
}
} else if (time instanceof TimePeriod) {
if (ctx.has(XmlBeansEncodingFlags.DOCUMENT)) {
return createTimePeriodDocument((TimePeriod) time);
} else {
return createTimePeriodType((TimePeriod) time, null);
}
} else {
throw new UnsupportedEncoderInputException(this, time);
}
}
return null;
}
private XmlObject createTimePeriodDocument(TimePeriod time) throws EncodingException {
TimePeriodDocument timePeriodDoc = TimePeriodDocument.Factory.newInstance(getXmlOptions());
createTimePeriodType(time, timePeriodDoc.addNewTimePeriod());
return timePeriodDoc;
}
/**
* Creates a XML TimePeriod from the SOS time object.
*
* @param timePeriod
* SOS time object
* @param timePeriodType
* the xml time period (may be {@code null})
* @return XML TimePeriod
*
*
* @throws EncodingException
* if an error occurs.
*/
private TimePeriodType createTimePeriodType(TimePeriod timePeriod, TimePeriodType timePeriodType)
throws EncodingException {
try {
TimePeriodType tpt;
if (timePeriodType == null) {
tpt = TimePeriodType.Factory.newInstance(getXmlOptions());
} else {
tpt = timePeriodType;
}
if (timePeriod.getGmlId() != null && !timePeriod.getGmlId().isEmpty()) {
tpt.setId(timePeriod.getGmlId());
}
tpt.setBeginPosition(createTimePositionType(timePeriod.getStartTimePosition()));
tpt.setEndPosition(createTimePositionType(timePeriod.getEndTimePosition()));
return tpt;
} catch (XmlRuntimeException | XmlValueDisconnectedException x) {
throw new EncodingException("Error while creating TimePeriod!", x);
}
}
private XmlObject createTimeInstantDocument(TimeInstant time) {
TimeInstantDocument timeInstantDoc = TimeInstantDocument.Factory.newInstance(getXmlOptions());
createTimeInstantType(time, timeInstantDoc.addNewTimeInstant());
return timeInstantDoc;
}
/**
* Creates a XML TimeInstant from the SOS time object.
*
* @param timeInstant
* SOS time object
* @param timeInstantType
* the xml time instant (may be {@code null})
* @return XML TimeInstant
*
*/
private TimeInstantType createTimeInstantType(TimeInstant timeInstant, TimeInstantType timeInstantType) {
// create time instant
TimeInstantType tit;
if (timeInstantType == null) {
tit = TimeInstantType.Factory.newInstance(getXmlOptions());
} else {
tit = timeInstantType;
}
if (timeInstant.isSetGmlId()) {
tit.setId(timeInstant.getGmlId());
}
tit.setTimePosition(createTimePositionType(timeInstant.getTimePosition()));
return tit;
}
private TimePositionType createTimePositionType(final TimePosition timePosition) throws DateTimeFormatException {
final TimePositionType xbTimePosition = TimePositionType.Factory.newInstance();
if (!timePosition.isSetTime()) {
if (timePosition.isSetIndeterminateValue()) {
xbTimePosition.setIndeterminatePosition(
TimeIndeterminateValueType.Enum.forString(timePosition.getIndeterminateValue().getValue()));
} else {
xbTimePosition.setIndeterminatePosition(
TimeIndeterminateValueType.Enum.forString(IndeterminateValue.UNKNOWN.getValue()));
}
} else {
final String endString =
DateTimeHelper.formatDateTime2String(timePosition.getTime(), timePosition.getTimeFormat());
// concat minutes for timeZone offset, because gml requires
// xs:dateTime, which needs minutes in
// timezone offset
// TODO enable really
xbTimePosition.setStringValue(endString);
}
return xbTimePosition;
}
private XmlObject createPosition(Geometry geom, Optional