Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Validate crs and valid domain during transactions #692

Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
import static org.deegree.commons.xml.CommonNamespaces.XLNNS;
import static org.deegree.commons.xml.XMLAdapter.writeElement;
import static org.deegree.commons.xml.stax.XMLStreamUtils.skipElement;
import static org.deegree.feature.Features.findFeaturesAndGeometries;
import static org.deegree.gml.GMLInputFactory.createGMLStreamReader;
import static org.deegree.gml.GMLVersion.GML_32;
import static org.deegree.protocol.wfs.WFSConstants.VERSION_100;
Expand All @@ -67,9 +68,11 @@
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.xml.namespace.QName;
import javax.xml.stream.XMLStreamException;
Expand Down Expand Up @@ -111,7 +114,10 @@
import org.deegree.filter.IdFilter;
import org.deegree.filter.OperatorFilter;
import org.deegree.filter.expression.ValueReference;
import org.deegree.geometry.Envelope;
import org.deegree.geometry.Geometry;
import org.deegree.geometry.GeometryFactory;
import org.deegree.geometry.SimpleGeometryFactory;
import org.deegree.geometry.validation.CoordinateValidityInspector;
import org.deegree.gml.GMLInputFactory;
import org.deegree.gml.GMLStreamReader;
Expand Down Expand Up @@ -155,6 +161,8 @@ class TransactionHandler {

private static final Logger LOG = LoggerFactory.getLogger( TransactionHandler.class );

private static final SimpleGeometryFactory GEOM_FACTORY = new SimpleGeometryFactory();

private final WebFeatureService master;

private final WfsFeatureStoreManager service;
Expand Down Expand Up @@ -201,12 +209,14 @@ class TransactionHandler {
*
* @param response
* response that is used to write the result
* @param queryCRS
* list of all supported CRS
* @throws OWSException
* if a WFS specific exception occurs, e.g. a feature type is not served
* @throws IOException
* @throws XMLStreamException
*/
void doTransaction( HttpResponseBuffer response )
void doTransaction( HttpResponseBuffer response, List<ICRS> queryCRS )
throws OWSException, XMLStreamException, IOException {

LOG.debug( "doTransaction: " + request );
Expand All @@ -233,7 +243,7 @@ void doTransaction( HttpResponseBuffer response )
break;
}
case INSERT: {
doInsert( (Insert) operation );
doInsert( (Insert) operation, queryCRS );
break;
}
case NATIVE: {
Expand Down Expand Up @@ -365,7 +375,7 @@ private void doDelete( Delete delete, Lock lock )
}
}

private void doInsert( Insert insert )
private void doInsert( Insert insert, List<ICRS> queryCRS )
throws OWSException {

LOG.debug( "doInsert: " + insert );
Expand All @@ -382,24 +392,15 @@ private void doInsert( Insert insert )
throw new OWSException( msg, NO_APPLICABLE_CODE );
}

ICRS defaultCRS = null;
if ( insert.getSrsName() != null ) {
try {
defaultCRS = CRSManager.lookup( insert.getSrsName() );
} catch ( UnknownCRSException e ) {
String msg = "Cannot perform insert. Specified srsName '" + insert.getSrsName()
+ "' is not supported by this WFS.";
throw new OWSException( msg, INVALID_PARAMETER_VALUE, "srsName" );
}
}

ICRS defaultCRS = determineDefaultCrs( insert, queryCRS );
GMLVersion inputFormat = determineFormat( request.getVersion(), insert.getInputFormat() );

// TODO streaming
FeatureStoreTransaction ta = null;
try {
XMLStreamReader xmlStream = insert.getFeatures();
FeatureCollection fc = parseFeaturesOrCollection( xmlStream, inputFormat, defaultCRS );
evaluateSrsNameForFeatureCollection( fc, queryCRS, insert.getHandle() );
FeatureStore fs = service.getStores()[0];
ta = acquireTransaction( fs );
IDGenMode mode = insert.getIdGen();
Expand All @@ -414,6 +415,8 @@ private void doInsert( Insert insert )
for ( String newFid : newFids ) {
inserted.add( newFid, insert.getHandle() );
}
} catch ( OWSException e ) {
throw e;
} catch ( XMLParsingException e ) {
String exceptionCode = INVALID_PARAMETER_VALUE;
if ( VERSION_200.equals( request.getVersion() ) ) {
Expand Down Expand Up @@ -540,7 +543,6 @@ private void doNative( Native nativeOp )

private void doUpdate( Update update, Lock lock )
throws OWSException {

LOG.debug( "doUpdate: " + update );
QName ftName = update.getTypeName();
FeatureType ft = service.lookupFeatureType( ftName );
Expand Down Expand Up @@ -928,4 +930,78 @@ private String determineNamespaceUri( ValueReference valueReference, FeatureType
return ft.getName().getNamespaceURI();
}

private ICRS determineDefaultCrs( Insert insert, List<ICRS> queryCRS )
throws OWSException {
String srsName = insert.getSrsName();
if ( srsName != null ) {
try {
ICRS defaultCrs = CRSManager.lookup( insert.getSrsName() );
if ( !isCrsSupported( defaultCrs, queryCRS ) ) {
String msg = "The value of the srsName parameter is not one of the SRS values the server claims to support in its capabilities document.";
throw new OWSException( msg, INVALID_PARAMETER_VALUE, "srsName" );
}
return defaultCrs;
} catch ( UnknownCRSException e ) {
String msg = "Cannot perform insert. Specified srsName '" + srsName + "' is not supported by this WFS.";
throw new OWSException( msg, INVALID_PARAMETER_VALUE, "srsName" );
}
}
return null;
}

private void evaluateSrsNameForFeatureCollection( FeatureCollection fc, List<ICRS> queryCRS, String handle )
throws OWSException {
for ( Feature feature : fc )
evaluateSrsNameForFeature( feature, queryCRS, handle );
}

private void evaluateSrsNameForFeature( Feature feature, List<ICRS> queryCRS, String handle )
throws OWSException {
Set<Geometry> geometries = new LinkedHashSet<Geometry>();
findFeaturesAndGeometries( feature, geometries, new LinkedHashSet<Feature>(), new LinkedHashSet<String>(),
new LinkedHashSet<String>() );
for ( Geometry geometry : geometries ) {
ICRS crs = geometry.getCoordinateSystem();
evaluateSrsName( crs, queryCRS, handle );
evaluateValidDomain( crs, geometry, handle );
}
}

private void evaluateSrsName( ICRS crs, List<ICRS> supportedCrs, String handle )
throws OWSException {
if ( !isCrsSupported( crs, supportedCrs ) ) {
String message = "The value of the at least one geometrie srs is not one of the SRS values "
+ "the server claims to support in its capabilities document.";
if ( handle == null || "".equals( handle ) )
handle = "Transaction";
throw new OWSException( message, OWSException.OPERATION_PROCESSING_FAILED, handle );
}
}

private void evaluateValidDomain( ICRS crs, Geometry geometry, String handle )
throws OWSException {
double[] validDomain = crs.getValidDomain();
if ( validDomain == null ) {
LOG.warn( "Valid domain of crs {} is not available. Check if geometry is inside the valid "
+ "domain not possible. The check is skipped and insert processed.", crs.getAlias() );
return;
}
Envelope validDomainBbox = GEOM_FACTORY.createEnvelope( validDomain[0], validDomain[1], validDomain[2],
validDomain[3], crs );
if ( !geometry.isWithin( validDomainBbox ) ) {
String message = "At least one geometry is not in the valid domain of the srs.";
if ( handle == null || "".equals( handle ) )
handle = "Transaction";
throw new OWSException( message, OWSException.OPERATION_PROCESSING_FAILED, handle );
}
}

private boolean isCrsSupported( ICRS crs, List<ICRS> supportedCrs )
throws OWSException {
if ( crs != null && supportedCrs != null )
if ( !supportedCrs.contains( crs ) )
return false;
return true;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -817,7 +817,7 @@ public void doKVP( Map<String, String> kvpParamsUC, HttpServletRequest request,
}
checkTransactionsEnabled( requestName );
Transaction transaction = TransactionKVPAdapter.parse( kvpParamsUC );
new TransactionHandler( this, service, transaction, idGenMode, allowFeatureReferencesToDatastore ).doTransaction( response );
new TransactionHandler( this, service, transaction, idGenMode, allowFeatureReferencesToDatastore ).doTransaction( response, queryCRS );
break;
default:
throw new RuntimeException( "Internal error: Unhandled request '" + requestName + "'." );
Expand Down Expand Up @@ -980,7 +980,7 @@ public void doXML( XMLStreamReader xmlStream, HttpServletRequest request, HttpRe
checkTransactionsEnabled( requestName );
TransactionXmlReader transactionReader = new TransactionXmlReaderFactory().createReader( xmlStream );
Transaction transaction = transactionReader.read( xmlStream );
new TransactionHandler( this, service, transaction, idGenMode, allowFeatureReferencesToDatastore ).doTransaction( response );
new TransactionHandler( this, service, transaction, idGenMode, allowFeatureReferencesToDatastore ).doTransaction( response, queryCRS );
break;
default:
throw new RuntimeException( "Internal error: Unhandled request '" + requestName + "'." );
Expand Down Expand Up @@ -1147,7 +1147,7 @@ public void doSOAP( SOAPEnvelope soapDoc, HttpServletRequest request, HttpRespon
checkTransactionsEnabled( requestName );
TransactionXmlReader transactionReader = new TransactionXmlReaderFactory().createReader( requestVersion );
Transaction transaction = transactionReader.read( bodyXmlStream );
new TransactionHandler( this, service, transaction, idGenMode, allowFeatureReferencesToDatastore ).doTransaction( response );
new TransactionHandler( this, service, transaction, idGenMode, allowFeatureReferencesToDatastore ).doTransaction( response, queryCRS );
break;
default:
throw new RuntimeException( "Internal error: Unhandled request '" + requestName + "'." );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@
<EnableTransactions>true</EnableTransactions>
<DisableResponseBuffering>true</DisableResponseBuffering>
<QueryCRS>EPSG:4326</QueryCRS>
<QueryCRS>EPSG:32615</QueryCRS>
</deegreeWFS>