From 9722dca25143c29e8fe2be1b29c574a8a86f344d Mon Sep 17 00:00:00 2001 From: Lyn Elisa Goltz Date: Thu, 19 Jan 2017 08:26:19 +0100 Subject: [PATCH 1/4] #4242 - allow references to already inserted fetaures in insert transaction --- .../java/org/deegree/gml/GMLStreamReader.java | 10 +++++ .../gml/commons/AbstractGMLObjectReader.java | 13 ++++++- .../gml/reference/FeatureReference.java | 39 +++++++++++++++++++ .../org/deegree/commons/tom/Reference.java | 9 +++++ .../sql/insert/InsertRowManager.java | 5 ++- .../services/wfs/TransactionHandler.java | 8 +++- 6 files changed, 80 insertions(+), 4 deletions(-) diff --git a/deegree-core/deegree-core-base/src/main/java/org/deegree/gml/GMLStreamReader.java b/deegree-core/deegree-core-base/src/main/java/org/deegree/gml/GMLStreamReader.java index 2d8f7c1a6c..5b6d7b1fd6 100644 --- a/deegree-core/deegree-core-base/src/main/java/org/deegree/gml/GMLStreamReader.java +++ b/deegree-core/deegree-core-base/src/main/java/org/deegree/gml/GMLStreamReader.java @@ -147,6 +147,8 @@ public class GMLStreamReader { private boolean laxMode; + private GMLReferenceResolver internalResolver; + /** * Creates a new {@link GMLStreamReader} instance. * @@ -251,6 +253,14 @@ public void setResolver( GMLReferenceResolver resolver ) { this.resolver = resolver; } + public void setInternalResolver ( GMLReferenceResolver internalResolver ) { + this.internalResolver = internalResolver; + } + + public GMLReferenceResolver getInternalResolver () { + return internalResolver; + } + /** * Enables or disables lax parsing (disable syntactical checks). * diff --git a/deegree-core/deegree-core-base/src/main/java/org/deegree/gml/commons/AbstractGMLObjectReader.java b/deegree-core/deegree-core-base/src/main/java/org/deegree/gml/commons/AbstractGMLObjectReader.java index 53e8395900..153e42a27f 100644 --- a/deegree-core/deegree-core-base/src/main/java/org/deegree/gml/commons/AbstractGMLObjectReader.java +++ b/deegree-core/deegree-core-base/src/main/java/org/deegree/gml/commons/AbstractGMLObjectReader.java @@ -155,6 +155,8 @@ public abstract class AbstractGMLObjectReader extends XMLAdapter { protected static final QName XSI_NIL = new QName( XSINS, "nil", "xsi" ); + private final GMLReferenceResolver internalResolver; + // TODO should be final, but is currently modified by GMLFeatureReader protected AppSchema schema; @@ -167,6 +169,7 @@ public abstract class AbstractGMLObjectReader extends XMLAdapter { protected AbstractGMLObjectReader( GMLStreamReader gmlStreamReader ) { this.gmlStreamReader = gmlStreamReader; this.specialResolver = gmlStreamReader.getResolver(); + this.internalResolver = gmlStreamReader.getInternalResolver(); this.idContext = gmlStreamReader.getIdContext(); // TODO this.schema = gmlStreamReader.getAppSchema(); @@ -322,9 +325,17 @@ private Property parseFeatureProperty( XMLStreamReaderWrapper xmlStream, Feature if ( href != null ) { FeatureReference refFeature = null; if ( specialResolver != null ) { - refFeature = new FeatureReference( specialResolver, href, xmlStream.getSystemId() ); + if( internalResolver == null ) { + refFeature = new FeatureReference( specialResolver, href, xmlStream.getSystemId() ); + } else { + refFeature = new FeatureReference( specialResolver, internalResolver, href, xmlStream.getSystemId() ); + } } else { + if( internalResolver == null ) { refFeature = new FeatureReference( idContext, href, xmlStream.getSystemId() ); + } else { + refFeature = new FeatureReference( idContext, internalResolver, href, xmlStream.getSystemId() ); + } } idContext.addReference( refFeature ); List values = new ArrayList(); diff --git a/deegree-core/deegree-core-base/src/main/java/org/deegree/gml/reference/FeatureReference.java b/deegree-core/deegree-core-base/src/main/java/org/deegree/gml/reference/FeatureReference.java index 1ddd464ea9..25033e95e4 100644 --- a/deegree-core/deegree-core-base/src/main/java/org/deegree/gml/reference/FeatureReference.java +++ b/deegree-core/deegree-core-base/src/main/java/org/deegree/gml/reference/FeatureReference.java @@ -40,7 +40,9 @@ import javax.xml.namespace.QName; +import org.deegree.commons.tom.ReferenceResolvingException; import org.deegree.commons.tom.TypedObjectNode; +import org.deegree.commons.tom.gml.GMLObject; import org.deegree.commons.tom.gml.GMLReference; import org.deegree.commons.tom.gml.GMLReferenceResolver; import org.deegree.commons.tom.gml.property.Property; @@ -48,6 +50,9 @@ import org.deegree.feature.property.ExtraProps; import org.deegree.feature.types.FeatureType; import org.deegree.geometry.Envelope; +import org.deegree.gml.schema.GMLSchemaInfoSet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * A {@link GMLReference} that targets a {@link Feature}. @@ -59,6 +64,10 @@ */ public class FeatureReference extends GMLReference implements Feature { + private static final Logger LOG = LoggerFactory.getLogger( FeatureReference.class ); + + private final GMLReferenceResolver internalResolver; + /** * Creates a new {@link FeatureReference} instance. * @@ -70,7 +79,24 @@ public class FeatureReference extends GMLReference implements Feature { * base URL for resolving the uri, may be null (no resolving of relative URLs) */ public FeatureReference( GMLReferenceResolver resolver, String uri, String baseURL ) { + this( resolver, null, uri, baseURL ); + } + + /** + * Creates a new {@link FeatureReference} instance. + * + * @param resolver + * used for resolving the reference, must not be null + * @param internalResolver + * used for resolving references, may be null + * @param uri + * the feature's uri, must not be null + * @param baseURL + * base URL for resolving the uri, may be null (no resolving of relative URLs) + */ + public FeatureReference( GMLReferenceResolver resolver, GMLReferenceResolver internalResolver, String uri, String baseURL ) { super( resolver, uri, baseURL ); + this.internalResolver = internalResolver; } @Override @@ -139,4 +165,17 @@ public void setExtraProperties( ExtraProps extraProps ) { getReferencedObject().setExtraProperties( extraProps ); } + @Override + public synchronized Feature getReferencedObject() + throws ReferenceResolvingException { + try { + return super.getReferencedObject(); + } catch(ReferenceResolvingException e) { + GMLObject object = this.internalResolver.getObject( getURI(), getBaseURL() ); + if ( object != null ) + LOG.info( "Feature with uri {} could be resolved by the internal resolver.", getURI() ); + return null; + } + } + } diff --git a/deegree-core/deegree-core-commons/src/main/java/org/deegree/commons/tom/Reference.java b/deegree-core/deegree-core-commons/src/main/java/org/deegree/commons/tom/Reference.java index 1f1c8a8888..d6f904ba4c 100644 --- a/deegree-core/deegree-core-commons/src/main/java/org/deegree/commons/tom/Reference.java +++ b/deegree-core/deegree-core-commons/src/main/java/org/deegree/commons/tom/Reference.java @@ -111,6 +111,15 @@ public boolean isLocal() { return uri.startsWith( "#" ); } + /** + * Returns the base URL for resolving the uri. + * + * @return base URL for resolving the uri, may be null (no resolving of relative URLs) + */ + public String getBaseURL() { + return baseURL; + } + /** * Sets the referenced object. * diff --git a/deegree-datastores/deegree-featurestores/deegree-featurestore-sql/src/main/java/org/deegree/feature/persistence/sql/insert/InsertRowManager.java b/deegree-datastores/deegree-featurestores/deegree-featurestore-sql/src/main/java/org/deegree/feature/persistence/sql/insert/InsertRowManager.java index 5f58aa09d5..19b7629cfa 100644 --- a/deegree-datastores/deegree-featurestores/deegree-featurestore-sql/src/main/java/org/deegree/feature/persistence/sql/insert/InsertRowManager.java +++ b/deegree-datastores/deegree-featurestores/deegree-featurestore-sql/src/main/java/org/deegree/feature/persistence/sql/insert/InsertRowManager.java @@ -347,11 +347,12 @@ public void buildInsertRows( final TypedObjectNode particle, final Mapping mappi String href = null; Feature feature = (Feature) getPropValue( value ); if ( feature instanceof FeatureReference ) { - if ( ( (FeatureReference) feature ).isLocal() || ( (FeatureReference) feature ).isResolved() ) { + FeatureReference featureReference = (FeatureReference) feature; + if ( ( featureReference.isLocal() || featureReference.isResolved() ) && featureReference.getReferencedObject() != null ) { subFeatureRow = lookupFeatureRow( feature.getId() ); } // always use the uri if href is mapped explicitly - href = ( (FeatureReference) feature ).getURI(); + href = featureReference.getURI(); MappingExpression me = ( (FeatureMapping) mapping ).getHrefMapping(); if ( !( me instanceof DBField ) ) { LOG.debug( "Skipping feature mapping (href). Not mapped to database column." ); diff --git a/deegree-services/deegree-services-wfs/src/main/java/org/deegree/services/wfs/TransactionHandler.java b/deegree-services/deegree-services-wfs/src/main/java/org/deegree/services/wfs/TransactionHandler.java index 108ab64285..0a184fbbfd 100644 --- a/deegree-services/deegree-services-wfs/src/main/java/org/deegree/services/wfs/TransactionHandler.java +++ b/deegree-services/deegree-services-wfs/src/main/java/org/deegree/services/wfs/TransactionHandler.java @@ -77,9 +77,11 @@ import javax.xml.stream.XMLStreamWriter; import org.deegree.commons.ows.exception.OWSException; +import org.deegree.commons.tom.CombinedReferenceResolver; import org.deegree.commons.tom.ReferenceResolvingException; import org.deegree.commons.tom.TypedObjectNode; import org.deegree.commons.tom.genericxml.GenericXMLElement; +import org.deegree.commons.tom.gml.GMLReferenceResolver; import org.deegree.commons.tom.gml.property.Property; import org.deegree.commons.tom.gml.property.PropertyType; import org.deegree.commons.tom.ows.Version; @@ -98,6 +100,8 @@ import org.deegree.feature.GenericFeatureCollection; import org.deegree.feature.persistence.FeatureStore; import org.deegree.feature.persistence.FeatureStoreException; +import org.deegree.feature.persistence.FeatureStoreGMLIdResolver; +import org.deegree.feature.persistence.FeatureStoreGmlIdentifierResolver; import org.deegree.feature.persistence.FeatureStoreTransaction; import org.deegree.feature.persistence.lock.Lock; import org.deegree.feature.persistence.lock.LockManager; @@ -117,6 +121,7 @@ import org.deegree.gml.GMLVersion; import org.deegree.gml.feature.GMLFeatureReader; import org.deegree.gml.reference.FeatureReference; +import org.deegree.gml.reference.GmlDocumentIdContext; import org.deegree.protocol.wfs.transaction.ReleaseAction; import org.deegree.protocol.wfs.transaction.Transaction; import org.deegree.protocol.wfs.transaction.TransactionAction; @@ -436,6 +441,7 @@ private FeatureCollection parseFeaturesOrCollection( XMLStreamReader xmlStream, // TODO determine correct schema AppSchema schema = service.getStores()[0].getSchema(); GMLStreamReader gmlStream = GMLInputFactory.createGMLStreamReader( inputFormat, xmlStream ); + gmlStream.setInternalResolver( new FeatureStoreGMLIdResolver( service.getStores()[0] ) ); gmlStream.setApplicationSchema( schema ); gmlStream.setDefaultCRS( defaultCRS ); @@ -466,7 +472,7 @@ private FeatureCollection parseFeaturesOrCollection( XMLStreamReader xmlStream, } // resolve local xlink references - gmlStream.getIdContext().resolveLocalRefs(); + // gmlStream.getIdContext().resolveLocalRefs(); return fc; } From 38d702e4bb20a8ec720777f1c750ff1b7c38e277 Mon Sep 17 00:00:00 2001 From: Lyn Elisa Goltz Date: Tue, 21 Mar 2017 08:38:38 +0100 Subject: [PATCH 2/4] #4472 - added configuration option allowFeatureReferencesToDatastore=true|false --- .../gml/reference/FeatureReference.java | 6 +++-- .../services/wfs/TransactionHandler.java | 26 ++++++++++--------- .../services/wfs/WebFeatureService.java | 9 ++++--- .../services/wfs/3.4.0/wfs_configuration.xsd | 1 + 4 files changed, 25 insertions(+), 17 deletions(-) diff --git a/deegree-core/deegree-core-base/src/main/java/org/deegree/gml/reference/FeatureReference.java b/deegree-core/deegree-core-base/src/main/java/org/deegree/gml/reference/FeatureReference.java index 25033e95e4..8a1cddbb78 100644 --- a/deegree-core/deegree-core-base/src/main/java/org/deegree/gml/reference/FeatureReference.java +++ b/deegree-core/deegree-core-base/src/main/java/org/deegree/gml/reference/FeatureReference.java @@ -50,7 +50,6 @@ import org.deegree.feature.property.ExtraProps; import org.deegree.feature.types.FeatureType; import org.deegree.geometry.Envelope; -import org.deegree.gml.schema.GMLSchemaInfoSet; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -170,7 +169,10 @@ public synchronized Feature getReferencedObject() throws ReferenceResolvingException { try { return super.getReferencedObject(); - } catch(ReferenceResolvingException e) { + } catch ( ReferenceResolvingException e ) { + if ( internalResolver == null ) { + throw e; + } GMLObject object = this.internalResolver.getObject( getURI(), getBaseURL() ); if ( object != null ) LOG.info( "Feature with uri {} could be resolved by the internal resolver.", getURI() ); diff --git a/deegree-services/deegree-services-wfs/src/main/java/org/deegree/services/wfs/TransactionHandler.java b/deegree-services/deegree-services-wfs/src/main/java/org/deegree/services/wfs/TransactionHandler.java index 0a184fbbfd..957468378f 100644 --- a/deegree-services/deegree-services-wfs/src/main/java/org/deegree/services/wfs/TransactionHandler.java +++ b/deegree-services/deegree-services-wfs/src/main/java/org/deegree/services/wfs/TransactionHandler.java @@ -77,11 +77,9 @@ import javax.xml.stream.XMLStreamWriter; import org.deegree.commons.ows.exception.OWSException; -import org.deegree.commons.tom.CombinedReferenceResolver; import org.deegree.commons.tom.ReferenceResolvingException; import org.deegree.commons.tom.TypedObjectNode; import org.deegree.commons.tom.genericxml.GenericXMLElement; -import org.deegree.commons.tom.gml.GMLReferenceResolver; import org.deegree.commons.tom.gml.property.Property; import org.deegree.commons.tom.gml.property.PropertyType; import org.deegree.commons.tom.ows.Version; @@ -101,7 +99,6 @@ import org.deegree.feature.persistence.FeatureStore; import org.deegree.feature.persistence.FeatureStoreException; import org.deegree.feature.persistence.FeatureStoreGMLIdResolver; -import org.deegree.feature.persistence.FeatureStoreGmlIdentifierResolver; import org.deegree.feature.persistence.FeatureStoreTransaction; import org.deegree.feature.persistence.lock.Lock; import org.deegree.feature.persistence.lock.LockManager; @@ -121,7 +118,6 @@ import org.deegree.gml.GMLVersion; import org.deegree.gml.feature.GMLFeatureReader; import org.deegree.gml.reference.FeatureReference; -import org.deegree.gml.reference.GmlDocumentIdContext; import org.deegree.protocol.wfs.transaction.ReleaseAction; import org.deegree.protocol.wfs.transaction.Transaction; import org.deegree.protocol.wfs.transaction.TransactionAction; @@ -176,24 +172,27 @@ class TransactionHandler { private final IDGenMode idGenMode; + private final boolean allowFeatureReferencesToDatastore; + /** * Creates a new {@link TransactionHandler} instance that uses the given service to lookup requested * {@link FeatureType}s. - * - * @param master - * + * @param master + * * @param service * WFS instance used to lookup the feature types * @param request - * request to be handled + * request to be handled * @param idGenMode + * @param allowFeatureReferencesToDatastore */ TransactionHandler( WebFeatureService master, WfsFeatureStoreManager service, Transaction request, - IDGenMode idGenMode ) { + IDGenMode idGenMode, boolean allowFeatureReferencesToDatastore ) { this.master = master; this.service = service; this.request = request; this.idGenMode = idGenMode; + this.allowFeatureReferencesToDatastore = allowFeatureReferencesToDatastore; } /** @@ -439,9 +438,11 @@ private FeatureCollection parseFeaturesOrCollection( XMLStreamReader xmlStream, FeatureCollection fc = null; // TODO determine correct schema - AppSchema schema = service.getStores()[0].getSchema(); + FeatureStore featureStore = service.getStores()[0]; + AppSchema schema = featureStore.getSchema(); GMLStreamReader gmlStream = GMLInputFactory.createGMLStreamReader( inputFormat, xmlStream ); - gmlStream.setInternalResolver( new FeatureStoreGMLIdResolver( service.getStores()[0] ) ); + if ( allowFeatureReferencesToDatastore ) + gmlStream.setInternalResolver( new FeatureStoreGMLIdResolver( featureStore ) ); gmlStream.setApplicationSchema( schema ); gmlStream.setDefaultCRS( defaultCRS ); @@ -472,7 +473,8 @@ private FeatureCollection parseFeaturesOrCollection( XMLStreamReader xmlStream, } // resolve local xlink references - // gmlStream.getIdContext().resolveLocalRefs(); + if ( !allowFeatureReferencesToDatastore ) + gmlStream.getIdContext().resolveLocalRefs(); return fc; } diff --git a/deegree-services/deegree-services-wfs/src/main/java/org/deegree/services/wfs/WebFeatureService.java b/deegree-services/deegree-services-wfs/src/main/java/org/deegree/services/wfs/WebFeatureService.java index b5612eec38..611e40b021 100644 --- a/deegree-services/deegree-services-wfs/src/main/java/org/deegree/services/wfs/WebFeatureService.java +++ b/deegree-services/deegree-services-wfs/src/main/java/org/deegree/services/wfs/WebFeatureService.java @@ -256,6 +256,8 @@ public class WebFeatureService extends AbstractOWS { private boolean enableResponsePaging; + private boolean allowFeatureReferencesToDatastore = false; + private OWSMetadataProvider mdProvider; public WebFeatureService( ResourceMetadata metadata, Workspace workspace, Object jaxbConfig ) { @@ -275,6 +277,7 @@ public void init( DeegreeServicesMetadataType serviceMetadata, DeegreeServiceCon if ( enableTransactions != null ) { this.enableTransactions = enableTransactions.isValue(); this.idGenMode = parseIdGenMode( enableTransactions.getIdGen() ); + this.allowFeatureReferencesToDatastore = enableTransactions.isAllowFeatureReferencesToDatastore(); } if ( jaxbConfig.isEnableResponseBuffering() != null ) { disableBuffering = !jaxbConfig.isEnableResponseBuffering(); @@ -793,7 +796,7 @@ public void doKVP( Map kvpParamsUC, HttpServletRequest request, } checkTransactionsEnabled( requestName ); Transaction transaction = TransactionKVPAdapter.parse( kvpParamsUC ); - new TransactionHandler( this, service, transaction, idGenMode ).doTransaction( response ); + new TransactionHandler( this, service, transaction, idGenMode, allowFeatureReferencesToDatastore ).doTransaction( response ); break; default: throw new RuntimeException( "Internal error: Unhandled request '" + requestName + "'." ); @@ -956,7 +959,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 ).doTransaction( response ); + new TransactionHandler( this, service, transaction, idGenMode, allowFeatureReferencesToDatastore ).doTransaction( response ); break; default: throw new RuntimeException( "Internal error: Unhandled request '" + requestName + "'." ); @@ -1123,7 +1126,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 ).doTransaction( response ); + new TransactionHandler( this, service, transaction, idGenMode, allowFeatureReferencesToDatastore ).doTransaction( response ); break; default: throw new RuntimeException( "Internal error: Unhandled request '" + requestName + "'." ); diff --git a/deegree-services/deegree-services-wfs/src/main/resources/META-INF/schemas/services/wfs/3.4.0/wfs_configuration.xsd b/deegree-services/deegree-services-wfs/src/main/resources/META-INF/schemas/services/wfs/3.4.0/wfs_configuration.xsd index 729606ff45..8a423dc8e7 100644 --- a/deegree-services/deegree-services-wfs/src/main/resources/META-INF/schemas/services/wfs/3.4.0/wfs_configuration.xsd +++ b/deegree-services/deegree-services-wfs/src/main/resources/META-INF/schemas/services/wfs/3.4.0/wfs_configuration.xsd @@ -43,6 +43,7 @@ + From d0253b857cdc5a8cb3dd690025c043bd85b97035 Mon Sep 17 00:00:00 2001 From: Lyn Elisa Goltz Date: Tue, 21 Mar 2017 09:08:58 +0100 Subject: [PATCH 3/4] #4473 - documented new config option allowFeatureReferencesToDatastore --- .../src/main/sphinx/webservices.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deegree-services/deegree-webservices-handbook/src/main/sphinx/webservices.rst b/deegree-services/deegree-webservices-handbook/src/main/sphinx/webservices.rst index a1c98e24a4..a3db622ba2 100644 --- a/deegree-services/deegree-webservices-handbook/src/main/sphinx/webservices.rst +++ b/deegree-services/deegree-webservices-handbook/src/main/sphinx/webservices.rst @@ -112,7 +112,7 @@ General options Transactions ^^^^^^^^^^^^ -By default, WFS-T requests will be rejected. Setting the ``EnableTransactions`` option to ``true`` will enable transaction support. This option has the optional attribute ``idGenMode`` which controls how ids of inserted features (the values in the gml:id attribute) are treated. There are three id generation modes available: +By default, WFS-T requests will be rejected. Setting the ``EnableTransactions`` option to ``true`` will enable transaction support. This option has two optional attributes: ``allowFeatureReferencesToDatastore`` and ``idGenMode``. If ``allowFeatureReferencesToDatastore`` is true it is allowed to insert features with references to already inserted features, default is false. ``idGenMode`` controls how ids of inserted features (the values in the gml:id attribute) are treated. There are three id generation modes available: * **UseExisting**: The original gml:id values from the input are stored. This may lead to errors if the provided ids are already in use. * **GenerateNew** (default): New and unique ids are generated. References in the input GML (xlink:href) that point to a feature with an reassigned id are fixed as well, so reference consistency is maintained. From b8548236aaf06a53209af76056962c06e1ca45e0 Mon Sep 17 00:00:00 2001 From: Lyn Elisa Goltz Date: Tue, 21 Mar 2017 13:11:02 +0100 Subject: [PATCH 4/4] #4474 - enabled/enhanced check of references --- .../java/org/deegree/feature/Features.java | 14 +++++--- .../gml/reference/FeatureReference.java | 32 +++++++++++++++---- .../org/deegree/commons/tom/Reference.java | 12 ++++++- .../sql/insert/InsertRowManager.java | 3 +- .../services/wfs/TransactionHandler.java | 3 +- 5 files changed, 49 insertions(+), 15 deletions(-) diff --git a/deegree-core/deegree-core-base/src/main/java/org/deegree/feature/Features.java b/deegree-core/deegree-core-base/src/main/java/org/deegree/feature/Features.java index 6cbdf93ecb..70cee75070 100644 --- a/deegree-core/deegree-core-base/src/main/java/org/deegree/feature/Features.java +++ b/deegree-core/deegree-core-base/src/main/java/org/deegree/feature/Features.java @@ -193,7 +193,7 @@ private static Pair getPrimitives( Object value1, Object value2 /** * Determines all {@link Feature} and {@link Geometry} objects contained in the given {@link TypedObjectNode} and - * their ids. + * their ids. Does not include internal referenced {@link Feature}s. * * @param node * typed object node to be scanned, can be null @@ -217,11 +217,15 @@ public static void findFeaturesAndGeometries( TypedObjectNode node, Set ) { Reference ref = (Reference) node; - if ( ref.isResolved() ) { - node = ( (Reference) node ).getReferencedObject(); - } else if ( node instanceof Reference ) { + if ( ref.isResolved() && !ref.isInternalResolved() ) { + node = ref.getReferencedObject(); + } else { try { - node = ( (Reference) node ).getReferencedObject(); + TypedObjectNode referencedObject = ref.getReferencedObject(); + if ( !ref.isInternalResolved() ) + node = referencedObject; + else + return; } catch ( ReferenceResolvingException e ) { LOG.warn( "Unable to resolve external reference '" + ref.getURI() + ". Ignoring." ); return; diff --git a/deegree-core/deegree-core-base/src/main/java/org/deegree/gml/reference/FeatureReference.java b/deegree-core/deegree-core-base/src/main/java/org/deegree/gml/reference/FeatureReference.java index 8a1cddbb78..272ec9b51f 100644 --- a/deegree-core/deegree-core-base/src/main/java/org/deegree/gml/reference/FeatureReference.java +++ b/deegree-core/deegree-core-base/src/main/java/org/deegree/gml/reference/FeatureReference.java @@ -66,6 +66,8 @@ public class FeatureReference extends GMLReference implements Feature { private static final Logger LOG = LoggerFactory.getLogger( FeatureReference.class ); private final GMLReferenceResolver internalResolver; + + private boolean internalResolved = false; /** * Creates a new {@link FeatureReference} instance. @@ -170,14 +172,32 @@ public synchronized Feature getReferencedObject() try { return super.getReferencedObject(); } catch ( ReferenceResolvingException e ) { - if ( internalResolver == null ) { + if ( internalResolver == null ) throw e; + return resolveInternalFeature( e ); + } + } + + @Override + public boolean isInternalResolved() { + return internalResolved; + } + + private Feature resolveInternalFeature( ReferenceResolvingException e ) { + String uri = getURI(); + GMLObject object = this.internalResolver.getObject( uri, getBaseURL() ); + if ( object != null ) { + if ( object instanceof Feature ) { + LOG.info( "Feature with uri {} could be resolved by the internal resolver.", uri ); + resolve( (Feature) object ); + this.internalResolved = true; + return (Feature) object; } - GMLObject object = this.internalResolver.getObject( getURI(), getBaseURL() ); - if ( object != null ) - LOG.info( "Feature with uri {} could be resolved by the internal resolver.", getURI() ); - return null; + String msg = "Object with uri '" + uri + + "' could be resolved from internal resolver but is no Feature instance."; + throw exception = new ReferenceResolvingException( msg ); } + throw e; } -} +} \ No newline at end of file diff --git a/deegree-core/deegree-core-commons/src/main/java/org/deegree/commons/tom/Reference.java b/deegree-core/deegree-core-commons/src/main/java/org/deegree/commons/tom/Reference.java index d6f904ba4c..0a5691fd56 100644 --- a/deegree-core/deegree-core-commons/src/main/java/org/deegree/commons/tom/Reference.java +++ b/deegree-core/deegree-core-commons/src/main/java/org/deegree/commons/tom/Reference.java @@ -57,7 +57,7 @@ public class Reference implements Object { private T object; - private ReferenceResolvingException exception; + protected ReferenceResolvingException exception; /** * Creates a new {@link Reference} instance. @@ -106,6 +106,16 @@ public boolean isResolved() { return object != null; } + /** + * Returns whether the reference has been resolved and is an internal reference. + * + * @return true if the reference is resolved is an internal reference, false if the + * reference has not been resolved or is not internal + */ + public boolean isInternalResolved() { + return false; + } + // TODO can we get rid of this method? public boolean isLocal() { return uri.startsWith( "#" ); diff --git a/deegree-datastores/deegree-featurestores/deegree-featurestore-sql/src/main/java/org/deegree/feature/persistence/sql/insert/InsertRowManager.java b/deegree-datastores/deegree-featurestores/deegree-featurestore-sql/src/main/java/org/deegree/feature/persistence/sql/insert/InsertRowManager.java index 19b7629cfa..0638e6a733 100644 --- a/deegree-datastores/deegree-featurestores/deegree-featurestore-sql/src/main/java/org/deegree/feature/persistence/sql/insert/InsertRowManager.java +++ b/deegree-datastores/deegree-featurestores/deegree-featurestore-sql/src/main/java/org/deegree/feature/persistence/sql/insert/InsertRowManager.java @@ -348,7 +348,8 @@ public void buildInsertRows( final TypedObjectNode particle, final Mapping mappi Feature feature = (Feature) getPropValue( value ); if ( feature instanceof FeatureReference ) { FeatureReference featureReference = (FeatureReference) feature; - if ( ( featureReference.isLocal() || featureReference.isResolved() ) && featureReference.getReferencedObject() != null ) { + if ( ( featureReference.isLocal() || featureReference.isResolved() ) + && !featureReference.isInternalResolved() ) { subFeatureRow = lookupFeatureRow( feature.getId() ); } // always use the uri if href is mapped explicitly diff --git a/deegree-services/deegree-services-wfs/src/main/java/org/deegree/services/wfs/TransactionHandler.java b/deegree-services/deegree-services-wfs/src/main/java/org/deegree/services/wfs/TransactionHandler.java index 957468378f..68c42f937d 100644 --- a/deegree-services/deegree-services-wfs/src/main/java/org/deegree/services/wfs/TransactionHandler.java +++ b/deegree-services/deegree-services-wfs/src/main/java/org/deegree/services/wfs/TransactionHandler.java @@ -473,8 +473,7 @@ private FeatureCollection parseFeaturesOrCollection( XMLStreamReader xmlStream, } // resolve local xlink references - if ( !allowFeatureReferencesToDatastore ) - gmlStream.getIdContext().resolveLocalRefs(); + gmlStream.getIdContext().resolveLocalRefs(); return fc; }