diff --git a/deegree-datastores/deegree-featurestores/deegree-featurestore-sql/src/main/java/org/deegree/feature/persistence/sql/mapper/AppSchemaMapper.java b/deegree-datastores/deegree-featurestores/deegree-featurestore-sql/src/main/java/org/deegree/feature/persistence/sql/mapper/AppSchemaMapper.java
index 3f96075b18..fba71d24a5 100644
--- a/deegree-datastores/deegree-featurestores/deegree-featurestore-sql/src/main/java/org/deegree/feature/persistence/sql/mapper/AppSchemaMapper.java
+++ b/deegree-datastores/deegree-featurestores/deegree-featurestore-sql/src/main/java/org/deegree/feature/persistence/sql/mapper/AppSchemaMapper.java
@@ -132,9 +132,9 @@ public class AppSchemaMapper {
private final int maxComplexityIndex;
- private final int allowedCycleDepth;
-
+ private final ReferenceData referenceData;
+ private final int allowedCycleDepth;
/**
* Creates a new {@link AppSchemaMapper} instance for the given schema.
@@ -184,11 +184,40 @@ public AppSchemaMapper( AppSchema appSchema, boolean createBlobMapping, boolean
public AppSchemaMapper( AppSchema appSchema, boolean createBlobMapping, boolean createRelationalMapping,
GeometryStorageParams geometryParams, int maxLength, boolean usePrefixedSQLIdentifiers,
boolean useIntegerFids, int allowedCycleDepth ) {
+ this(appSchema, createBlobMapping, createRelationalMapping, geometryParams, maxLength,
+ usePrefixedSQLIdentifiers, useIntegerFids, allowedCycleDepth, null );
+ }
+ /**
+ * Creates a new {@link AppSchemaMapper} instance for the given schema.
+ *
+ * @param appSchema
+ * application schema to be mapped, must not be null
+ * @param createBlobMapping
+ * true, if BLOB mapping should be performed, false otherwise
+ * @param createRelationalMapping
+ * true, if relational mapping should be performed, false otherwise
+ * @param geometryParams
+ * parameters for storing geometries, must not be null
+ * @param maxLength
+ * max length of column names
+ * @param usePrefixedSQLIdentifiers
+ * true
if the sql identifiers should be prefixed, false
otherwise
+ * @param useIntegerFids
+ * true
if the integer fids should be used, false
for uuids
+ * @param allowedCycleDepth
+ * depth of the allowed cycles
+ * @param referenceData
+ * describing the data stored in the features store
+ */
+ public AppSchemaMapper( AppSchema appSchema, boolean createBlobMapping, boolean createRelationalMapping,
+ GeometryStorageParams geometryParams, int maxLength, boolean usePrefixedSQLIdentifiers,
+ boolean useIntegerFids, int allowedCycleDepth, ReferenceData referenceData ) {
this.appSchema = appSchema;
this.geometryParams = geometryParams;
this.useIntegerFids = useIntegerFids;
this.allowedCycleDepth = allowedCycleDepth;
this.maxComplexityIndex = DEFAULT_COMPLEXITY_INDEX * ( allowedCycleDepth + 1 );
+ this.referenceData = referenceData;
List ftList = appSchema.getFeatureTypes( null, false, false );
List blackList = new ArrayList();
@@ -262,7 +291,7 @@ private FeatureTypeMapping[] generateFtMappings( FeatureType[] fts ) {
}
private FeatureTypeMapping generateFtMapping( FeatureType ft ) {
- CycleAnalyser cycleAnalyser = new CycleAnalyser( allowedCycleDepth );
+ CycleAnalyser cycleAnalyser = new CycleAnalyser( allowedCycleDepth, ft.getName() );
LOG.info( "Mapping feature type '" + ft.getName() + "'" );
MappingContext mc = mcManager.newContext( ft.getName(), detectPrimaryKeyColumnName() );
@@ -318,7 +347,7 @@ private List generatePropMapping( PropertyType pt, MappingContext mc, C
MappingContext propMc = null;
List jc = null;
- if ( pt.getMaxOccurs() == 1 ) {
+ if ( pt.getMaxOccurs() == 1 || referenceDataHasOnlyOne( cycleAnalyser ) ) {
propMc = mcManager.mapOneToOneElement( mc, eName );
} else {
propMc = mcManager.mapOneToManyElements( mc, eName );
@@ -354,7 +383,7 @@ private List generatePropMapping( PropertyType pt, MappingContext mc, C
}
if ( pt instanceof SimplePropertyType ) {
- mappings.add( generatePropMapping( (SimplePropertyType) pt, mc ) );
+ mappings.add( generatePropMapping( (SimplePropertyType) pt, mc, cycleAnalyser ) );
} else if ( pt instanceof GeometryPropertyType ) {
mappings.add( generatePropMapping( (GeometryPropertyType) pt, mc ) );
} else if ( pt instanceof FeaturePropertyType ) {
@@ -381,13 +410,13 @@ private List generatePropMapping( PropertyType pt, MappingContext mc, C
return mappings;
}
- private PrimitiveMapping generatePropMapping( SimplePropertyType pt, MappingContext mc ) {
+ private PrimitiveMapping generatePropMapping( SimplePropertyType pt, MappingContext mc, CycleAnalyser cycleAnalyser ) {
LOG.debug( "Mapping simple property '" + pt.getName() + "'" );
ValueReference path = getPropName( pt.getName() );
MappingContext propMc = null;
List jc = null;
MappingExpression mapping = null;
- if ( pt.getMaxOccurs() == 1 ) {
+ if ( pt.getMaxOccurs() == 1 || referenceDataHasOnlyOne( cycleAnalyser ) ) {
propMc = mcManager.mapOneToOneElement( mc, pt.getName() );
mapping = new DBField( propMc.getColumn() );
} else {
@@ -468,7 +497,7 @@ private CompoundMapping generatePropMapping( CustomPropertyType pt, MappingConte
MappingContext propMc = null;
List jc = null;
- if ( pt.getMaxOccurs() == 1 ) {
+ if ( pt.getMaxOccurs() == 1 || referenceDataHasOnlyOne( cycleAnalyser ) ) {
propMc = mcManager.mapOneToOneElement( mc, pt.getName() );
} else {
propMc = mcManager.mapOneToManyElements( mc, pt.getName() );
@@ -714,6 +743,8 @@ private List generateMapping( XSTerm term, int occurence, MappingContex
private List generateMapping( XSElementDeclaration elDecl, int occurence, MappingContext mc,
CycleAnalyser cycleAnalyser ) {
cycleAnalyser.add( elDecl );
+ if ( referenceDataHasOnlyOne( cycleAnalyser ) )
+ occurence = 1;
List mappings = new ArrayList();
@@ -818,6 +849,14 @@ private List generateMapping( XSWildcard wildCard, int occurrence, Mapp
return new ArrayList<>();
}
+ private boolean referenceDataHasOnlyOne( CycleAnalyser cycleAnalyser ) {
+ if ( referenceData == null )
+ return false;
+ List xpath = cycleAnalyser.getPath();
+ QName featureTypeName = cycleAnalyser.getFeatureTypeName();
+ return referenceData.hasZeroOrOneProperty( featureTypeName, xpath );
+ }
+
private String getName( QName name ) {
if ( name.getNamespaceURI() != null && !name.getNamespaceURI().equals( "" ) ) {
String prefix = nsToPrefix.get( name.getNamespaceURI() );
diff --git a/deegree-datastores/deegree-featurestores/deegree-featurestore-sql/src/main/java/org/deegree/feature/persistence/sql/mapper/CycleAnalyser.java b/deegree-datastores/deegree-featurestores/deegree-featurestore-sql/src/main/java/org/deegree/feature/persistence/sql/mapper/CycleAnalyser.java
index 8b6941dfd6..ff64bfb947 100644
--- a/deegree-datastores/deegree-featurestores/deegree-featurestore-sql/src/main/java/org/deegree/feature/persistence/sql/mapper/CycleAnalyser.java
+++ b/deegree-datastores/deegree-featurestores/deegree-featurestore-sql/src/main/java/org/deegree/feature/persistence/sql/mapper/CycleAnalyser.java
@@ -28,12 +28,16 @@ public class CycleAnalyser {
private final int allowedCycleDepth;
+ private final QName featureTypeName;
+
/**
* @param allowedCycleDepth
* the allowed depth of cycles
+ * @param featureTypeName name of the feature type, never null
*/
- CycleAnalyser( int allowedCycleDepth ) {
+ CycleAnalyser( int allowedCycleDepth, QName featureTypeName ) {
this.allowedCycleDepth = allowedCycleDepth;
+ this.featureTypeName = featureTypeName;
}
/**
@@ -141,6 +145,20 @@ public List getElementDeclarations() {
return parentEls;
}
+ /**
+ * @return the name of the feature type, never null
+ */
+ public QName getFeatureTypeName() {
+ return featureTypeName;
+ }
+
+ /**
+ * @return the current path. May be empty but never null
+ */
+ public List getPath() {
+ return path;
+ }
+
private void log() {
StringBuffer sb = new StringBuffer();
Map nameToCycleDepth = new HashMap<>();
diff --git a/deegree-datastores/deegree-featurestores/deegree-featurestore-sql/src/main/java/org/deegree/feature/persistence/sql/mapper/GmlReferenceData.java b/deegree-datastores/deegree-featurestores/deegree-featurestore-sql/src/main/java/org/deegree/feature/persistence/sql/mapper/GmlReferenceData.java
new file mode 100644
index 0000000000..5ee66dc257
--- /dev/null
+++ b/deegree-datastores/deegree-featurestores/deegree-featurestore-sql/src/main/java/org/deegree/feature/persistence/sql/mapper/GmlReferenceData.java
@@ -0,0 +1,89 @@
+package org.deegree.feature.persistence.sql.mapper;
+
+import org.deegree.commons.tom.ElementNode;
+import org.deegree.commons.tom.TypedObjectNode;
+import org.deegree.commons.tom.gml.property.Property;
+import org.deegree.cs.exceptions.UnknownCRSException;
+import org.deegree.feature.Feature;
+import org.deegree.feature.FeatureCollection;
+import org.deegree.gml.GMLInputFactory;
+import org.deegree.gml.GMLStreamReader;
+import org.deegree.gml.GMLVersion;
+
+import javax.xml.namespace.QName;
+import javax.xml.stream.XMLStreamException;
+import java.io.IOException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * @author Lyn Goltz
+ */
+public class GmlReferenceData implements ReferenceData {
+
+ private Map> features;
+
+ public GmlReferenceData( URL referenceData )
+ throws IOException, XMLStreamException, UnknownCRSException {
+ GMLStreamReader gmlStreamReader = GMLInputFactory.createGMLStreamReader( GMLVersion.GML_32, referenceData );
+ FeatureCollection featureCollection = gmlStreamReader.readFeatureCollection();
+ this.features = featureCollection.stream().collect( Collectors.groupingBy( Feature::getName ) );
+ }
+
+ @Override
+ public boolean hasZeroOrOneProperty( QName featureTypeName, List xpath ) {
+ List featuresOfType = this.features.get( featureTypeName );
+ if ( featuresOfType != null && !featuresOfType.isEmpty() ) {
+ for ( Feature feature : featuresOfType ) {
+ if ( hasMoreThanOne( feature, xpath ) )
+ return false;
+ }
+ return true;
+ }
+ return false;
+ }
+
+ private boolean hasMoreThanOne( Feature feature, List xpath ) {
+ if ( xpath.isEmpty() )
+ return true;
+ Iterator iterator = xpath.iterator();
+ QName firstProperty = iterator.next();
+ List properties = feature.getProperties( firstProperty );
+ return hasMoreThanOne( iterator, properties );
+ }
+
+ private boolean hasMoreThanOne( Iterator iterator, List properties ) {
+ if ( !iterator.hasNext() ) {
+ if ( properties.size() > 1 )
+ return true;
+ else
+ return false;
+ } else {
+ QName next = iterator.next();
+ for ( ElementNode property : properties ) {
+ List subProperties = getChildsByName( property, next );
+ if ( hasMoreThanOne( iterator, subProperties ) )
+ return true;
+ }
+ return false;
+ }
+ }
+
+ private List getChildsByName( ElementNode property, QName propertyName ) {
+ List properties = new ArrayList<>();
+ List children = property.getChildren();
+ for ( TypedObjectNode child : children ) {
+ if ( child instanceof ElementNode ) {
+ QName name = ( (ElementNode) child ).getName();
+ if ( name.equals( propertyName ) )
+ properties.add( (ElementNode) child );
+ }
+ }
+ return properties;
+ }
+
+}
diff --git a/deegree-datastores/deegree-featurestores/deegree-featurestore-sql/src/main/java/org/deegree/feature/persistence/sql/mapper/ReferenceData.java b/deegree-datastores/deegree-featurestores/deegree-featurestore-sql/src/main/java/org/deegree/feature/persistence/sql/mapper/ReferenceData.java
new file mode 100644
index 0000000000..1e22c50146
--- /dev/null
+++ b/deegree-datastores/deegree-featurestores/deegree-featurestore-sql/src/main/java/org/deegree/feature/persistence/sql/mapper/ReferenceData.java
@@ -0,0 +1,20 @@
+package org.deegree.feature.persistence.sql.mapper;
+
+import javax.xml.namespace.QName;
+import java.util.List;
+
+/**
+ * @author Lyn Goltz
+ */
+public interface ReferenceData {
+
+ /**
+ * @param featureTypeName
+ * the name of the feature type, never null
+ * @param xpath
+ * the steps describing the path to the feature, may be empty. but never null
+ * @return true
if the property identified by the path occurs one or zero times, false
otherwise
+ */
+ boolean hasZeroOrOneProperty( QName featureTypeName, List xpath );
+
+}
\ No newline at end of file
diff --git a/deegree-datastores/deegree-featurestores/deegree-featurestore-sql/src/test/java/org/deegree/feature/persistence/sql/mapper/AppSchemaMapperTest.java b/deegree-datastores/deegree-featurestores/deegree-featurestore-sql/src/test/java/org/deegree/feature/persistence/sql/mapper/AppSchemaMapperTest.java
index 4b72a2bc12..b6ce0aebf1 100644
--- a/deegree-datastores/deegree-featurestores/deegree-featurestore-sql/src/test/java/org/deegree/feature/persistence/sql/mapper/AppSchemaMapperTest.java
+++ b/deegree-datastores/deegree-featurestores/deegree-featurestore-sql/src/test/java/org/deegree/feature/persistence/sql/mapper/AppSchemaMapperTest.java
@@ -8,6 +8,7 @@
import org.deegree.feature.persistence.sql.MappedAppSchema;
import org.deegree.feature.persistence.sql.rules.CompoundMapping;
import org.deegree.feature.persistence.sql.rules.Mapping;
+import org.deegree.feature.persistence.sql.rules.PrimitiveMapping;
import org.deegree.feature.types.AppSchema;
import org.deegree.gml.schema.GMLAppSchemaReader;
import org.junit.Before;
@@ -20,13 +21,18 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import java.util.Map;
import static org.deegree.feature.types.property.GeometryPropertyType.CoordinateDimension.DIM_2;
import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
/**
* @author Lyn Goltz
@@ -35,6 +41,8 @@ public class AppSchemaMapperTest {
private static final QName FEATURE_A = new QName( "http://test.de/schema", "FeatureA" );
+ private static final QName FEATURE_B = new QName( "http://test.de/schema", "FeatureB" );
+
@Rule
public TemporaryFolder folder = new TemporaryFolder();
@@ -50,6 +58,8 @@ public class AppSchemaMapperTest {
private File schemaWithTwoSelfDependentCycles;
+ private File schemaForSampleValues;
+
@Before
public void copySchemas()
throws IOException {
@@ -59,6 +69,7 @@ public void copySchemas()
this.schemaWithSimpleCycle = copyToTmpFolder( "schemaWithSimpleCycle.xsd" );
this.schemaWithTwoCycles = copyToTmpFolder( "schemaWithTwoCycles.xsd" );
this.schemaWithTwoSelfDependentCycles = copyToTmpFolder( "schemaWithTwoSelfDependentCycles.xsd" );
+ this.schemaForSampleValues = copyToTmpFolder( "schemaForSampleValues.xsd" );
}
@Test
@@ -68,7 +79,7 @@ public void testWithSimpleCycle_Depth0()
AppSchema appSchema = xsdDecoder.extractAppSchema();
CRSRef storageCrs = CRSManager.getCRSRef( "EPSG:4326" );
- GeometryStorageParams geometryParams = new GeometryStorageParams( storageCrs, String.valueOf( "0" ), DIM_2 );
+ GeometryStorageParams geometryParams = new GeometryStorageParams( storageCrs, "0", DIM_2 );
AppSchemaMapper mapper = new AppSchemaMapper( appSchema, false, true, geometryParams, 63, true, true, 0 );
MappedAppSchema mappedSchema = mapper.getMappedSchema();
@@ -97,7 +108,7 @@ public void testWithSimpleCycle_Depth0_default()
AppSchema appSchema = xsdDecoder.extractAppSchema();
CRSRef storageCrs = CRSManager.getCRSRef( "EPSG:4326" );
- GeometryStorageParams geometryParams = new GeometryStorageParams( storageCrs, String.valueOf( "0" ), DIM_2 );
+ GeometryStorageParams geometryParams = new GeometryStorageParams( storageCrs, "0", DIM_2 );
AppSchemaMapper mapper = new AppSchemaMapper( appSchema, false, true, geometryParams, 63, true, true );
MappedAppSchema mappedSchema = mapper.getMappedSchema();
@@ -126,7 +137,7 @@ public void testWithSimpleCycle_Depth1()
AppSchema appSchema = xsdDecoder.extractAppSchema();
CRSRef storageCrs = CRSManager.getCRSRef( "EPSG:4326" );
- GeometryStorageParams geometryParams = new GeometryStorageParams( storageCrs, String.valueOf( "0" ), DIM_2 );
+ GeometryStorageParams geometryParams = new GeometryStorageParams( storageCrs, "0", DIM_2 );
AppSchemaMapper mapper = new AppSchemaMapper( appSchema, false, true, geometryParams, 63, true, true, 1 );
MappedAppSchema mappedSchema = mapper.getMappedSchema();
@@ -160,7 +171,7 @@ public void testWithSimpleCycle_Depth2()
AppSchema appSchema = xsdDecoder.extractAppSchema();
CRSRef storageCrs = CRSManager.getCRSRef( "EPSG:4326" );
- GeometryStorageParams geometryParams = new GeometryStorageParams( storageCrs, String.valueOf( "0" ), DIM_2 );
+ GeometryStorageParams geometryParams = new GeometryStorageParams( storageCrs, "0", DIM_2 );
AppSchemaMapper mapper = new AppSchemaMapper( appSchema, false, true, geometryParams, 63, true, true, 2 );
MappedAppSchema mappedSchema = mapper.getMappedSchema();
@@ -200,7 +211,7 @@ public void testWithCycle1_Depth2()
AppSchema appSchema = xsdDecoder.extractAppSchema();
CRSRef storageCrs = CRSManager.getCRSRef( "EPSG:4326" );
- GeometryStorageParams geometryParams = new GeometryStorageParams( storageCrs, String.valueOf( "0" ), DIM_2 );
+ GeometryStorageParams geometryParams = new GeometryStorageParams( storageCrs, "0", DIM_2 );
AppSchemaMapper mapper = new AppSchemaMapper( appSchema, false, true, geometryParams, 63, true, true, 2 );
MappedAppSchema mappedSchema = mapper.getMappedSchema();
@@ -249,7 +260,7 @@ public void testWithCycle1_assertNoLoop()
AppSchema appSchema = xsdDecoder.extractAppSchema();
CRSRef storageCrs = CRSManager.getCRSRef( "EPSG:4326" );
- GeometryStorageParams geometryParams = new GeometryStorageParams( storageCrs, String.valueOf( "0" ), DIM_2 );
+ GeometryStorageParams geometryParams = new GeometryStorageParams( storageCrs, "0", DIM_2 );
AppSchemaMapper mapper = new AppSchemaMapper( appSchema, false, true, geometryParams, 63, true, true, 2 );
MappedAppSchema mappedSchema = mapper.getMappedSchema();
@@ -265,7 +276,7 @@ public void testWithCycle2_assertNoLoop()
AppSchema appSchema = xsdDecoder.extractAppSchema();
CRSRef storageCrs = CRSManager.getCRSRef( "EPSG:4326" );
- GeometryStorageParams geometryParams = new GeometryStorageParams( storageCrs, String.valueOf( "0" ), DIM_2 );
+ GeometryStorageParams geometryParams = new GeometryStorageParams( storageCrs, "0", DIM_2 );
AppSchemaMapper mapper = new AppSchemaMapper( appSchema, false, true, geometryParams, 63, true, true, 2 );
MappedAppSchema mappedSchema = mapper.getMappedSchema();
@@ -281,7 +292,7 @@ public void testWithCycle3_assertNoLoop()
AppSchema appSchema = xsdDecoder.extractAppSchema();
CRSRef storageCrs = CRSManager.getCRSRef( "EPSG:4326" );
- GeometryStorageParams geometryParams = new GeometryStorageParams( storageCrs, String.valueOf( "0" ), DIM_2 );
+ GeometryStorageParams geometryParams = new GeometryStorageParams( storageCrs, "0", DIM_2 );
AppSchemaMapper mapper = new AppSchemaMapper( appSchema, false, true, geometryParams, 63, true, true, 2 );
MappedAppSchema mappedSchema = mapper.getMappedSchema();
@@ -297,7 +308,7 @@ public void testWithTwoCycles()
AppSchema appSchema = xsdDecoder.extractAppSchema();
CRSRef storageCrs = CRSManager.getCRSRef( "EPSG:4326" );
- GeometryStorageParams geometryParams = new GeometryStorageParams( storageCrs, String.valueOf( "0" ), DIM_2 );
+ GeometryStorageParams geometryParams = new GeometryStorageParams( storageCrs, "0", DIM_2 );
AppSchemaMapper mapper = new AppSchemaMapper( appSchema, false, true, geometryParams, 63, true, true, 2 );
MappedAppSchema mappedSchema = mapper.getMappedSchema();
@@ -393,7 +404,7 @@ public void testWithTwoSelfDependentCycles()
AppSchema appSchema = xsdDecoder.extractAppSchema();
CRSRef storageCrs = CRSManager.getCRSRef( "EPSG:4326" );
- GeometryStorageParams geometryParams = new GeometryStorageParams( storageCrs, String.valueOf( "0" ), DIM_2 );
+ GeometryStorageParams geometryParams = new GeometryStorageParams( storageCrs, "0", DIM_2 );
AppSchemaMapper mapper = new AppSchemaMapper( appSchema, false, true, geometryParams, 63, true, true, 1 );
MappedAppSchema mappedSchema = mapper.getMappedSchema();
@@ -452,31 +463,277 @@ public void testWithTwoSelfDependentCycles()
assertThat( getFeatureC( featureEofEDepth2Depth3Mapping ), is( nullValue() ) );
}
+ @Test
+ public void testWithoutReferenceData()
+ throws Exception {
+ GMLAppSchemaReader xsdDecoder = new GMLAppSchemaReader( null, null, schemaForSampleValues );
+ AppSchema appSchema = xsdDecoder.extractAppSchema();
+
+ CRSRef storageCrs = CRSManager.getCRSRef( "EPSG:4326" );
+ GeometryStorageParams geometryParams = new GeometryStorageParams( storageCrs, "0", DIM_2 );
+ AppSchemaMapper mapper = new AppSchemaMapper( appSchema, false, true, geometryParams, 63, true, true, 0, null );
+
+ MappedAppSchema mappedSchema = mapper.getMappedSchema();
+
+ Map ftMappings = mappedSchema.getFtMappings();
+ assertThat( ftMappings.size(), is( 2 ) );
+
+ FeatureTypeMapping featureA = mappedSchema.getFtMapping( FEATURE_A );
+ List mappings = featureA.getMappings();
+ assertThat( mappings.size(), is( 5 ) );
+ assertThat( getPrimitive( mappings, "prop_A1" ).getJoinedTable(), is( notNullValue() ) );
+ assertThat( getPrimitive( mappings, "prop_A2" ).getJoinedTable(), is( nullValue() ) );
+ assertThat( getPrimitive( mappings, "prop_A3" ).getJoinedTable(), is( notNullValue() ) );
+ }
+
+ @Test
+ public void testWithReferenceData()
+ throws Exception {
+ GMLAppSchemaReader xsdDecoder = new GMLAppSchemaReader( null, null, schemaForSampleValues );
+ AppSchema appSchema = xsdDecoder.extractAppSchema();
+
+ QName featureTypeName = new QName( "http://test.de/schema", "FeatureA", "te" );
+ ReferenceData referenceData = mock( ReferenceData.class );
+ QName propA1 = new QName( "http://test.de/schema", "prop_A1", "te" );
+ when( referenceData.hasZeroOrOneProperty( featureTypeName, Collections.singletonList( propA1 ) ) ).thenReturn( false );
+ QName propA3 = new QName( "http://test.de/schema", "prop_A3", "te" );
+ when( referenceData.hasZeroOrOneProperty( featureTypeName, Collections.singletonList( propA3 ) ) ).thenReturn( true );
+
+ CRSRef storageCrs = CRSManager.getCRSRef( "EPSG:4326" );
+ GeometryStorageParams geometryParams = new GeometryStorageParams( storageCrs, "0", DIM_2 );
+ AppSchemaMapper mapper = new AppSchemaMapper( appSchema, false, true, geometryParams, 63, true, true, 0, referenceData );
+
+ MappedAppSchema mappedSchema = mapper.getMappedSchema();
+
+ Map ftMappings = mappedSchema.getFtMappings();
+ assertThat( ftMappings.size(), is( 2 ) );
+
+ FeatureTypeMapping featureA = mappedSchema.getFtMapping( FEATURE_A );
+ List mappings = featureA.getMappings();
+ assertThat( mappings.size(), is( 5 ) );
+ assertThat( getPrimitive( mappings, "prop_A1" ).getJoinedTable(), is( notNullValue() ) );
+ assertThat( getPrimitive( mappings, "prop_A2" ).getJoinedTable(), is( nullValue() ) );
+ assertThat( getPrimitive( mappings, "prop_A3" ).getJoinedTable(), is( nullValue() ) );
+ }
+
+ @Test
+ public void testWithReferenceData_ComplexData_ComplexN()
+ throws Exception {
+ GMLAppSchemaReader xsdDecoder = new GMLAppSchemaReader( null, null, schemaForSampleValues );
+ AppSchema appSchema = xsdDecoder.extractAppSchema();
+
+ QName featureTypeName = new QName( "http://test.de/schema", "FeatureA", "te" );
+ ReferenceData referenceData = mock( ReferenceData.class );
+ QName propA1 = new QName( "http://test.de/schema", "prop_A1", "te" );
+ when( referenceData.hasZeroOrOneProperty( featureTypeName, Collections.singletonList( propA1 ) ) ).thenReturn( false );
+ QName propA3 = new QName( "http://test.de/schema", "prop_A3", "te" );
+ when( referenceData.hasZeroOrOneProperty( featureTypeName, Collections.singletonList( propA3 ) ) ).thenReturn( true );
+ QName propComplexA4 = new QName( "http://test.de/schema", "complex_A4", "te" );
+ when( referenceData.hasZeroOrOneProperty( featureTypeName, Collections.singletonList( propComplexA4 ) ) ).thenReturn( false );
+ List complexA4_1 = new ArrayList<>();
+ complexA4_1.add( new QName( "http://test.de/schema", "complex_A4", "te" ) );
+ complexA4_1.add( new QName( "http://test.de/schema", "prop_A4_1", "te" ) );
+ when( referenceData.hasZeroOrOneProperty( featureTypeName, complexA4_1 ) ).thenReturn( false );
+ List complexA4_2 = new ArrayList<>();
+ complexA4_2.add( new QName( "http://test.de/schema", "complex_A4", "te" ) );
+ complexA4_2.add( new QName( "http://test.de/schema", "prop_A4_3", "te" ) );
+ when( referenceData.hasZeroOrOneProperty( featureTypeName, complexA4_2 ) ).thenReturn( true );
+
+ CRSRef storageCrs = CRSManager.getCRSRef( "EPSG:4326" );
+ GeometryStorageParams geometryParams = new GeometryStorageParams( storageCrs, "0", DIM_2 );
+ AppSchemaMapper mapper = new AppSchemaMapper( appSchema, false, true, geometryParams, 63, true, true, 0, referenceData );
+
+ MappedAppSchema mappedSchema = mapper.getMappedSchema();
+
+ Map ftMappings = mappedSchema.getFtMappings();
+ assertThat( ftMappings.size(), is( 2 ) );
+
+ FeatureTypeMapping feature = mappedSchema.getFtMapping( FEATURE_A );
+ List mappings = feature.getMappings();
+ assertThat( mappings.size(), is( 5 ) );
+ assertThat( getPrimitive( mappings, "prop_A1" ).getJoinedTable(), is( notNullValue() ) );
+ assertThat( getPrimitive( mappings, "prop_A2" ).getJoinedTable(), is( nullValue() ) );
+ assertThat( getPrimitive( mappings, "prop_A3" ).getJoinedTable(), is( nullValue() ) );
+ CompoundMapping complexMapping = getCompound( mappings, "complex_A4" );
+ assertThat( complexMapping.getJoinedTable(), is( notNullValue() ) );
+ List complexMappings = complexMapping.getParticles();
+ assertThat( getPrimitive( complexMappings, "prop_A4_1" ).getJoinedTable(), is( notNullValue() ) );
+ assertThat( getPrimitive( complexMappings, "prop_A4_2" ).getJoinedTable(), is( nullValue() ) );
+ assertThat( getPrimitive( complexMappings, "prop_A4_3" ).getJoinedTable(), is( nullValue() ) );
+ }
+
+ @Test
+ public void testWithReferenceData_ComplexData_Complex1()
+ throws Exception {
+ GMLAppSchemaReader xsdDecoder = new GMLAppSchemaReader( null, null, schemaForSampleValues );
+ AppSchema appSchema = xsdDecoder.extractAppSchema();
+
+ QName featureTypeName = new QName( "http://test.de/schema", "FeatureA", "te" );
+ ReferenceData referenceData = mock( ReferenceData.class );
+ QName propA1 = new QName( "http://test.de/schema", "prop_A1", "te" );
+ when( referenceData.hasZeroOrOneProperty( featureTypeName, Collections.singletonList( propA1 ) ) ).thenReturn( false );
+ QName propA3 = new QName( "http://test.de/schema", "prop_A3", "te" );
+ when( referenceData.hasZeroOrOneProperty( featureTypeName, Collections.singletonList( propA3 ) ) ).thenReturn( true );
+ QName propComplexA4 = new QName( "http://test.de/schema", "complex_A4", "te" );
+ when( referenceData.hasZeroOrOneProperty( featureTypeName, Collections.singletonList( propComplexA4 ) ) ).thenReturn( true );
+ List complexA4_1 = new ArrayList<>();
+ complexA4_1.add( new QName( "http://test.de/schema", "complex_A4", "te" ) );
+ complexA4_1.add( new QName( "http://test.de/schema", "prop_A4_1", "te" ) );
+ when( referenceData.hasZeroOrOneProperty( featureTypeName, complexA4_1 ) ).thenReturn( false );
+ List complexA4_2 = new ArrayList<>();
+ complexA4_2.add( new QName( "http://test.de/schema", "complex_A4", "te" ) );
+ complexA4_2.add( new QName( "http://test.de/schema", "prop_A4_3", "te" ) );
+ when( referenceData.hasZeroOrOneProperty( featureTypeName, complexA4_2 ) ).thenReturn( true );
+
+ CRSRef storageCrs = CRSManager.getCRSRef( "EPSG:4326" );
+ GeometryStorageParams geometryParams = new GeometryStorageParams( storageCrs, "0", DIM_2 );
+ AppSchemaMapper mapper = new AppSchemaMapper( appSchema, false, true, geometryParams, 63, true, true, 0, referenceData );
+
+ MappedAppSchema mappedSchema = mapper.getMappedSchema();
+
+ Map ftMappings = mappedSchema.getFtMappings();
+ assertThat( ftMappings.size(), is( 2 ) );
+
+ FeatureTypeMapping feature = mappedSchema.getFtMapping( FEATURE_A );
+ List mappings = feature.getMappings();
+ assertThat( mappings.size(), is( 5 ) );
+ assertThat( getPrimitive( mappings, "prop_A1" ).getJoinedTable(), is( notNullValue() ) );
+ assertThat( getPrimitive( mappings, "prop_A2" ).getJoinedTable(), is( nullValue() ) );
+ assertThat( getPrimitive( mappings, "prop_A3" ).getJoinedTable(), is( nullValue() ) );
+ CompoundMapping complexMapping = getCompound( mappings, "complex_A4" );
+ assertThat( complexMapping.getJoinedTable(), is( nullValue() ) );
+ List complexMappings = complexMapping.getParticles();
+ assertThat( getPrimitive( complexMappings, "prop_A4_1" ).getJoinedTable(), is( notNullValue() ) );
+ assertThat( getPrimitive( complexMappings, "prop_A4_2" ).getJoinedTable(), is( nullValue() ) );
+ assertThat( getPrimitive( complexMappings, "prop_A4_3" ).getJoinedTable(), is( nullValue() ) );
+ }
+
+ @Test
+ public void testWithReferenceData_ReferencedFeature_RefN()
+ throws Exception {
+ GMLAppSchemaReader xsdDecoder = new GMLAppSchemaReader( null, null, schemaForSampleValues );
+ AppSchema appSchema = xsdDecoder.extractAppSchema();
+
+ QName featureTypeNameB = new QName( "http://test.de/schema", "FeatureB", "te" );
+ ReferenceData referenceData = mock( ReferenceData.class );
+ QName propB1 = new QName( "http://test.de/schema", "prop_B1", "te" );
+ when( referenceData.hasZeroOrOneProperty( featureTypeNameB, Collections.singletonList( propB1 ) ) ).thenReturn( false );
+ QName propB3 = new QName( "http://test.de/schema", "prop_B3", "te" );
+ when( referenceData.hasZeroOrOneProperty( featureTypeNameB, Collections.singletonList( propB3 ) ) ).thenReturn( true );
+ QName propFfeatureA = new QName( "http://test.de/schema", "featureA", "te" );
+ when( referenceData.hasZeroOrOneProperty( featureTypeNameB, Collections.singletonList( propFfeatureA ) ) ).thenReturn( false );
+
+ QName featureTypeNameA = new QName( "http://test.de/schema", "FeatureA", "te" );
+ QName propA1 = new QName( "http://test.de/schema", "prop_A1", "te" );
+ when( referenceData.hasZeroOrOneProperty( featureTypeNameA, Collections.singletonList( propA1 ) ) ).thenReturn( false );
+ QName propA3 = new QName( "http://test.de/schema", "prop_A3", "te" );
+ when( referenceData.hasZeroOrOneProperty( featureTypeNameA, Collections.singletonList( propA3 ) ) ).thenReturn( true );
+
+ CRSRef storageCrs = CRSManager.getCRSRef( "EPSG:4326" );
+ GeometryStorageParams geometryParams = new GeometryStorageParams( storageCrs, "0", DIM_2 );
+ AppSchemaMapper mapper = new AppSchemaMapper( appSchema, false, true, geometryParams, 63, true, true, 0, referenceData );
+
+ MappedAppSchema mappedSchema = mapper.getMappedSchema();
+
+ Map ftMappings = mappedSchema.getFtMappings();
+ assertThat( ftMappings.size(), is( 2 ) );
+
+ FeatureTypeMapping featureB = mappedSchema.getFtMapping( FEATURE_B );
+ List mappingsB = featureB.getMappings();
+ assertThat( mappingsB.size(), is( 5 ) );
+ assertThat( getPrimitive( mappingsB, "prop_B1" ).getJoinedTable(), is( notNullValue() ) );
+ assertThat( getPrimitive( mappingsB, "prop_B2" ).getJoinedTable(), is( nullValue() ) );
+ assertThat( getPrimitive( mappingsB, "prop_B3" ).getJoinedTable(), is( nullValue() ) );
+ assertThat( getCompound( mappingsB, "featureA" ).getJoinedTable(), is( notNullValue() ) );
+
+ FeatureTypeMapping featureA = mappedSchema.getFtMapping( FEATURE_A );
+ List mappingsA = featureA.getMappings();
+ assertThat( mappingsA.size(), is( 5 ) );
+ assertThat( getPrimitive( mappingsA, "prop_A1" ).getJoinedTable(), is( notNullValue() ) );
+ assertThat( getPrimitive( mappingsA, "prop_A2" ).getJoinedTable(), is( nullValue() ) );
+ assertThat( getPrimitive( mappingsA, "prop_A3" ).getJoinedTable(), is( nullValue() ) );
+ }
+
+ @Test
+ public void testWithReferenceData_ReferencedFeature_Ref1()
+ throws Exception {
+ GMLAppSchemaReader xsdDecoder = new GMLAppSchemaReader( null, null, schemaForSampleValues );
+ AppSchema appSchema = xsdDecoder.extractAppSchema();
+
+ QName featureTypeNameB = new QName( "http://test.de/schema", "FeatureB", "te" );
+ ReferenceData referenceData = mock( ReferenceData.class );
+ QName propB1 = new QName( "http://test.de/schema", "prop_B1", "te" );
+ when( referenceData.hasZeroOrOneProperty( featureTypeNameB, Collections.singletonList( propB1 ) ) ).thenReturn( false );
+ QName propB3 = new QName( "http://test.de/schema", "prop_B3", "te" );
+ when( referenceData.hasZeroOrOneProperty( featureTypeNameB, Collections.singletonList( propB3 ) ) ).thenReturn( true );
+ QName propFfeatureA = new QName( "http://test.de/schema", "featureA", "te" );
+ when( referenceData.hasZeroOrOneProperty( featureTypeNameB, Collections.singletonList( propFfeatureA ) ) ).thenReturn( true );
+
+ QName featureTypeNameA = new QName( "http://test.de/schema", "FeatureA", "te" );
+ QName propA1 = new QName( "http://test.de/schema", "prop_A1", "te" );
+ when( referenceData.hasZeroOrOneProperty( featureTypeNameA, Collections.singletonList( propA1 ) ) ).thenReturn( false );
+ QName propA3 = new QName( "http://test.de/schema", "prop_A3", "te" );
+ when( referenceData.hasZeroOrOneProperty( featureTypeNameA, Collections.singletonList( propA3 ) ) ).thenReturn( true );
+
+ CRSRef storageCrs = CRSManager.getCRSRef( "EPSG:4326" );
+ GeometryStorageParams geometryParams = new GeometryStorageParams( storageCrs, "0", DIM_2 );
+ AppSchemaMapper mapper = new AppSchemaMapper( appSchema, false, true, geometryParams, 63, true, true, 0, referenceData );
+
+ MappedAppSchema mappedSchema = mapper.getMappedSchema();
+
+ Map ftMappings = mappedSchema.getFtMappings();
+ assertThat( ftMappings.size(), is( 2 ) );
+
+ FeatureTypeMapping featureB = mappedSchema.getFtMapping( FEATURE_B );
+ List mappingsB = featureB.getMappings();
+ assertThat( mappingsB.size(), is( 5 ) );
+ assertThat( getPrimitive( mappingsB, "prop_B1" ).getJoinedTable(), is( notNullValue() ) );
+ assertThat( getPrimitive( mappingsB, "prop_B2" ).getJoinedTable(), is( nullValue() ) );
+ assertThat( getPrimitive( mappingsB, "prop_B3" ).getJoinedTable(), is( nullValue() ) );
+ assertThat( getCompound( mappingsB, "featureA" ).getJoinedTable(), is( nullValue() ) );
+
+ FeatureTypeMapping featureA = mappedSchema.getFtMapping( FEATURE_A );
+ List mappingsA = featureA.getMappings();
+ assertThat( mappingsA.size(), is( 5 ) );
+ assertThat( getPrimitive( mappingsA, "prop_A1" ).getJoinedTable(), is( notNullValue() ) );
+ assertThat( getPrimitive( mappingsA, "prop_A2" ).getJoinedTable(), is( nullValue() ) );
+ assertThat( getPrimitive( mappingsA, "prop_A3" ).getJoinedTable(), is( nullValue() ) );
+ }
+
private CompoundMapping getFeatureC( List mappings ) {
- return getFeature( mappings, "FeatureC" );
+ return getCompound( mappings, "FeatureC" );
}
private CompoundMapping getFeatureD( List mappings ) {
- return getFeature( mappings, "FeatureD" );
+ return getCompound( mappings, "FeatureD" );
}
private CompoundMapping getFeatureE( List mappings ) {
- return getFeature( mappings, "FeatureE" );
+ return getCompound( mappings, "FeatureE" );
}
private CompoundMapping getFeatureF( List mappings ) {
- return getFeature( mappings, "FeatureF" );
+ return getCompound( mappings, "FeatureF" );
}
- private CompoundMapping getFeature( List mappings, String featureE ) {
+ private CompoundMapping getCompound( List mappings, String name ) {
for ( Mapping mapping : mappings ) {
- if ( mapping.getPath().getAsQName().getLocalPart().equals( featureE ) ) {
+ if ( mapping.getPath().getAsQName().getLocalPart().equals( name ) ) {
return (CompoundMapping) mapping;
}
}
return null;
}
+ private PrimitiveMapping getPrimitive( List mappings, String name ) {
+ for ( Mapping mapping : mappings ) {
+ if ( mapping.getPath().getAsQName().getLocalPart().equals( name ) ) {
+ return (PrimitiveMapping) mapping;
+ }
+ }
+ return null;
+ }
+
private File copyToTmpFolder( String resourceName )
throws IOException {
InputStream resource = AppSchemaMapperTest.class.getResourceAsStream( resourceName );
diff --git a/deegree-datastores/deegree-featurestores/deegree-featurestore-sql/src/test/java/org/deegree/feature/persistence/sql/mapper/GmlReferenceDataTest.java b/deegree-datastores/deegree-featurestores/deegree-featurestore-sql/src/test/java/org/deegree/feature/persistence/sql/mapper/GmlReferenceDataTest.java
new file mode 100644
index 0000000000..bbe8595414
--- /dev/null
+++ b/deegree-datastores/deegree-featurestores/deegree-featurestore-sql/src/test/java/org/deegree/feature/persistence/sql/mapper/GmlReferenceDataTest.java
@@ -0,0 +1,202 @@
+package org.deegree.feature.persistence.sql.mapper;
+
+import org.junit.Test;
+
+import javax.xml.namespace.QName;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import static java.util.Arrays.asList;
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+
+/**
+ * @author Lyn Goltz
+ */
+public class GmlReferenceDataTest {
+
+ private static final QName FEATURETYPE_A_NAME = new QName( "http://test.de/schema", "FeatureA", "te" );
+
+ private static final QName PROP_A1_NAME = new QName( "http://test.de/schema", "prop_A1", "te" );
+
+ private static final QName PROP_A3_NAME = new QName( "http://test.de/schema", "prop_A3", "te" );
+
+ private static final QName PROP_COMPLEX_A4_NAME = new QName( "http://test.de/schema", "complex_A4", "te" );
+
+ private static final QName PROP_COMPLEX_A4_1_NAME = new QName( "http://test.de/schema", "prop_A4_1", "te" );
+
+ private static final QName PROP_COMPLEX_A4_3_NAME = new QName( "http://test.de/schema", "prop_A4_3", "te" );
+
+ private static final QName FEATURETYPE_B_NAME = new QName( "http://test.de/schema", "FeatureB", "te" );
+
+ private static final QName PROP_B1_NAME = new QName( "http://test.de/schema", "prop_B1", "te" );
+
+ private static final QName PROP_B3_NAME = new QName( "http://test.de/schema", "prop_B3", "te" );
+
+ @Test
+ public void test_NoSample()
+ throws Exception {
+ URL resource = getClass().getResource( "data/sampleValues_simple_1.xml" );
+ GmlReferenceData gmlReferenceData = new GmlReferenceData( resource );
+
+ boolean hasMaxOne1 = gmlReferenceData.hasZeroOrOneProperty( FEATURETYPE_B_NAME,
+ Collections.singletonList( PROP_B1_NAME ) );
+ assertThat( hasMaxOne1, is( false ) );
+ }
+
+ @Test
+ public void test_NoProperty()
+ throws Exception {
+ URL resource = getClass().getResource( "data/sampleValues_simple_1.xml" );
+ GmlReferenceData gmlReferenceData = new GmlReferenceData( resource );
+
+ boolean hasMaxOne2 = gmlReferenceData.hasZeroOrOneProperty( FEATURETYPE_A_NAME,
+ Collections.singletonList( PROP_A3_NAME ) );
+ assertThat( hasMaxOne2, is( true ) );
+ }
+
+ @Test
+ public void test_Simple_1()
+ throws Exception {
+ URL resource = getClass().getResource( "data/sampleValues_simple_1.xml" );
+ GmlReferenceData gmlReferenceData = new GmlReferenceData( resource );
+
+ boolean hasMaxOne1 = gmlReferenceData.hasZeroOrOneProperty( FEATURETYPE_A_NAME,
+ Collections.singletonList( PROP_A1_NAME ) );
+ assertThat( hasMaxOne1, is( true ) );
+
+ boolean hasMaxOne3 = gmlReferenceData.hasZeroOrOneProperty( FEATURETYPE_A_NAME,
+ Collections.singletonList( PROP_A3_NAME ) );
+ assertThat( hasMaxOne3, is( true ) );
+ }
+
+ @Test
+ public void test_Simple_N()
+ throws Exception {
+ URL resource = getClass().getResource( "data/sampleValues_simple_N.xml" );
+ GmlReferenceData gmlReferenceData = new GmlReferenceData( resource );
+
+ boolean hasMaxOne1 = gmlReferenceData.hasZeroOrOneProperty( FEATURETYPE_A_NAME,
+ Collections.singletonList( PROP_A1_NAME ) );
+ assertThat( hasMaxOne1, is( false ) );
+
+ boolean hasMaxOne3 = gmlReferenceData.hasZeroOrOneProperty( FEATURETYPE_A_NAME,
+ Collections.singletonList( PROP_A3_NAME ) );
+ assertThat( hasMaxOne3, is( false ) );
+ }
+
+ @Test
+ public void test_Complex_1()
+ throws Exception {
+ URL resource = getClass().getResource( "data/sampleValues_complex_1.xml" );
+ GmlReferenceData gmlReferenceData = new GmlReferenceData( resource );
+
+ boolean hasMaxOneB1 = gmlReferenceData.hasZeroOrOneProperty( FEATURETYPE_A_NAME,
+ Collections.singletonList(
+ PROP_COMPLEX_A4_NAME ) );
+ assertThat( hasMaxOneB1, is( true ) );
+
+ boolean hasMaxOneA4_1 = gmlReferenceData.hasZeroOrOneProperty( FEATURETYPE_A_NAME,
+ asList( PROP_COMPLEX_A4_NAME,
+ PROP_COMPLEX_A4_1_NAME ) );
+ assertThat( hasMaxOneA4_1, is( true ) );
+
+ boolean hasMaxOneA4_3 = gmlReferenceData.hasZeroOrOneProperty( FEATURETYPE_A_NAME,
+ asList( PROP_COMPLEX_A4_NAME,
+ PROP_COMPLEX_A4_3_NAME ) );
+ assertThat( hasMaxOneA4_3, is( true ) );
+ }
+
+ @Test
+ public void test_Complex_N()
+ throws Exception {
+ URL resource = getClass().getResource( "data/sampleValues_complex_N.xml" );
+ GmlReferenceData gmlReferenceData = new GmlReferenceData( resource );
+
+ boolean hasMaxOneB1 = gmlReferenceData.hasZeroOrOneProperty( FEATURETYPE_A_NAME,
+ Collections.singletonList(
+ PROP_COMPLEX_A4_NAME ) );
+ assertThat( hasMaxOneB1, is( false ) );
+
+ boolean hasMaxOneA4_1 = gmlReferenceData.hasZeroOrOneProperty( FEATURETYPE_A_NAME,
+ asList( PROP_COMPLEX_A4_NAME,
+ PROP_COMPLEX_A4_1_NAME ) );
+ assertThat( hasMaxOneA4_1, is( false ) );
+
+ boolean hasMaxOneA4_3 = gmlReferenceData.hasZeroOrOneProperty( FEATURETYPE_A_NAME,
+ asList( PROP_COMPLEX_A4_NAME,
+ PROP_COMPLEX_A4_3_NAME ) );
+ assertThat( hasMaxOneA4_3, is( true ) );
+ }
+
+ @Test
+ public void test_Reference_1()
+ throws Exception {
+ URL resource = getClass().getResource( "data/sampleValues_reference_1.xml" );
+ GmlReferenceData gmlReferenceData = new GmlReferenceData( resource );
+
+ boolean hasMaxOneB1 = gmlReferenceData.hasZeroOrOneProperty( FEATURETYPE_B_NAME,
+ Collections.singletonList( PROP_B1_NAME ) );
+ assertThat( hasMaxOneB1, is( false ) );
+
+ boolean hasMaxOneB3 = gmlReferenceData.hasZeroOrOneProperty( FEATURETYPE_B_NAME,
+ Collections.singletonList( PROP_B3_NAME ) );
+ assertThat( hasMaxOneB3, is( false ) );
+
+ boolean hasMaxOneA1 = gmlReferenceData.hasZeroOrOneProperty( FEATURETYPE_A_NAME,
+ Collections.singletonList( PROP_A1_NAME ) );
+ assertThat( hasMaxOneA1, is( false ) );
+
+ boolean hasMaxOneA3 = gmlReferenceData.hasZeroOrOneProperty( FEATURETYPE_A_NAME,
+ Collections.singletonList( PROP_A3_NAME ) );
+ assertThat( hasMaxOneA3, is( false ) );
+ }
+
+ @Test
+ public void test_Reference_N()
+ throws Exception {
+ URL resource = getClass().getResource( "data/sampleValues_reference_N.xml" );
+ GmlReferenceData gmlReferenceData = new GmlReferenceData( resource );
+
+ boolean hasMaxOneB1 = gmlReferenceData.hasZeroOrOneProperty( FEATURETYPE_B_NAME,
+ Collections.singletonList( PROP_B1_NAME ) );
+ assertThat( hasMaxOneB1, is( false ) );
+
+ boolean hasMaxOneB3 = gmlReferenceData.hasZeroOrOneProperty( FEATURETYPE_B_NAME,
+ Collections.singletonList( PROP_B3_NAME ) );
+ assertThat( hasMaxOneB3, is( false ) );
+
+ boolean hasMaxOneA1 = gmlReferenceData.hasZeroOrOneProperty( FEATURETYPE_A_NAME,
+ Collections.singletonList( PROP_A1_NAME ) );
+ assertThat( hasMaxOneA1, is( false ) );
+
+ boolean hasMaxOneA3 = gmlReferenceData.hasZeroOrOneProperty( FEATURETYPE_A_NAME,
+ Collections.singletonList( PROP_A3_NAME ) );
+ assertThat( hasMaxOneA3, is( false ) );
+ }
+
+ @Test
+ public void test_Inspire()
+ throws Exception {
+ URL resource = getClass().getResource( "data/Inspire-Adress.xml" );
+ GmlReferenceData gmlReferenceData = new GmlReferenceData( resource );
+
+ QName AdressFeatureTypeName = new QName( "http://inspire.ec.europa.eu/schemas/ad/4.0", "Address", "ad" );
+ QName position = new QName( "http://test.de/schema", "position", "te" );
+
+ List posSpec = new ArrayList<>();
+ posSpec.add( position );
+ posSpec.add( new QName( "http://test.de/schema", "GeographicPosition", "te" ) );
+ posSpec.add( new QName( "http://test.de/schema", "specification", "te" ) );
+
+ boolean hasMaxOnePosition = gmlReferenceData.hasZeroOrOneProperty( AdressFeatureTypeName,
+ Collections.singletonList( position ) );
+ assertThat( hasMaxOnePosition, is( true ) );
+
+ boolean hasMaxOnePosSpec = gmlReferenceData.hasZeroOrOneProperty( AdressFeatureTypeName, posSpec );
+ assertThat( hasMaxOnePosSpec, is( true ) );
+ }
+
+}
\ No newline at end of file
diff --git a/deegree-datastores/deegree-featurestores/deegree-featurestore-sql/src/test/resources/org/deegree/feature/persistence/sql/mapper/data/Inspire-Adress.xml b/deegree-datastores/deegree-featurestores/deegree-featurestore-sql/src/test/resources/org/deegree/feature/persistence/sql/mapper/data/Inspire-Adress.xml
new file mode 100644
index 0000000000..3040f59987
--- /dev/null
+++ b/deegree-datastores/deegree-featurestores/deegree-featurestore-sql/src/test/resources/org/deegree/feature/persistence/sql/mapper/data/Inspire-Adress.xml
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+ Address_1
+ https://registry.gdi-de.org/id
+
+
+
+
+
+
+
+ 49.119752 7.046397
+
+
+
+
+ true
+
+
+
+
+
+
+
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/deegree-datastores/deegree-featurestores/deegree-featurestore-sql/src/test/resources/org/deegree/feature/persistence/sql/mapper/data/sampleValues_complex_1.xml b/deegree-datastores/deegree-featurestores/deegree-featurestore-sql/src/test/resources/org/deegree/feature/persistence/sql/mapper/data/sampleValues_complex_1.xml
new file mode 100644
index 0000000000..dd40d2cc5d
--- /dev/null
+++ b/deegree-datastores/deegree-featurestores/deegree-featurestore-sql/src/test/resources/org/deegree/feature/persistence/sql/mapper/data/sampleValues_complex_1.xml
@@ -0,0 +1,19 @@
+
+
+
+
+ B-OneA
+ B-OneB
+ 22
+ 231
+ 232
+
+ A4-One
+ 2
+
+
+
+
\ No newline at end of file
diff --git a/deegree-datastores/deegree-featurestores/deegree-featurestore-sql/src/test/resources/org/deegree/feature/persistence/sql/mapper/data/sampleValues_complex_N.xml b/deegree-datastores/deegree-featurestores/deegree-featurestore-sql/src/test/resources/org/deegree/feature/persistence/sql/mapper/data/sampleValues_complex_N.xml
new file mode 100644
index 0000000000..2c159c081a
--- /dev/null
+++ b/deegree-datastores/deegree-featurestores/deegree-featurestore-sql/src/test/resources/org/deegree/feature/persistence/sql/mapper/data/sampleValues_complex_N.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ B-OneA
+ B-OneB
+ 22
+ 231
+ 232
+
+ A4-One
+ 2
+ 3
+
+
+ A4-One-1
+ A4-One-2
+ 21
+ 31
+
+
+
+
\ No newline at end of file
diff --git a/deegree-datastores/deegree-featurestores/deegree-featurestore-sql/src/test/resources/org/deegree/feature/persistence/sql/mapper/data/sampleValues_reference_1.xml b/deegree-datastores/deegree-featurestores/deegree-featurestore-sql/src/test/resources/org/deegree/feature/persistence/sql/mapper/data/sampleValues_reference_1.xml
new file mode 100644
index 0000000000..c3d74d02d0
--- /dev/null
+++ b/deegree-datastores/deegree-featurestores/deegree-featurestore-sql/src/test/resources/org/deegree/feature/persistence/sql/mapper/data/sampleValues_reference_1.xml
@@ -0,0 +1,22 @@
+
+
+
+
+ OneA
+ OneB
+ 2
+ 31
+ 32
+
+
+ B-OneA
+ B-OneB
+ 22
+
+
+
+
+
\ No newline at end of file
diff --git a/deegree-datastores/deegree-featurestores/deegree-featurestore-sql/src/test/resources/org/deegree/feature/persistence/sql/mapper/data/sampleValues_reference_N.xml b/deegree-datastores/deegree-featurestores/deegree-featurestore-sql/src/test/resources/org/deegree/feature/persistence/sql/mapper/data/sampleValues_reference_N.xml
new file mode 100644
index 0000000000..e5ada79645
--- /dev/null
+++ b/deegree-datastores/deegree-featurestores/deegree-featurestore-sql/src/test/resources/org/deegree/feature/persistence/sql/mapper/data/sampleValues_reference_N.xml
@@ -0,0 +1,33 @@
+
+
+
+
+ OneA
+ OneB
+ 2
+ 31
+ 32
+
+
+ B-OneA
+ B-OneB
+ 22
+ 231
+ 232
+
+
+
+
+ B-OneA
+ B-OneB
+ 22
+ 231
+ 232
+
+
+
+
+
\ No newline at end of file
diff --git a/deegree-datastores/deegree-featurestores/deegree-featurestore-sql/src/test/resources/org/deegree/feature/persistence/sql/mapper/data/sampleValues_simple_1.xml b/deegree-datastores/deegree-featurestores/deegree-featurestore-sql/src/test/resources/org/deegree/feature/persistence/sql/mapper/data/sampleValues_simple_1.xml
new file mode 100644
index 0000000000..08737973b0
--- /dev/null
+++ b/deegree-datastores/deegree-featurestores/deegree-featurestore-sql/src/test/resources/org/deegree/feature/persistence/sql/mapper/data/sampleValues_simple_1.xml
@@ -0,0 +1,12 @@
+
+
+
+
+ One
+ 2
+
+
+
\ No newline at end of file
diff --git a/deegree-datastores/deegree-featurestores/deegree-featurestore-sql/src/test/resources/org/deegree/feature/persistence/sql/mapper/data/sampleValues_simple_N.xml b/deegree-datastores/deegree-featurestores/deegree-featurestore-sql/src/test/resources/org/deegree/feature/persistence/sql/mapper/data/sampleValues_simple_N.xml
new file mode 100644
index 0000000000..8cc4971523
--- /dev/null
+++ b/deegree-datastores/deegree-featurestores/deegree-featurestore-sql/src/test/resources/org/deegree/feature/persistence/sql/mapper/data/sampleValues_simple_N.xml
@@ -0,0 +1,15 @@
+
+
+
+
+ OneA
+ OneB
+ 2
+ 31
+ 32
+
+
+
\ No newline at end of file
diff --git a/deegree-datastores/deegree-featurestores/deegree-featurestore-sql/src/test/resources/org/deegree/feature/persistence/sql/mapper/schemaForSampleValues.xsd b/deegree-datastores/deegree-featurestores/deegree-featurestore-sql/src/test/resources/org/deegree/feature/persistence/sql/mapper/schemaForSampleValues.xsd
new file mode 100644
index 0000000000..e34b9f4675
--- /dev/null
+++ b/deegree-datastores/deegree-featurestores/deegree-featurestore-sql/src/test/resources/org/deegree/feature/persistence/sql/mapper/schemaForSampleValues.xsd
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/deegree-services/deegree-webservices-handbook/src/main/asciidoc/cli-utility.adoc b/deegree-services/deegree-webservices-handbook/src/main/asciidoc/cli-utility.adoc
new file mode 100644
index 0000000000..7380595cdc
--- /dev/null
+++ b/deegree-services/deegree-webservices-handbook/src/main/asciidoc/cli-utility.adoc
@@ -0,0 +1,213 @@
+[[deegree-cli-utility]]
+== deegree-cli-utility
+
+Command line utility to generate `DDL` and `deegree SQLFeatureStore` from GML application schemas.
+
+You can download the latest release from http://repo.deegree.org/content/repositories/public/org/deegree/deegree-tools-config. The distribution bundle must be unpacked in an arbitrary directory.
+
+=== Prerequisite
+
+Java is installed and the _JAVA_HOME_ system environment variable points to the correct installation directory
+of a compatible JDK.
+Supported JDK versions are listed in <>.
+
+=== Usage
+
+The executable sh and bat files are location in the directory _bin_ of the unpacked distribution. The following command shows the usage of this command line tool:
+
+----
+./d3config SqlFeatureStoreConfigCreator
+----
+
+Results in:
+
+----
+Usage: ./d3config SqlFeatureStoreConfigCreator [options] schema_url
+
+options:
+ --format={deegree|ddl|all} (default=deegree)
+ --srid= (default=4258)
+ --idtype={int|uuid} (default=int)
+ --mapping={relational|blob} (default=relational)
+ --dialect={postgis|oracle} (default=postgis)
+ --cycledepth=INT (positive integer value to specify the depth of cycles; default: 0)
+ --listOfPropertiesWithPrimitiveHref= (see below)
+ --referenceData= (GML Feature collection containing reference features. The generated config is simplified to map this feature collection).
+
+The option listOfPropertiesWithPrimitiveHref references a file listing properties which are written with primitive instead of feature mappings (see deegree-webservices documentation and README of this tool for further information):
+---------- begin file ----------
+# lines beginning with an # are ignored
+# property with namespace binding
+{http://inspire.ec.europa.eu/schemas/ps/4.0}designation
+# property without namespace binding
+designation
+# empty lines are ignored
+
+# leading and trailing white spaces are ignored
+---------- end file ----------
+----
+
+The SQL DDL and XML output is written into files in the current directory. The filename of each file is derived from the
+schema file name in the given `schema_url`.
+
+==== Usage of option cycledepth
+
+Some GML application schemas defines cycles, e.g. http://schemas.opengis.net/sweCommon/2.0/simple_components.xsd[Sensor Web Enablement (SWE) Common Data Model]: Quantity may have a complex property "quality", which may have a Quantity.
+In deegree it is not possible to configure infinite dependencies and it is not recommended to configure deep structures. With the option _cycledepth_ the max depth can be specified. The default is 0 which means, that writing of the configuration and DDL stops as soon as a cycle is detected. This is the recommended behaviour.
+
+==== Usage of option listOfPropertiesWithPrimitiveHref
+
+The option listOfPropertiesWithPrimitiveHref references a file listing properties which are written with primitive instead of feature mappings.
+
+For example, in some INSPIRE themes codelists values are stored in xlink:href attributes. Corresponding to the GML application schema the type is a gml:ReferenceType. Usually deegree would handle this as feature mapping but it is recommended to use a primitive mapping here.
+
+Primitive mapping enables direct filtering on those properties with deegree. For example, filtering on INSPIRE codelist hrefs is possible then.
+
+Syntax of content of file:
+
+----
+{NamespaceURI}localPart
+----
+
+If multiple properties shall use primitive mappings, they must be listed in new lines.
+
+Example:
+
+----
+{http://inspire.ec.europa.eu/schemas/gn/4.0}nativeness
+{http://inspire.ec.europa.eu/schemas/ps/4.0}designation
+----
+
+==== Usage of option referenceData
+
+The data which should be imported in a SQLFeatureStore may be much less complex than the GML application schema. This option allows to reference sample data which must be the highest complexity level as the data to import in the SQLFeatureStore configured with the generated configuration.
+The referenced file must contain a GML 3.2 FeatureCollection containing at least one featureMember. The deegree-cli-utility tool considers this data and tries to create a configuration with less complexity than the GML application schema allows.
+This concerns the cardinality of properties, e.g. if a property may occur multiple times but occurs only one time in the data, the configuration is limited to exact one occurrence of this property. The number of joins is reduced, which speeds up the creation of the java representation of the features.
+
+Reducing the complexity of the mapping can result in a much faster processing of requests, especially of GetMap requests. The features requested via WFS (GetFeature requests) are still schema conform.
+
+Example content of the referenced file:
+
+[source,xml]
+----
+
+
+
+
+ https://deegree.org/id/AdministrativeUnit_1
+
+ ...
+
+ 987789
+
+
+ AdministrativeUnit_1
+ https://deegree.org/id
+
+
+
+
+ Gemeinde
+
+
+ DE
+
+
+
+ deu
+
+
+
+
+
+
+ Test
+ Latn
+
+
+
+
+
+ 2021-09-08T13:49:44Z
+
+
+
+
+
+
+
+----
+
+=== Examples
+
+**Generate SQL DDL for INSPIRE Cadastral Parcels 4.0 with UUIDGenerator**
+
+----
+./d3config SqlFeatureStoreConfigCreator --srid=25832 --format=ddl --idtype=uuid http://inspire.ec.europa.eu/schemas/cp/4.0/CadastralParcels.xsd
+----
+
+The generated file is './CadastralParcels.sql'.
+
+**Generate deegree SQLFeatureStore for INSPIRE Cadastral Parcels 4.0 with UUIDGenerator**
+
+----
+./d3config SqlFeatureStoreConfigCreator --srid=25832 --format=deegree --idtype=uuid http://inspire.ec.europa.eu/schemas/cp/4.0/CadastralParcels.xsd
+----
+
+The generated file is './CadastralParcels.xml'.
+
+**Generate SQL DDL for INSPIRE Cadastral Parcels 4.0 with AutoIDGenerator**
+
+----
+./d3config SqlFeatureStoreConfigCreator --srid=25832 --format=ddl --idtype=int http://inspire.ec.europa.eu/schemas/cp/4.0/CadastralParcels.xsd
+----
+
+The generated file is './CadastralParcels.sql'.
+
+**Generate deegree SQLFeatureStore for INSPIRE Cadastral Parcels 4.0 with AutoIDGenerator**
+
+----
+./d3config SqlFeatureStoreConfigCreator --srid=25832 --format=deegree --idtype=int http://inspire.ec.europa.eu/schemas/cp/4.0/CadastralParcels.xsd
+----
+
+The generated file is './CadastralParcels.xml'.
+
+**Generate deegree SQLFeatureStore and SQL DDL for INSPIRE Cadastral Parcels 4.0 with AutoIDGenerator**
+
+----
+./d3config SqlFeatureStoreConfigCreator --srid=25832 --format=all --idtype=int http://inspire.ec.europa.eu/schemas/cp/4.0/CadastralParcels.xsd
+----
+
+The generated files are './CadastralParcels.sql' and './CadastralParcels.xml'.
+
+**Generate deegree SQLFeatureStore and SQL DDL for INSPIRE Cadastral Parcels 4.0 with Blob-Mapping**
+
+----
+./d3config SqlFeatureStoreConfigCreator --format=all --mapping=blob http://inspire.ec.europa.eu/schemas/cp/4.0/CadastralParcels.xsd
+----
+
+The generated files are './CadastralParcels.sql' and './CadastralParcels.xml' with Blob-Mapping for PostGIS.
+
+**Generate deegree SQLFeatureStore and SQL DDL for INSPIRE Cadastral Parcels 4.0 for Oracle DBMS with Oracle Locator**
+
+----
+./d3config SqlFeatureStoreConfigCreator --format=all --dialect=oracle http://inspire.ec.europa.eu/schemas/cp/4.0/CadastralParcels.xsd
+----
+
+The generated files are './CadastralParcels.sql' and './CadastralParcels.xml' with relational mapping for Oracle Locator.
+
+**Generate deegree SQLFeatureStore for INSPIRE Cadastral Parcels 4.0 with list of properties with primitive href**
+
+----
+./d3config SqlFeatureStoreConfigCreator --format=deegree --listOfPropertiesWithPrimitiveHref= http://inspire.ec.europa.eu/schemas/cp/4.0/CadastralParcels.xsd
+----
+
+The generated file is './CadastralParcels.xml'. All properties listed in the referenced file are written with primitive instead of feature mappings.
+
+=== Behind http proxy
+
+Set the `http.proxyHost`, `http.proxyPort` and `http.nonProxyHosts` config properties.
+
+----
+java -Dhttp.proxyHost=your-proxy.net -Dhttp.proxyPort=80 -jar deegree-cli-utility.jar --format=ddl --idtype=uuid http://inspire.ec.europa.eu/schemas/cp/4.0/CadastralParcels.xsd
+----
\ No newline at end of file
diff --git a/deegree-services/deegree-webservices-handbook/src/main/asciidoc/index.adoc b/deegree-services/deegree-webservices-handbook/src/main/asciidoc/index.adoc
index 31f6792f6a..f1153cb75f 100644
--- a/deegree-services/deegree-webservices-handbook/src/main/asciidoc/index.adoc
+++ b/deegree-services/deegree-webservices-handbook/src/main/asciidoc/index.adoc
@@ -45,6 +45,8 @@ include::crs.adoc[]
include::restapi.adoc[]
+include::cli-utility.adoc[]
+
include::javamodules.adoc[]
include::gdal.adoc[]
\ No newline at end of file
diff --git a/deegree-services/deegree-webservices-handbook/src/main/asciidoc/installation.adoc b/deegree-services/deegree-webservices-handbook/src/main/asciidoc/installation.adoc
index a2721ff33b..eb45407464 100644
--- a/deegree-services/deegree-webservices-handbook/src/main/asciidoc/installation.adoc
+++ b/deegree-services/deegree-webservices-handbook/src/main/asciidoc/installation.adoc
@@ -1,6 +1,7 @@
[[anchor-installation]]
== Installation
+[[system-requirements]]
=== System requirements
deegree webservices work on any platform with a compatible Java SE 8
diff --git a/deegree-tools/deegree-tools-config/README.md b/deegree-tools/deegree-tools-config/README.md
index f00e3fbfec..4e797bfc1a 100644
--- a/deegree-tools/deegree-tools-config/README.md
+++ b/deegree-tools/deegree-tools-config/README.md
@@ -1,105 +1,6 @@
# deegree-cli-utility
-[![Build Status](https://travis-ci.org/JuergenWeichand/deegree-cli-utility.svg?branch=master)](https://travis-ci.org/JuergenWeichand/deegree-cli-utility)
-
-Command line utility based on [deegree3](https://github.com/deegree/deegree3) to generate `DDL` and `deegree SQLFeatureStore` from GML application schemas.
-
-You can download the latest release [here](https://github.com/lat-lon/deegree-cli-utility/releases) or build it yourself.
-
- git clone https://github.com/lat-lon/deegree-cli-utility.git
- cd deegree-cli-utility/
- git checkout deegree-3.4
- mvn clean package -Pjar-with-dependencies
-
-## Usage
-
-```
-Usage: java -jar deegree-cli-utility.jar [options] schema_url
-
-options:
- --format={deegree|ddl|all}, default=deegree
- --srid=, default=4258
- --idtype={int|uuid}, default=int
- --mapping={relational|blob}, default=relational
- --dialect={postgis|oracle}, default=postgis
- --listOfPropertiesWithPrimitiveHref=
-```
-
-The SQL DDL and XML output is written into files in the current directory. The filename of each file is derived from the
-schema file name in the given `schema_url`.
-
-### Example: Generate SQL DDL for INSPIRE Cadastral Parcels 4.0 with UUIDGenerator
-
- java -jar deegree-cli-utility.jar --srid=25832 --format=ddl --idtype=uuid http://inspire.ec.europa.eu/schemas/cp/4.0/CadastralParcels.xsd
-
-The generated file is './CadastralParcels.sql'.
-
-### Example: Generate deegree SQLFeatureStore for INSPIRE Cadastral Parcels 4.0 with UUIDGenerator
-
- java -jar deegree-cli-utility.jar --srid=25832 --format=deegree --idtype=uuid http://inspire.ec.europa.eu/schemas/cp/4.0/CadastralParcels.xsd
-
-The generated file is './CadastralParcels.xml'.
-
-### Example: Generate SQL DDL for INSPIRE Cadastral Parcels 4.0 with AutoIDGenerator
-
- java -jar deegree-cli-utility.jar --srid=25832 --format=ddl --idtype=int http://inspire.ec.europa.eu/schemas/cp/4.0/CadastralParcels.xsd
-
-The generated file is './CadastralParcels.sql'.
-
-### Example: Generate deegree SQLFeatureStore for INSPIRE Cadastral Parcels 4.0 with AutoIDGenerator
-
- java -jar deegree-cli-utility.jar --srid=25832 --format=deegree --idtype=int http://inspire.ec.europa.eu/schemas/cp/4.0/CadastralParcels.xsd
-
-The generated file is './CadastralParcels.xml'.
-
-### Example: Generate deegree SQLFeatureStore and SQL DDL for INSPIRE Cadastral Parcels 4.0 with AutoIDGenerator
-
- java -jar deegree-cli-utility.jar --srid=25832 --format=all --idtype=int http://inspire.ec.europa.eu/schemas/cp/4.0/CadastralParcels.xsd
-
-The generated files are './CadastralParcels.sql' and './CadastralParcels.xml'.
-
-### Example: Generate deegree SQLFeatureStore and SQL DDL for INSPIRE Cadastral Parcels 4.0 with Blob-Mapping
-
- java -jar deegree-cli-utility.jar --format=all --mapping=blob http://inspire.ec.europa.eu/schemas/cp/4.0/CadastralParcels.xsd
-
-The generated files are './CadastralParcels.sql' and './CadastralParcels.xml' with Blob-Mapping for PostGIS.
-
-### Example: Generate deegree SQLFeatureStore and SQL DDL for INSPIRE Cadastral Parcels 4.0 for Oracle DBMS with Oracle Locator
-
- java -jar deegree-cli-utility.jar --format=all --dialect=oracle http://inspire.ec.europa.eu/schemas/cp/4.0/CadastralParcels.xsd
-
-The generated files are './CadastralParcels.sql' and './CadastralParcels.xml' with relational mapping for Oracle Locator.
-
-### Example: Generate deegree SQLFeatureStore for INSPIRE Cadastral Parcels 4.0 with list of properties with primitive href
-
- java -jar deegree-cli-utility.jar --format=deegree --listOfPropertiesWithPrimitiveHref= http://inspire.ec.europa.eu/schemas/cp/4.0/CadastralParcels.xsd
-
-The generated file is './CadastralParcels.xml'. All properties listed in the referenced file are written with primitive instead of feature mappings.
-
-## Usage of option listOfPropertiesWithPrimitiveHref
-
-The option listOfPropertiesWithPrimitiveHref references a file listing properties which are written with primitive instead of feature mappings.
-
-For example, in some INSPIRE themes codelists values are stored in xlink:href attributes. Corresponding to the GML appplication schema the type is a gml:ReferenceType. Usually deegree would handle this as feature mapping but it is recommended to use a primitive mapping here.
-
-Primitive mapping enables direct filtering on those properties with deegree. For example, filtering on INSPIRE codelist hrefs is possible then.
-
-Syntax of content of file:
-
- {NamespaceURI}localPart
-
-If multiple properties shall use primitive mappings, they must be listed in new lines.
-
-Example:
-
- {http://inspire.ec.europa.eu/schemas/gn/4.0}nativeness
- {http://inspire.ec.europa.eu/schemas/ps/4.0}designation
-
-## Behind http proxy
-
-Set the `http.proxyHost`, `http.proxyPort` and `http.nonProxyHosts` config properties.
-
- java -Dhttp.proxyHost=your-proxy.net -Dhttp.proxyPort=80 -jar deegree-cli-utility.jar --format=ddl --idtype=uuid http://inspire.ec.europa.eu/schemas/cp/4.0/CadastralParcels.xsd
+Migrated to [deegree Webservice Handbook](https://download.deegree.org/documentation/current/html/)
# License
diff --git a/deegree-tools/deegree-tools-config/src/main/java/org/deegree/tools/config/SqlFeatureStoreConfigCreator.java b/deegree-tools/deegree-tools-config/src/main/java/org/deegree/tools/config/SqlFeatureStoreConfigCreator.java
index 6dc843ff79..57421e0a96 100644
--- a/deegree-tools/deegree-tools-config/src/main/java/org/deegree/tools/config/SqlFeatureStoreConfigCreator.java
+++ b/deegree-tools/deegree-tools-config/src/main/java/org/deegree/tools/config/SqlFeatureStoreConfigCreator.java
@@ -25,8 +25,11 @@
import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
import java.io.IOException;
import java.net.URI;
+import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
@@ -48,6 +51,8 @@
import org.deegree.feature.persistence.sql.config.SQLFeatureStoreConfigWriter;
import org.deegree.feature.persistence.sql.ddl.DDLCreator;
import org.deegree.feature.persistence.sql.mapper.AppSchemaMapper;
+import org.deegree.feature.persistence.sql.mapper.GmlReferenceData;
+import org.deegree.feature.persistence.sql.mapper.ReferenceData;
import org.deegree.feature.types.AppSchema;
import org.deegree.gml.schema.GMLAppSchemaReader;
import org.deegree.sqldialect.SQLDialect;
@@ -83,20 +88,23 @@ public class SqlFeatureStoreConfigCreator {
private static List propertiesWithPrimitiveHref; // primitive href mapping instead of feature mapping is used
// in deegree configuration for listed properties
+ private static ReferenceData referenceData;
+
public static void main( String[] args )
throws Exception {
if ( args.length == 0 ) {
- System.out.println( "Usage: java -jar deegree-cli-utility.jar [options] schema_url" );
+ System.out.println( "Usage: ./d3config SqlFeatureStoreConfigCreator [options] schema_url" );
System.out.println( "" );
System.out.println( "options:" );
- System.out.println( " --format={deegree|ddl|all}" );
- System.out.println( " --srid=" );
- System.out.println( " --idtype={int|uuid}" );
- System.out.println( " --mapping={relational|blob}" );
- System.out.println( " --dialect={postgis|oracle}" );
+ System.out.println( " --format={deegree|ddl|all} (default=deegree)" );
+ System.out.println( " --srid= (default=4258)" );
+ System.out.println( " --idtype={int|uuid} (default=int)" );
+ System.out.println( " --mapping={relational|blob} (default=relational)" );
+ System.out.println( " --dialect={postgis|oracle} (default=postgis)" );
System.out.println( " --cycledepth=INT (positive integer value to specify the depth of cycles; default: 0)" );
- System.out.println( " --listOfPropertiesWithPrimitiveHref=" );
+ System.out.println( " --listOfPropertiesWithPrimitiveHref= (see below)" );
+ System.out.println( " --referenceData= (GML Feature collection containing reference features. The generated config is simplified to map this feature collection.)" );
System.out.println( "" );
System.out.println( "The option listOfPropertiesWithPrimitiveHref references a file listing properties which are written with primitive instead of feature mappings (see deegree-webservices documentation and README of this tool for further information):" );
System.out.println( "---------- begin file ----------" );
@@ -140,6 +148,11 @@ public static void main( String[] args )
String pathToFile = arg.split( "=" )[1];
propertiesWithPrimitiveHref = propertyNameParser.parsePropertiesWithPrimitiveHref( pathToFile );
System.out.println( "Using listOfPropertiesWithPrimitiveHref=" + propertiesWithPrimitiveHref );
+ } else if ( arg.startsWith( "--referenceData" ) ) {
+ String pathToFile = arg.split( "=" )[1];
+ File referenceDataUrl = new File( pathToFile );
+ referenceData = new GmlReferenceData( referenceDataUrl.toURI().toURL() );
+ System.out.println( "Using referenceData" + referenceDataUrl );
} else {
schemaUrl = arg;
}
@@ -153,7 +166,7 @@ public static void main( String[] args )
GeometryStorageParams geometryParams = new GeometryStorageParams( storageCrs, String.valueOf( srid ), DIM_2 );
AppSchemaMapper mapper = new AppSchemaMapper( appSchema, !relationalMapping, relationalMapping, geometryParams,
sqlDialect.getMaxColumnNameLength(), true, useIntegerFids,
- depth );
+ depth, referenceData );
MappedAppSchema mappedSchema = mapper.getMappedSchema();
SQLFeatureStoreConfigWriter configWriter = new SQLFeatureStoreConfigWriter( mappedSchema,
propertiesWithPrimitiveHref );