/**
* Copyright (C) 2012-2017 52°North Initiative for Geospatial Open Source
* Software GmbH
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation.
*
* If the program is linked with libraries which are licensed under one of
* the following licenses, the combination of the program with the linked
* library is not considered a "derivative work" of the program:
*
* - Apache License, version 2.0
* - Apache Software License, version 1.0
* - GNU Lesser General Public License, version 3
* - Mozilla Public License, versions 1.0, 1.1 and 2.0
* - Common Development and Distribution License (CDDL), version 1.0
*
* Therefore the distribution of the program linked with libraries licensed
* under the aforementioned licenses, is permitted by the copyright holders
* if the distribution is compliant with both the GNU General Public
* License version 2 and the aforementioned licenses.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*/
package org.n52.sos.converter;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.n52.sos.convert.RequestResponseModifier;
import org.n52.sos.convert.RequestResponseModifierFacilitator;
import org.n52.sos.convert.RequestResponseModifierKeyType;
import org.n52.sos.exception.ows.InvalidParameterValueException;
import org.n52.sos.exception.ows.MissingParameterValueException;
import org.n52.sos.exception.ows.NoApplicableCodeException;
import org.n52.sos.ogc.filter.SpatialFilter;
import org.n52.sos.ogc.gml.AbstractFeature;
import org.n52.sos.ogc.om.AbstractStreaming;
import org.n52.sos.ogc.om.NamedValue;
import org.n52.sos.ogc.om.OmObservation;
import org.n52.sos.ogc.om.features.FeatureCollection;
import org.n52.sos.ogc.om.features.samplingFeatures.SamplingFeature;
import org.n52.sos.ogc.ows.OWSConstants;
import org.n52.sos.ogc.ows.OwsExceptionReport;
import org.n52.sos.ogc.sensorML.AbstractComponent;
import org.n52.sos.ogc.sensorML.AbstractProcess;
import org.n52.sos.ogc.sensorML.AbstractSensorML;
import org.n52.sos.ogc.sensorML.SensorML;
import org.n52.sos.ogc.sensorML.SensorMLConstants;
import org.n52.sos.ogc.sensorML.System;
import org.n52.sos.ogc.sensorML.elements.SmlCapabilities;
import org.n52.sos.ogc.sensorML.elements.SmlComponent;
import org.n52.sos.ogc.sensorML.elements.SmlLocation;
import org.n52.sos.ogc.sensorML.elements.SmlPosition;
import org.n52.sos.ogc.sensorML.v20.AbstractPhysicalProcess;
import org.n52.sos.ogc.sos.Sos1Constants;
import org.n52.sos.ogc.sos.Sos2Constants;
import org.n52.sos.ogc.sos.SosConstants;
import org.n52.sos.ogc.sos.SosEnvelope;
import org.n52.sos.ogc.sos.SosObservationOffering;
import org.n52.sos.ogc.sos.SosProcedureDescription;
import org.n52.sos.ogc.swe.SweConstants;
import org.n52.sos.ogc.swe.SweConstants.SweCoordinateName;
import org.n52.sos.ogc.swe.SweCoordinate;
import org.n52.sos.ogc.swe.SweEnvelope;
import org.n52.sos.ogc.swe.SweField;
import org.n52.sos.ogc.swe.SweVector;
import org.n52.sos.ogc.swe.simpleType.SweCount;
import org.n52.sos.ogc.swe.simpleType.SweQuantity;
import org.n52.sos.ogc.swe.simpleType.SweText;
import org.n52.sos.request.AbstractServiceRequest;
import org.n52.sos.request.DescribeSensorRequest;
import org.n52.sos.request.GetCapabilitiesRequest;
import org.n52.sos.request.GetFeatureOfInterestRequest;
import org.n52.sos.request.GetObservationByIdRequest;
import org.n52.sos.request.GetObservationRequest;
import org.n52.sos.request.GetResultRequest;
import org.n52.sos.request.InsertObservationRequest;
import org.n52.sos.request.InsertResultTemplateRequest;
import org.n52.sos.request.SrsNameRequest;
import org.n52.sos.response.AbstractServiceResponse;
import org.n52.sos.response.DescribeSensorResponse;
import org.n52.sos.response.GetCapabilitiesResponse;
import org.n52.sos.response.GetFeatureOfInterestResponse;
import org.n52.sos.response.GetObservationByIdResponse;
import org.n52.sos.response.GetObservationResponse;
import org.n52.sos.response.GetResultResponse;
import org.n52.sos.response.InsertObservationResponse;
import org.n52.sos.response.InsertResultTemplateResponse;
import org.n52.sos.service.ProcedureDescriptionSettings;
import org.n52.sos.service.ServiceConfiguration;
import org.n52.sos.util.CollectionHelper;
import org.n52.sos.util.Constants;
import org.n52.sos.util.EpsgConstants;
import org.n52.sos.util.GeometryHandler;
import org.n52.sos.util.JTSHelper;
import org.n52.sos.util.StringHelper;
import org.n52.sos.util.SweHelper;
import com.google.common.base.Joiner;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.vividsolutions.jts.geom.Envelope;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.Point;
/**
* Class that transforms geometries in the requests to the stored EPSG code and
* transforms geometries in the responses to the default response or requested
* EPSG code.
*
* @author Carsten Hollmann <c.hollmann@52north.org>
*
* @since 4.1.0
*
*/
public class CoordinateTransformator implements
RequestResponseModifier<AbstractServiceRequest<?>, AbstractServiceResponse> {
private static final Set<RequestResponseModifierKeyType> REQUEST_RESPONSE_MODIFIER_KEY_TYPES = getKeyTypes();
/**
* Get the keys
*
* @return Set of keys
*/
private static Set<RequestResponseModifierKeyType> getKeyTypes() {
Set<String> services = Sets.newHashSet(SosConstants.SOS);
Set<String> versions = Sets.newHashSet(Sos1Constants.SERVICEVERSION, Sos2Constants.SERVICEVERSION);
Map<AbstractServiceRequest<?>, AbstractServiceResponse> requestResponseMap = Maps.newHashMap();
requestResponseMap.put(new GetCapabilitiesRequest(), new GetCapabilitiesResponse());
requestResponseMap.put(new GetObservationRequest(), new GetObservationResponse());
requestResponseMap.put(new GetObservationByIdRequest(), new GetObservationByIdResponse());
requestResponseMap.put(new GetFeatureOfInterestRequest(), new GetFeatureOfInterestResponse());
requestResponseMap.put(new InsertObservationRequest(), new InsertObservationResponse());
requestResponseMap.put(new InsertResultTemplateRequest(), new InsertResultTemplateResponse());
requestResponseMap.put(new GetResultRequest(), new GetResultResponse());
requestResponseMap.put(new DescribeSensorRequest(), new DescribeSensorResponse());
Set<RequestResponseModifierKeyType> keys = Sets.newHashSet();
for (String service : services) {
for (String version : versions) {
for (AbstractServiceRequest<?> request : requestResponseMap.keySet()) {
keys.add(new RequestResponseModifierKeyType(service, version, request));
keys.add(new RequestResponseModifierKeyType(service, version, request, requestResponseMap
.get(request)));
}
}
}
return keys;
}
@Override
public Set<RequestResponseModifierKeyType> getRequestResponseModifierKeyTypes() {
return Collections.unmodifiableSet(REQUEST_RESPONSE_MODIFIER_KEY_TYPES);
}
@Override
public AbstractServiceRequest<?> modifyRequest(AbstractServiceRequest<?> request) throws OwsExceptionReport {
checkRequestIfCrsIsSetAndSupported(request);
if (request instanceof GetFeatureOfInterestRequest) {
return modifyGetFeatureOfInterestRequest((GetFeatureOfInterestRequest) request);
} else if (request instanceof GetObservationRequest) {
return modifyGetObservationRequest((GetObservationRequest) request);
} else if (request instanceof GetResultRequest) {
return modifyGetResultRequest((GetResultRequest) request);
} else if (request instanceof InsertObservationRequest) {
return modifyInsertObservationRequest((InsertObservationRequest) request);
} else if (request instanceof InsertResultTemplateRequest) {
return modifyInsertResultTemplateRequest((InsertResultTemplateRequest) request);
}
return request;
}
@Override
public AbstractServiceResponse modifyResponse(AbstractServiceRequest<?> request, AbstractServiceResponse response)
throws OwsExceptionReport {
if (request instanceof GetFeatureOfInterestRequest && response instanceof GetFeatureOfInterestResponse) {
return modifyGetFeatureOfInterestResponse((GetFeatureOfInterestRequest) request,
(GetFeatureOfInterestResponse) response);
} else if (request instanceof GetObservationRequest && response instanceof GetObservationResponse) {
return modifyGetObservationResponse((GetObservationRequest) request, (GetObservationResponse) response);
} else if (request instanceof GetObservationByIdRequest && response instanceof GetObservationByIdResponse) {
return modifyGetObservationByIdResponse((GetObservationByIdRequest) request,
(GetObservationByIdResponse) response);
} else if (request instanceof GetCapabilitiesRequest && response instanceof GetCapabilitiesResponse) {
return modifyGetCapabilitiesResponse((GetCapabilitiesRequest) request, (GetCapabilitiesResponse) response);
} else if (request instanceof DescribeSensorRequest && response instanceof DescribeSensorResponse) {
return modifyDescribeSensorResponse((DescribeSensorRequest) request, (DescribeSensorResponse) response);
}
return response;
}
/**
* Modify the GetFeatureOfInterest request
*
* @param request
* the GetFeatureOfInterest request
* @return Modified the GetFeatureOfInterest request
* @throws OwsExceptionReport
* If the transformation fails
*/
private AbstractServiceRequest<?> modifyGetFeatureOfInterestRequest(GetFeatureOfInterestRequest request)
throws OwsExceptionReport {
if (request.isSetSpatialFilters()) {
preProcessSpatialFilters(request.getSpatialFilters());
}
return request;
}
/**
* Modify the GetObservation request
*
* @param request
* the GetObservation request
* @return Modified the GetObservation request
* @throws OwsExceptionReport
* If the transformation fails
*/
private AbstractServiceRequest<?> modifyGetObservationRequest(GetObservationRequest request)
throws OwsExceptionReport {
if (request.isSetSpatialFilter()) {
preProcessSpatialFilter(request.getSpatialFilter());
}
return request;
}
/**
* Modify the GetResult request
*
* @param request
* the GetResult request
* @return Modified the GetResult request
* @throws OwsExceptionReport
* If the transformation fails
*/
private AbstractServiceRequest<?> modifyGetResultRequest(GetResultRequest request) throws OwsExceptionReport {
if (request.isSetSpatialFilter()) {
preProcessSpatialFilter(request.getSpatialFilter());
}
return request;
}
/**
* Modify the InsertObservation request
*
* @param request
* the InsertObservation request
* @return Modified the InsertObservation request
* @throws OwsExceptionReport
* If the transformation fails
*/
private AbstractServiceRequest<?> modifyInsertObservationRequest(InsertObservationRequest request)
throws OwsExceptionReport {
if (request.isSetObservation()) {
checkRequestedObservations(request.getObservations());
}
return request;
}
/**
* Modify the InsertResultTemplate request
*
* @param request
* the InsertResultTemplate request
* @return Modified the InsertResultTemplate request
* @throws OwsExceptionReport
* If the transformation fails
*/
private AbstractServiceRequest<?> modifyInsertResultTemplateRequest(InsertResultTemplateRequest request)
throws OwsExceptionReport {
if (request.getObservationTemplate().getFeatureOfInterest() instanceof SamplingFeature) {
checkResponseGeometryOfSamplingFeature((SamplingFeature) request.getObservationTemplate()
.getFeatureOfInterest(), getGeomtryHandler().getStorageEPSG());
}
return request;
}
/**
* Modify the GetFeatureOfInterest response
*
* @param request
* the GetFeatureOfInterest request
* @return Modified the GetFeatureOfInterest request
* @param response
* the GetFeatureOfInterest response
* @return Modified the GetFeatureOfInterest response
* @throws OwsExceptionReport
* If the transformation fails
*/
private AbstractServiceResponse modifyGetFeatureOfInterestResponse(GetFeatureOfInterestRequest request,
GetFeatureOfInterestResponse response) throws OwsExceptionReport {
processAbstractFeature(response.getAbstractFeature(), getRequestedCrs(request));
return response;
}
/**
* Modify the GetObservation response
*
* @param request
* the GetObservation request
* @return Modified the GetObservation request
* @param response
* the GetObservation response
* @return Modified the GetObservation response
* @throws OwsExceptionReport
* If the transformation fails
*/
private AbstractServiceResponse modifyGetObservationResponse(GetObservationRequest request,
GetObservationResponse response) throws OwsExceptionReport {
response.setResponseFormat(request.getResponseFormat());
checkResponseObservations(response.getObservationCollection(), getRequestedCrs(request));
return response;
}
/**
* Modify the GetObservationById response
*
* @param request
* the GetObservationById request
* @return Modified the GetObservationById request
* @param response
* the GetObservationById response
* @return Modified the GetObservationById response
* @throws OwsExceptionReport
* If the transformation fails
*/
private AbstractServiceResponse modifyGetObservationByIdResponse(GetObservationByIdRequest request,
GetObservationByIdResponse response) throws OwsExceptionReport {
checkResponseObservations(response.getObservationCollection(), getRequestedCrs(request));
return response;
}
/**
* Modify the GetCapabilities response
*
* @param request
* the GetCapabilities request
* @return Modified the GetCapabilities request
* @param response
* the GetCapabilities response
* @return Modified the GetCapabilities response
* @throws OwsExceptionReport
* If an error occurs
*/
private AbstractServiceResponse modifyGetCapabilitiesResponse(GetCapabilitiesRequest request,
GetCapabilitiesResponse response) throws OwsExceptionReport {
if (response.getCapabilities().isSetContents()) {
for (SosObservationOffering sosObservationOffering : response.getCapabilities().getContents()) {
if (sosObservationOffering.isSetObservedArea()) {
SosEnvelope observedArea = sosObservationOffering.getObservedArea();
int targetSrid = getRequestedCrs(request);
Envelope transformEnvelope =
getGeomtryHandler().transformEnvelope(observedArea.getEnvelope(), observedArea.getSrid(),
targetSrid);
observedArea.setEnvelope(transformEnvelope);
observedArea.setSrid(targetSrid);
sosObservationOffering.setObservedArea(observedArea);
}
}
}
return response;
}
/**
* Modify the DescribeSensor response
*
* @param request
* the DescribeSensor request
* @return Modified the DescribeSensor request
* @param response
* the DescribeSensor response
* @return Modified the DescribeSensor response
* @throws OwsExceptionReport
* If the transformation fails
*/
private AbstractServiceResponse modifyDescribeSensorResponse(DescribeSensorRequest request,
DescribeSensorResponse response) throws NumberFormatException, OwsExceptionReport {
int requestedCrs = getRequestedCrs(request);
if (response.isSetProcedureDescriptions()) {
for (SosProcedureDescription description : response.getProcedureDescriptions()) {
if (description instanceof AbstractSensorML) {
checkAbstractSensorML((AbstractSensorML) description, requestedCrs);
}
}
}
return response;
}
/**
* Check the {@link AbstractSensorML} if modifications are required
*
* @param abstractSensorML
* {@link AbstractSensorML} to check
* @param targetCrs
* Target EPSG code Target EPSG code
* @throws OwsExceptionReport
* If the transformation fails
*/
private void checkAbstractSensorML(AbstractSensorML abstractSensorML, int targetCrs) throws OwsExceptionReport {
if (abstractSensorML instanceof SensorML) {
checkCapabilitiesForObservedAreaAndTransform(abstractSensorML, targetCrs);
if (((SensorML) abstractSensorML).isSetMembers()) {
for (AbstractProcess member : ((SensorML) abstractSensorML).getMembers()) {
checkCapabilitiesForObservedAreaAndTransform(member, targetCrs);
checkAbstractProcess(member, targetCrs);
}
}
} else {
checkAbstractProcess(abstractSensorML, targetCrs);
}
}
/**
* Check the {@link AbstractProcess} if modifications are required
*
* @param abstractProcess
* {@link AbstractProcess} to check
* @param targetCrs
* Target EPSG code
* @throws OwsExceptionReport
* If the transformation fails
*/
private void checkAbstractProcess(AbstractSensorML abstractSensorML, int targetCrs) throws OwsExceptionReport {
if (abstractSensorML instanceof AbstractComponent) {
AbstractComponent abstractComponent = (AbstractComponent) abstractSensorML;
if (abstractComponent.isSetPosition()) {
transformPosition(abstractComponent.getPosition(), targetCrs);
} else if (abstractComponent.isSetLocation()) {
transformLocation(abstractComponent.getLocation(), targetCrs);
}
if (abstractComponent instanceof System && ((System) abstractComponent).isSetComponents()) {
for (SmlComponent component : ((System) abstractComponent).getComponents()) {
if (component.isSetProcess()) {
checkAbstractSensorML(component.getProcess(), targetCrs);
}
}
}
} else if (abstractSensorML instanceof AbstractPhysicalProcess) {
AbstractPhysicalProcess process = (AbstractPhysicalProcess) abstractSensorML;
if (process.isSetPosition()) {
transformPosition(process.getPosition(), targetCrs);
}
}
}
/**
* Check the {@link SmlPosition} if modifications are required
*
* @param position
* {@link SmlPosition} to check
* @param targetCrs
* Target EPSG code
* @throws OwsExceptionReport
* If the transformation fails
*/
private void transformPosition(SmlPosition position, int targetCrs) throws OwsExceptionReport {
int sourceCrs = targetCrs;
if (position.isSetReferenceFrame()) {
sourceCrs = getCrsFromString(position.getReferenceFrame());
} else if (position.isSetVector() && position.getVector().isSetReferenceFrame()) {
sourceCrs = getCrsFromString(position.getVector().getReferenceFrame());
}
if (position.isSetPosition()) {
position.setPosition(transformSweCoordinates(position.getPosition(), sourceCrs, targetCrs));
position.setReferenceFrame(ServiceConfiguration.getInstance().getSrsNamePrefix() + targetCrs);
} else if (position.isSetVector()) {
SweVector vector = position.getVector();
vector.setCoordinates(transformSweCoordinates(vector.getCoordinates(), sourceCrs, targetCrs));
vector.setReferenceFrame(ServiceConfiguration.getInstance().getSrsNamePrefix() + targetCrs);
}
}
/**
* Transform coordinates
*
* @param position
* {@link SweCoordinate}s to transform
* @param sourceCrs
* Source CRS
* @param targetCrs
* Target CRS
* @return Transformed {@link SweCoordinate}s
* @throws OwsExceptionReport
* if an error occurs
*/
private List<SweCoordinate<?>> transformSweCoordinates(List<SweCoordinate<?>> position, int sourceCrs,
int targetCrs) throws OwsExceptionReport {
SweCoordinate<?> altitude = null;
Object easting = null;
Object northing = null;
for (SweCoordinate<?> coordinate : position) {
if (SweCoordinateName.altitude.name().equals(coordinate.getName())) {
altitude = coordinate;
} else if (SweCoordinateName.northing.name().equals(coordinate.getName())) {
northing = coordinate.getValue().getValue();
} else if (SweCoordinateName.easting.name().equals(coordinate.getName())) {
easting = coordinate.getValue().getValue();
}
}
List<Object> coordinates = Lists.newArrayListWithExpectedSize(Constants.INT_2);
if (getGeomtryHandler().isNorthingFirstEpsgCode(sourceCrs)) {
coordinates.add(northing);
coordinates.add(easting);
} else {
coordinates.add(easting);
coordinates.add(northing);
}
Geometry geom =
getGeomtryHandler().transform(
JTSHelper.createGeometryFromWKT(
JTSHelper.createWKTPointFromCoordinateString(Joiner.on(Constants.SPACE_STRING).join(
coordinates)), sourceCrs), targetCrs);
double x, y;
if (getGeomtryHandler().isNorthingFirstEpsgCode(targetCrs)) {
x = geom.getCoordinate().y;
y = geom.getCoordinate().x;
} else {
x = geom.getCoordinate().x;
y = geom.getCoordinate().y;
}
SweQuantity yq =
SweHelper.createSweQuantity(y, SweConstants.Y_AXIS, ProcedureDescriptionSettings.getInstance()
.getLatLongUom());
SweQuantity xq =
SweHelper.createSweQuantity(x, SweConstants.X_AXIS, ProcedureDescriptionSettings.getInstance()
.getLatLongUom());
if (altitude != null) {
return Lists.<SweCoordinate<?>> newArrayList(new SweCoordinate<Double>(SweCoordinateName.northing.name(), yq),
new SweCoordinate<Double>(SweCoordinateName.easting.name(), xq), altitude);
}
return Lists.<SweCoordinate<?>> newArrayList(new SweCoordinate<Double>(SweCoordinateName.northing.name(), yq),
new SweCoordinate<Double>(SweCoordinateName.easting.name(), xq));
}
/**
* Check the {@link SmlLocation} if modifications are required
*
* @param location
* {@link SmlLocation} to check
* @param targetCrs
* Target EPSG code
* @throws OwsExceptionReport
* If the transformation fails
*/
private void transformLocation(SmlLocation location, int targetCrs) throws OwsExceptionReport {
location.setPoint((Point) getGeomtryHandler().transform(location.getPoint(), targetCrs));
}
/**
* Check if the {@link AbstractSensorML} contains {@link SmlCapabilities}
* with observed area
*
* @param abstractSensorML
* {@link AbstractSensorML} to check
* @param targetCrs
* Target EPSG code
* @throws OwsExceptionReport
* If the transformation fails
*/
private void checkCapabilitiesForObservedAreaAndTransform(AbstractSensorML abstractSensorML, int targetCrs)
throws OwsExceptionReport {
if (abstractSensorML.isSetCapabilities()) {
for (SmlCapabilities capabilities : abstractSensorML.getCapabilities()) {
if (SensorMLConstants.ELEMENT_NAME_OBSERVED_BBOX.equals(capabilities.getName())) {
if (capabilities.isSetAbstractDataRecord() && capabilities.getDataRecord().isSetFields()) {
for (SweField field : capabilities.getDataRecord().getFields()) {
if (SensorMLConstants.ELEMENT_NAME_OBSERVED_BBOX.equals(field.getName().getValue())
&& field.getElement() instanceof SweEnvelope
&& !Integer.toString(targetCrs).equals(
((SweEnvelope) field.getElement()).getReferenceFrame())) {
SweEnvelope envelope = (SweEnvelope) field.getElement();
Envelope transformEnvelope =
getGeomtryHandler().transformEnvelope(envelope.toEnvelope(),
getCrsFromString(envelope.getReferenceFrame()), targetCrs);
SweEnvelope newEnvelope =
new SweEnvelope(new SosEnvelope(transformEnvelope, targetCrs),
ProcedureDescriptionSettings.getInstance().getLatLongUom());
newEnvelope.setReferenceFrame(ServiceConfiguration.getInstance().getSrsNamePrefix()
+ targetCrs);
field.setElement(newEnvelope);
}
}
}
}
}
}
}
/**
* Check if the the CRS parameter is contained in the request and supported
*
* @param request
* Request to check
* @throws OwsExceptionReport
* If an error occurs or the requested RS is not supported
*/
private void checkRequestIfCrsIsSetAndSupported(AbstractServiceRequest<?> request) throws OwsExceptionReport {
int crsFrom = getCrsFrom(request);
if (EpsgConstants.NOT_SET_EPSG != crsFrom) {
String requestedCrs = Integer.toString(crsFrom);
if (!getGeomtryHandler().getSupportedCRS().contains(requestedCrs)) {
throw new InvalidParameterValueException(OWSConstants.AdditionalRequestParams.crs, requestedCrs);
}
}
}
/**
* Get the CRS from the request or if the CRS parameter is not set, return
* the {@link EpsgConstants.NOT_SET_EPSG}.
*
* @param request
* the request to check
* @return the requested CRS or {@link EpsgConstants.NOT_SET_EPSG}
* @throws OwsExceptionReport
* If an error occurs when parsing the request
*/
private int getCrsFrom(AbstractServiceRequest<?> request) throws OwsExceptionReport {
if (request.isSetExtensions()) {
if (request.getExtensions().containsExtension(OWSConstants.AdditionalRequestParams.crs)) {
return getCrs(request.getExtensions().getExtension(OWSConstants.AdditionalRequestParams.crs)
.getValue());
}
} else if (request instanceof SrsNameRequest && ((SrsNameRequest) request).isSetSrsName()) {
return getCrs(((SrsNameRequest) request).getSrsName());
}
return EpsgConstants.NOT_SET_EPSG;
}
/**
* Get the target EPSG code. If set, the request CRS, else the default
* response EPSG code.
*
* @param request
* the request to get CRS from
* @return Requested, if set, or the default response EPSG code
* @throws OwsExceptionReport
*/
private int getRequestedCrs(AbstractServiceRequest<?> request) throws OwsExceptionReport {
int crsFrom = getCrsFrom(request);
if (crsFrom != EpsgConstants.NOT_SET_EPSG) {
return crsFrom;
}
return getGeomtryHandler().getDefaultResponseEPSG();
}
/**
* Get the EPSG code as integer from value
*
* @param value
* EPSG code
* @return integer representation of EPSG code
* @throws OwsExceptionReport
* If an error occurs
*/
private int getCrs(Object value) throws OwsExceptionReport {
if (value instanceof SweCount) {
return ((SweCount) value).getValue();
} else if (value instanceof Integer) {
return (Integer) value;
} else if (value instanceof SweText) {
return getCrsFromString(((SweText) value).getValue());
} else if (value instanceof String) {
return getCrsFromString((String) value);
}
return EpsgConstants.NOT_SET_EPSG;
}
/**
* Get EPSG code as integer from String value
*
* @param crs
* String EPSG code
* @return integer representation of EPSG code
* @throws OwsExceptionReport
* If an error occurs when parsing
*/
private int getCrsFromString(String crs) throws OwsExceptionReport {
if (StringHelper.isNotEmpty(crs) && !"NOT_SET".equalsIgnoreCase(crs)) {
if (crs.startsWith(Constants.URN) || crs.startsWith(Constants.HTTP)) {
crs =
crs.replace(getConfiguration().getSrsNamePrefix(), Constants.EMPTY_STRING).replace(
getConfiguration().getSrsNamePrefixSosV2(), Constants.EMPTY_STRING);
}
crs =
crs.replace(EpsgConstants.EPSG_PREFIX_DOUBLE_COLON, Constants.EMPTY_STRING).replace(
EpsgConstants.EPSG_PREFIX, Constants.EMPTY_STRING);
try {
return Integer.valueOf(crs);
} catch (final NumberFormatException nfe) {
String parameter =
new StringBuilder().append(SosConstants.GetObservationParams.srsName.name())
.append(Constants.SLASH_CHAR).append(OWSConstants.AdditionalRequestParams.crs.name())
.toString();
throw new NoApplicableCodeException()
.causedBy(nfe)
.at(parameter)
.withMessage(
"Error while parsing '%s' parameter! Parameter has to match "
+ "pattern '%s', '%s', '%s','%s', with appended EPSG code number", parameter,
getConfiguration().getSrsNamePrefix(), getConfiguration().getSrsNamePrefixSosV2(),
EpsgConstants.EPSG_PREFIX_DOUBLE_COLON, EpsgConstants.EPSG_PREFIX);
}
}
throw new MissingParameterValueException(OWSConstants.AdditionalRequestParams.crs);
}
/**
* Check if the spatial filters geometries EPSG code are the same as the
* stored EPSG code. If not a coordinate transformation is performed.
*
* @param spatialFilters
* Spatial filters to check
* @throws OwsExceptionReport
* If the transformation fails
*/
private void preProcessSpatialFilters(List<SpatialFilter> spatialFilters) throws OwsExceptionReport {
for (SpatialFilter spatialFilter : spatialFilters) {
preProcessSpatialFilter(spatialFilter);
}
}
/**
* Check if the spatial filter geometry EPSG code is the same as the stored
* EPSG code. If not a coordinate transformation is performed.
*
* @param spatialFilter
* Spatial filter to check
* @throws OwsExceptionReport
* If the transformation fails
*/
private void preProcessSpatialFilter(SpatialFilter spatialFilter) throws OwsExceptionReport {
spatialFilter.setGeometry(getGeomtryHandler().transformToStorageEpsg(spatialFilter.getGeometry()));
}
/**
* Check all geometries in the requested {@link OmObservation}s and
* transform to storage EPSG code if necessary
*
* @param observations
* Requested {@link OmObservation}s
* @throws OwsExceptionReport
* If the transformation fails
*/
private void checkRequestedObservations(List<OmObservation> observations) throws OwsExceptionReport {
if (CollectionHelper.isNotEmpty(observations)) {
int storageCRS = getGeomtryHandler().getStorageEPSG();
for (OmObservation omObservation : observations) {
if (omObservation.getObservationConstellation().getFeatureOfInterest() instanceof SamplingFeature) {
SamplingFeature samplingFeature =
(SamplingFeature) omObservation.getObservationConstellation().getFeatureOfInterest();
checkRequestedGeometryOfSamplingFeature(samplingFeature);
}
if (omObservation.isSetParameter()) {
checkOmParameterForGeometry(omObservation.getParameter(), storageCRS);
}
}
}
}
/**
* Check all geometries in the response {@link OmObservation}s and transform
* to requested or default response EPSG code if necessary
*
* @param observations
* Response {@link OmObservation}s
* @param targetCrs
* Target EPSG code
* @throws OwsExceptionReport
* If the transformation fails
*/
private void checkResponseObservations(List<OmObservation> observations, int targetCRS) throws OwsExceptionReport {
if (CollectionHelper.isNotEmpty(observations)) {
for (OmObservation omObservation : observations) {
if (omObservation.getObservationConstellation().getFeatureOfInterest() instanceof SamplingFeature)
checkResponseGeometryOfSamplingFeature((SamplingFeature) omObservation
.getObservationConstellation().getFeatureOfInterest(), targetCRS);
if (omObservation.isSetParameter()) {
checkOmParameterForGeometry(omObservation.getParameter(), targetCRS);
}
if (omObservation.getValue() instanceof AbstractStreaming) {
((AbstractStreaming) omObservation.getValue()).add(OWSConstants.AdditionalRequestParams.crs,
targetCRS);
}
}
}
}
/**
* Check and transform the {@link SamplingFeature} geometry to storage EPSG
* code if necessary
*
* @param samplingFeature
* the {@link SamplingFeature}
* @throws OwsExceptionReport
* If the transformation fails
*/
private void checkRequestedGeometryOfSamplingFeature(SamplingFeature samplingFeature) throws OwsExceptionReport {
if (samplingFeature.isSetGeometry()) {
samplingFeature.setGeometry(getGeomtryHandler().transformToStorageEpsg(samplingFeature.getGeometry()));
}
}
/**
* Check and transform the {@link SamplingFeature} geometry to requested or
* default response EPSG code if necessary
*
* @param samplingFeature
* the {@link SamplingFeature}
* @param targetCrs
* Target EPSG code
* @throws OwsExceptionReport
* If the transformation fails
*/
private void checkResponseGeometryOfSamplingFeature(SamplingFeature samplingFeature, int targetCRS)
throws OwsExceptionReport {
if (samplingFeature.isSetGeometry()) {
if (samplingFeature.getGeometry().getSRID() != targetCRS) {
samplingFeature.setGeometry(getGeomtryHandler().transform(samplingFeature.getGeometry(), targetCRS));
}
}
}
/**
* Check all geometries in the response {@link AbstractFeature}s and
* transform to requested or default response EPSG code if necessary
*
* @param feature
* the response {@link AbstractFeature}s
* @param targetCrs
* Target EPSG code
* @throws OwsExceptionReport
* If the transformation fails
*/
private void processAbstractFeature(AbstractFeature feature, int targetCRS) throws OwsExceptionReport {
if (feature != null) {
if (feature instanceof FeatureCollection) {
FeatureCollection featureCollection = (FeatureCollection) feature;
for (AbstractFeature abstractFeature : featureCollection.getMembers().values()) {
if (abstractFeature instanceof SamplingFeature) {
checkResponseGeometryOfSamplingFeature((SamplingFeature) abstractFeature, targetCRS);
}
}
} else if (feature instanceof SamplingFeature) {
checkResponseGeometryOfSamplingFeature((SamplingFeature) feature, targetCRS);
}
}
}
/**
* Check if the O&M parameter contains a geometry and transform to target
* EPSG code, e.g. SOS 2.0 Spatial Filtering Profile
*
* @param parameters
* O&M parameter to check
* @param targetCrs
* Target EPSG code
* @throws OwsExceptionReport
* If the transformation fails
*/
@SuppressWarnings("unchecked")
private void checkOmParameterForGeometry(Collection<NamedValue<?>> parameters, int targetCRS)
throws OwsExceptionReport {
for (NamedValue<?> namedValue : parameters) {
if (Sos2Constants.HREF_PARAMETER_SPATIAL_FILTERING_PROFILE.equals(namedValue.getName().getHref())) {
NamedValue<Geometry> spatialFilteringProfileParameter = (NamedValue<Geometry>) namedValue;
spatialFilteringProfileParameter.getValue().setValue(
getGeomtryHandler().transform(spatialFilteringProfileParameter.getValue().getValue(),
targetCRS));
}
}
}
private GeometryHandler getGeomtryHandler() {
return GeometryHandler.getInstance();
}
private ServiceConfiguration getConfiguration() {
return ServiceConfiguration.getInstance();
}
@Override
public RequestResponseModifierFacilitator getFacilitator() {
return new RequestResponseModifierFacilitator();
}
}