diff --git a/admin/src/main/resources/nl/ipo/cds/admin/admin-securityContext.xml b/admin/src/main/resources/nl/ipo/cds/admin/admin-securityContext.xml index 7c24ecaa..d6245970 100644 --- a/admin/src/main/resources/nl/ipo/cds/admin/admin-securityContext.xml +++ b/admin/src/main/resources/nl/ipo/cds/admin/admin-securityContext.xml @@ -15,17 +15,17 @@ http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd"> - - - - - + + + + + - + diff --git a/deegree-workspaces/Hydrography/datasources/feature/fdsHY.xml b/deegree-workspaces/Hydrography/datasources/feature/fdsHY.xml new file mode 100644 index 00000000..90e30186 --- /dev/null +++ b/deegree-workspaces/Hydrography/datasources/feature/fdsHY.xml @@ -0,0 +1,34 @@ + + + conHY + + + + + + + + + + + EPSG:28992 + + + + + + + + + + + + + + EPSG:28992 + + + + + \ No newline at end of file diff --git a/deegree-workspaces/Hydrography/datasources/feature/fdsInspireHY.xml b/deegree-workspaces/Hydrography/datasources/feature/fdsInspireHY.xml new file mode 100644 index 00000000..7b71c98a --- /dev/null +++ b/deegree-workspaces/Hydrography/datasources/feature/fdsInspireHY.xml @@ -0,0 +1,152 @@ + + conHY + EPSG:28992 + http://www.inspire-provincies.nl/schemas/hy-n/3.0/HydroNetwork.xsd + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/deegree-workspaces/Hydrography/jdbc/conHY.xml b/deegree-workspaces/Hydrography/jdbc/conHY.xml new file mode 100644 index 00000000..adfa6fd4 --- /dev/null +++ b/deegree-workspaces/Hydrography/jdbc/conHY.xml @@ -0,0 +1,3 @@ + + cds-inspire + diff --git a/deegree-workspaces/Hydrography/services/download_HY.xml b/deegree-workspaces/Hydrography/services/download_HY.xml new file mode 100644 index 00000000..a0792ec1 --- /dev/null +++ b/deegree-workspaces/Hydrography/services/download_HY.xml @@ -0,0 +1,36 @@ + + + + 2.0.0 + + + fdsInspireHY + + EPSG:28992 + EPSG:4326 + EPSG:4258 + EPSG:3035 + EPSG:3034 + EPSG:2583 + EPSG:25831 + EPSG:25832 + urn:ogc:def:crs:EPSG::28992 + urn:ogc:def:crs:EPSG::4326 + urn:ogc:def:crs:EPSG::4258 + urn:ogc:def:crs:EPSG::3035 + urn:ogc:def:crs:EPSG::3034 + urn:ogc:def:crs:EPSG::25830 + urn:ogc:def:crs:EPSG::25831 + urn:ogc:def:crs:EPSG::25832 + + -1 + + + application/gml+xml; version=3.2 + text/xml; subtype=gml/3.2.1 + + true + + + + diff --git a/deegree-workspaces/Hydrography/services/download_HY_metadata.xml b/deegree-workspaces/Hydrography/services/download_HY_metadata.xml new file mode 100644 index 00000000..b20bad50 --- /dev/null +++ b/deegree-workspaces/Hydrography/services/download_HY_metadata.xml @@ -0,0 +1,50 @@ + + + cds-inspire + + + + + + To be replaced by the DatabaseMetadataProvider + application/vnd.iso.19139+xml + + + + dut + + + + dut + + + + + + + + + + To be replaced by the DatabaseMetadataProvider + application/vnd.iso.19139+xml + + + + dut + + + + dut + + + + + + diff --git a/deegree-workspaces/Hydrography/services/wfs_HY_NL.xml b/deegree-workspaces/Hydrography/services/wfs_HY_NL.xml new file mode 100644 index 00000000..2b617505 --- /dev/null +++ b/deegree-workspaces/Hydrography/services/wfs_HY_NL.xml @@ -0,0 +1,38 @@ + + + + + 1.0.0 + 1.1.0 + 2.0.0 + + fdsHY + + + false + + + true + + + EPSG:28992 + EPSG:4326 + EPSG:4258 + EPSG:3035 + EPSG:3034 + EPSG:2583 + EPSG:25831 + EPSG:25832 + urn:ogc:def:crs:EPSG::28992 + urn:ogc:def:crs:EPSG::4326 + urn:ogc:def:crs:EPSG::4258 + urn:ogc:def:crs:EPSG::3035 + urn:ogc:def:crs:EPSG::3034 + urn:ogc:def:crs:EPSG::25830 + urn:ogc:def:crs:EPSG::25831 + urn:ogc:def:crs:EPSG::25832 + + + + diff --git a/deegree-workspaces/Hydrography/services/wfs_HY_NL_metadata.xml b/deegree-workspaces/Hydrography/services/wfs_HY_NL_metadata.xml new file mode 100644 index 00000000..b20bad50 --- /dev/null +++ b/deegree-workspaces/Hydrography/services/wfs_HY_NL_metadata.xml @@ -0,0 +1,50 @@ + + + cds-inspire + + + + + + To be replaced by the DatabaseMetadataProvider + application/vnd.iso.19139+xml + + + + dut + + + + dut + + + + + + + + + + To be replaced by the DatabaseMetadataProvider + application/vnd.iso.19139+xml + + + + dut + + + + dut + + + + + + diff --git a/deegree-workspaces/Hydrography/spring/cds-inspire.xml b/deegree-workspaces/Hydrography/spring/cds-inspire.xml new file mode 100644 index 00000000..690c72e2 --- /dev/null +++ b/deegree-workspaces/Hydrography/spring/cds-inspire.xml @@ -0,0 +1,3 @@ + + nl.ipo.cds.deegree.Config + diff --git a/pom.xml b/pom.xml index 73a0ccaa..d9cb6cd4 100644 --- a/pom.xml +++ b/pom.xml @@ -579,12 +579,14 @@ theme-areamanagement theme-exposedelements theme-habitat + theme-hydronode theme-hazardarea theme-productionfacility theme-productioninstallation theme-productioninstallationpart theme-protectedsites theme-riskzone + theme-watercourselink validation - \ No newline at end of file + diff --git a/theme-hydronode/pom.xml b/theme-hydronode/pom.xml new file mode 100644 index 00000000..218a3242 --- /dev/null +++ b/theme-hydronode/pom.xml @@ -0,0 +1,42 @@ + + 4.0.0 + + nl.ipo.cds + cds-parent + 2.2-SNAPSHOT + + theme-hydronode + CDS - Theme HydroNode + + + + maven-assembly-plugin + + + + single + + package + + + + true + + src/main/assembly/assembly-sql.xml + + + + + + + + nl.ipo.cds + etl-proces + + + nl.ipo.cds + etl-test + test + + + diff --git a/theme-hydronode/src/main/assembly/assembly-sql.xml b/theme-hydronode/src/main/assembly/assembly-sql.xml new file mode 100644 index 00000000..922dd489 --- /dev/null +++ b/theme-hydronode/src/main/assembly/assembly-sql.xml @@ -0,0 +1,18 @@ + + + sql + + zip + + false + + + + src/main/sql + sql + + **/*.* + + + + \ No newline at end of file diff --git a/theme-hydronode/src/main/feeds/datasettypecodes.xml b/theme-hydronode/src/main/feeds/datasettypecodes.xml new file mode 100644 index 00000000..91f7cb96 --- /dev/null +++ b/theme-hydronode/src/main/feeds/datasettypecodes.xml @@ -0,0 +1,13 @@ + + + + http://www.inspire-provincies.nl/codeList/DatasetTypeCode/HydroNode + DatasetTypeCode HydroNode + + + http://www.inspire-provincies.nl/codeList/DatasetTypeCode/HydroNode/hydronodesnl + HydroNodesNL + + + + diff --git a/theme-hydronode/src/main/java/nl/ipo/cds/etl/theme/hydronode/Context.java b/theme-hydronode/src/main/java/nl/ipo/cds/etl/theme/hydronode/Context.java new file mode 100644 index 00000000..e7ed2acc --- /dev/null +++ b/theme-hydronode/src/main/java/nl/ipo/cds/etl/theme/hydronode/Context.java @@ -0,0 +1,15 @@ +package nl.ipo.cds.etl.theme.hydronode; + +import nl.ipo.cds.validation.DefaultValidatorContext; +import nl.ipo.cds.validation.ValidationReporter; +import nl.ipo.cds.validation.gml.codelists.CodeListFactory; + +public class Context extends DefaultValidatorContext { + + public Context ( + final CodeListFactory codeListFactory, + final ValidationReporter reporter) { + super (codeListFactory, reporter); + } + +} diff --git a/theme-hydronode/src/main/java/nl/ipo/cds/etl/theme/hydronode/HydroNode.java b/theme-hydronode/src/main/java/nl/ipo/cds/etl/theme/hydronode/HydroNode.java new file mode 100644 index 00000000..0349f9fb --- /dev/null +++ b/theme-hydronode/src/main/java/nl/ipo/cds/etl/theme/hydronode/HydroNode.java @@ -0,0 +1,84 @@ +package nl.ipo.cds.etl.theme.hydronode; + +import nl.ipo.cds.etl.PersistableFeature; +import nl.ipo.cds.etl.db.annotation.Column; +import nl.ipo.cds.etl.db.annotation.Table; +import nl.ipo.cds.etl.theme.annotation.CodeSpace; +import nl.ipo.cds.etl.theme.annotation.MappableAttribute; + +import org.deegree.commons.tom.ows.CodeType; +import org.deegree.geometry.Geometry; + +@Table(name = "hydro_node", schema = "bron") +public class HydroNode extends PersistableFeature { + + @Column(name = "inspire_id_dataset_code") + private CodeType inspireIdDatasetCode; + + @Column(name = "inspire_id_local_id") + private String inspireIdLocalId; + + @Column(name = "geometry") + private Geometry geometry; + + @Column(name = "name") + private String name; + + @Column(name = "category") + private CodeType category; + + @MappableAttribute + @CodeSpace("http://www.inspire-provincies.nl/codeList/DatasetTypeCode/HydroNode") + public CodeType getInspireIdDatasetCode() { + return inspireIdDatasetCode; + } + + @MappableAttribute + @CodeSpace("http://www.inspire-provincies.nl/codeList/DatasetTypeCode/HydroNode") + public void setInspireIdDatasetCode(CodeType inspireIdDatasetCode) { + this.inspireIdDatasetCode = inspireIdDatasetCode; + } + + @MappableAttribute + public String getInspireIdLocalId() { + return inspireIdLocalId; + } + + @MappableAttribute + public void setInspireIdLocalId(String inspireIdLocalId) { + this.inspireIdLocalId = inspireIdLocalId; + } + + @MappableAttribute + public Geometry getGeometry() { + return geometry; + } + + @MappableAttribute + public void setGeometry(Geometry geometry) { + this.geometry = geometry; + } + + @MappableAttribute + public String getName() { + return name; + } + + @MappableAttribute + public void setName(String name) { + this.name = name; + } + + @MappableAttribute + @CodeSpace("http://inspire.ec.europa.eu/codeList/HydroNodeCategoryValue") + public CodeType getCategory() { + return category; + } + + @MappableAttribute + @CodeSpace("http://inspire.ec.europa.eu/codeList/HydroNodeCategoryValue") + public void setCategory(CodeType category) { + this.category = category; + } + +} diff --git a/theme-hydronode/src/main/java/nl/ipo/cds/etl/theme/hydronode/HydroNodeValidator.java b/theme-hydronode/src/main/java/nl/ipo/cds/etl/theme/hydronode/HydroNodeValidator.java new file mode 100644 index 00000000..1b375117 --- /dev/null +++ b/theme-hydronode/src/main/java/nl/ipo/cds/etl/theme/hydronode/HydroNodeValidator.java @@ -0,0 +1,111 @@ +package nl.ipo.cds.etl.theme.hydronode; + +import static nl.ipo.cds.etl.theme.hydronode.Message.ATTRIBUTE_CODE_CODESPACE_INVALID; +import static nl.ipo.cds.etl.theme.hydronode.Message.ATTRIBUTE_EMPTY; +import static nl.ipo.cds.etl.theme.hydronode.Message.ATTRIBUTE_NULL; +import static nl.ipo.cds.etl.theme.hydronode.Message.GEOMETRY_SRS_NOT_RD; +import static nl.ipo.cds.etl.theme.hydronode.Message.GEOMETRY_SRS_NULL; + +import java.util.Map; + +import nl.ipo.cds.domain.EtlJob; +import nl.ipo.cds.etl.AbstractValidator; +import nl.ipo.cds.validation.AttributeExpression; +import nl.ipo.cds.validation.ValidationReporter; +import nl.ipo.cds.validation.Validator; +import nl.ipo.cds.validation.constants.Constant; +import nl.ipo.cds.validation.execute.CompilerException; +import nl.ipo.cds.validation.geometry.GeometryExpression; +import nl.ipo.cds.validation.gml.CodeExpression; +import nl.ipo.cds.validation.gml.codelists.CodeListFactory; + +import org.deegree.geometry.Geometry; + +public class HydroNodeValidator extends + AbstractValidator { + + private final CodeExpression inspireIdDatasetCode = code("inspireIdDatasetCode"); + + private final AttributeExpression inspireIdLocalId = stringAttr("inspireIdLocalId"); + + private final GeometryExpression geometry = geometry("geometry"); + + private final Constant inspireIdDatasetCodeSpace = constant("http://www.inspire-provincies.nl/codeList/DatasetTypeCode/HydroNode"); + + private final AttributeExpression name = stringAttr ("name"); + + private final CodeExpression category = code ("category"); + + private final Constant categoryCodeSpace = constant ("http://inspire.ec.europa.eu/codeList/HydroNodeCategoryValue"); + + public HydroNodeValidator(final Map validatorMessages) + throws CompilerException { + super(Context.class, HydroNode.class, validatorMessages); + compile(); + } + + @Override + public Context beforeJob(final EtlJob job, + final CodeListFactory codeListFactory, + final ValidationReporter reporter) { + return new Context(codeListFactory, reporter); + } + + public Validator getInspireIdDatasetCodeValidator () { + return validate ( + and( + validate (not (inspireIdDatasetCode.isNull ())).message (ATTRIBUTE_NULL, constant (inspireIdDatasetCode.name)), + validate (not (isBlank (inspireIdDatasetCode.code()))).message (ATTRIBUTE_EMPTY, constant (inspireIdDatasetCode.name)), + validate (inspireIdDatasetCode.hasCodeSpace (inspireIdDatasetCodeSpace)).message (ATTRIBUTE_CODE_CODESPACE_INVALID, inspireIdDatasetCode.codeSpace(), constant(inspireIdDatasetCode.name), inspireIdDatasetCodeSpace) + ).shortCircuit() + ); + } + + public Validator getInspireIdLocalIdValidator () { + return validate ( + and( + validate (not (inspireIdLocalId.isNull ())).message (ATTRIBUTE_NULL, constant(inspireIdLocalId.name)), + validate (not (isBlank (inspireIdLocalId))).message (ATTRIBUTE_EMPTY, constant(inspireIdLocalId.name)) + ).shortCircuit() + ); + } + + public Validator getGeometryValidator () { + return validate ( + and ( + // The following validations short-circuit, there must be a non-null and non-empty, non-point geometry: + validate (not (geometry.isNull ())).message (ATTRIBUTE_NULL, constant(geometry.name)), + // SRS validations: + and ( + validate (geometry.hasSrs ()).message (GEOMETRY_SRS_NULL), + validate (geometry.isSrs (constant ("28992"))).message (GEOMETRY_SRS_NOT_RD, geometry.srsName ()) + ).shortCircuit() + ).shortCircuit () + ); + } + + public Validator getNameValidator () { + return validate ( + and( + validate (not (name.isNull ())).message (ATTRIBUTE_NULL, constant(name.name)), + validate (not (isBlank (name))).message (ATTRIBUTE_EMPTY, constant(name.name)) + ).shortCircuit() + ); + } + + public Validator getCategoryValidator () { + return validate ( + ifExp ( + category.isNull (), + constant(true), + and( + validate (category.hasCodeSpace (categoryCodeSpace)).message (ATTRIBUTE_CODE_CODESPACE_INVALID, category.codeSpace(), constant(category.name), categoryCodeSpace), + validate (not (isBlank (category.code()))).message (ATTRIBUTE_EMPTY, constant(category.name)) + // must be deactivated as long as codelist http://inspire.ec.europa.eu/codeList/ProductCPAValue is empty +// validate (functionInput.isValid ()).message (ATTRIBUTE_CODE_INVALID, functionInput.code(), constant(functionInput.name), functionInputCodeSpace) + ).shortCircuit() + ) + ); + } + +} diff --git a/theme-hydronode/src/main/java/nl/ipo/cds/etl/theme/hydronode/Message.java b/theme-hydronode/src/main/java/nl/ipo/cds/etl/theme/hydronode/Message.java new file mode 100644 index 00000000..dbbb5eb8 --- /dev/null +++ b/theme-hydronode/src/main/java/nl/ipo/cds/etl/theme/hydronode/Message.java @@ -0,0 +1,114 @@ +package nl.ipo.cds.etl.theme.hydronode; + +import java.util.ArrayList; +import java.util.List; + +import nl.idgis.commons.jobexecutor.JobLogger.LogLevel; +import nl.ipo.cds.etl.ValidatorMessageKey; +import nl.ipo.cds.validation.AttributeExpression; +import nl.ipo.cds.validation.Expression; + +public enum Message implements ValidatorMessageKey { + + ATTRIBUTE_NULL, + ATTRIBUTE_EMPTY, + ATTRIBUTE_NOT_URL, + ATTRIBUTE_VALUE_NEGATIVE, + ATTRIBUTE_VALUE_TOO_LOW, + ATTRIBUTE_VALUE_TOO_HIGH, + ATTRIBUTE_CODE_CODESPACE_INVALID, + ATTRIBUTE_CODE_INVALID, + ATTRIBUTE_GROUP_INCONSISTENT, + + GEOMETRY_EMPTY_MULTIGEOMETRY, + GEOMETRY_ONLY_POINT_OR_MULTIPOINT, + GEOMETRY_ONLY_CURVE_OR_MULTICURVE, + GEOMETRY_ONLY_SURFACE_OR_MULTISURFACE, + GEOMETRY_POINT_NOT_ALLOWED, + GEOMETRY_POINT_DUPLICATION(Integer.MAX_VALUE, true), + GEOMETRY_EXTERIOR_RING_CW(LogLevel.WARNING), + GEOMETRY_INTERIOR_RING_CCW(LogLevel.WARNING), + GEOMETRY_DISCONTINUITY(Integer.MAX_VALUE, true), + GEOMETRY_SELF_INTERSECTION(Integer.MAX_VALUE, true), + GEOMETRY_RING_NOT_CLOSED(Integer.MAX_VALUE, true), + GEOMETRY_RING_SELF_INTERSECTION(Integer.MAX_VALUE, true), + GEOMETRY_INTERIOR_RINGS_TOUCH(Integer.MAX_VALUE, true), + GEOMETRY_INTERIOR_RINGS_INTERSECT(Integer.MAX_VALUE, true), + GEOMETRY_INTERIOR_RINGS_WITHIN(Integer.MAX_VALUE, true), + GEOMETRY_INTERIOR_RING_TOUCHES_EXTERIOR(Integer.MAX_VALUE, true), + GEOMETRY_INTERIOR_RING_INTERSECTS_EXTERIOR(Integer.MAX_VALUE, true), + GEOMETRY_INTERIOR_RING_OUTSIDE_EXTERIOR(Integer.MAX_VALUE, true), + GEOMETRY_INTERIOR_DISCONNECTED(Integer.MAX_VALUE, true), + GEOMETRY_SRS_NULL, + GEOMETRY_SRS_NOT_RD("EPSG:28992"), + + HAS_MORE_ERRORS(LogLevel.WARNING) + ; + + private final String[] params; + + private final LogLevel logLevel; + + private final int maxMessageLog; + + private final boolean addToShapeFile; + + private Message(LogLevel logLevel, Integer maxMessageLog, boolean addToShapeFile, String... params) { + this.maxMessageLog = maxMessageLog == null ? 10 : maxMessageLog; + this.logLevel = logLevel == null ? LogLevel.ERROR : logLevel; + this.addToShapeFile = addToShapeFile; + this.params = params; + } + + private Message(LogLevel logLevel, Integer maxMessageLog, String... params) { + this(logLevel, maxMessageLog, false, params); + } + + private Message(Integer maxMessageLog, boolean addToShapeFile, String... params) { + this(null, maxMessageLog, addToShapeFile, params); + } + + private Message(LogLevel logLevel) { + this(logLevel, null, false); + } + + private Message(String... params) { + this(null, null, false, params); + } + + @Override + public boolean isBlocking() { + return getLogLevel ().equals (LogLevel.ERROR); + } + + @Override + public List> getMessageParameters () { + final List> params = new ArrayList<> (); + // why twice??? + params.add (new AttributeExpression ("id", String.class)); + params.add (new AttributeExpression ("id", String.class)); + params.add (new AttributeExpression ("inspireIdLocalId", String.class)); + return params; + } + + @Override + public int getMaxMessageLog() { + return maxMessageLog; + } + + @Override + public boolean isAddToShapeFile () { + return addToShapeFile; + } + + @Override + public LogLevel getLogLevel() { + return logLevel; + } + + @Override + public Message getMaxMessageKey() { + return HAS_MORE_ERRORS; + } + +} diff --git a/theme-hydronode/src/main/java/nl/ipo/cds/etl/theme/hydronode/config/DatasetConfig.java b/theme-hydronode/src/main/java/nl/ipo/cds/etl/theme/hydronode/config/DatasetConfig.java new file mode 100644 index 00000000..186e58ee --- /dev/null +++ b/theme-hydronode/src/main/java/nl/ipo/cds/etl/theme/hydronode/config/DatasetConfig.java @@ -0,0 +1,60 @@ +package nl.ipo.cds.etl.theme.hydronode.config; + +import java.util.Properties; + +import javax.inject.Inject; +import javax.inject.Named; + +import nl.ipo.cds.attributemapping.operations.discover.OperationDiscoverer; +import nl.ipo.cds.etl.Transformer; +import nl.ipo.cds.etl.theme.DefaultThemeConfig; +import nl.ipo.cds.etl.theme.ThemeConfig; +import nl.ipo.cds.etl.theme.hydronode.HydroNode; +import nl.ipo.cds.etl.theme.hydronode.HydroNodeValidator; +import nl.ipo.cds.etl.util.ScriptExecutor; +import nl.ipo.cds.etl.util.ScriptTransformer; +import nl.ipo.cds.validation.execute.CompilerException; + +import org.springframework.beans.factory.config.PropertiesFactoryBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.io.ClassPathResource; + +@Configuration (value = "hydroNode.DatasetConfig") +public class DatasetConfig { + + private static final String THEME_NAME = "HydroNode"; + + @Bean + @Inject + public ThemeConfig hydroNodeThemeConfig ( + final HydroNodeValidator validator, + final OperationDiscoverer operationDiscoverer) { + return new DefaultThemeConfig (THEME_NAME, HydroNode.class, validator, operationDiscoverer); + } + + @Bean + public Transformer hydroNodeTransformer(final ScriptExecutor scriptExecutor) { + return new ScriptTransformer(scriptExecutor, new ClassPathResource ("nl/ipo/cds/etl/theme/hydronode/transform-bron-to-inspire.sql"), THEME_NAME); + } + + @Configuration (value = "hydroNode.Validators") + public static class Validators { + @Bean + @Inject + public HydroNodeValidator hydroNodeValidator ( + final @Named ("hydroNodeValidationMessages") Properties validatorMessages) throws CompilerException { + return new HydroNodeValidator (validatorMessages); + } + } + + @Configuration (value = "hydroNode.Messages") + public static class Messages { + @Bean + public PropertiesFactoryBean hydroNodeValidationMessages () { + final PropertiesFactoryBean properties = new PropertiesFactoryBean (); + properties.setLocation (new ClassPathResource ("nl/ipo/cds/etl/theme/hydronode/validator.messages")); + return properties; + } + } +} diff --git a/theme-hydronode/src/main/java/nl/ipo/cds/etl/theme/hydronode/config/Package.java b/theme-hydronode/src/main/java/nl/ipo/cds/etl/theme/hydronode/config/Package.java new file mode 100644 index 00000000..e6af9ab7 --- /dev/null +++ b/theme-hydronode/src/main/java/nl/ipo/cds/etl/theme/hydronode/config/Package.java @@ -0,0 +1,4 @@ +package nl.ipo.cds.etl.theme.hydronode.config; + +public interface Package { +} diff --git a/theme-hydronode/src/main/resources/nl/ipo/cds/etl/theme/hydronode/messages.properties b/theme-hydronode/src/main/resources/nl/ipo/cds/etl/theme/hydronode/messages.properties new file mode 100644 index 00000000..139597f9 --- /dev/null +++ b/theme-hydronode/src/main/resources/nl/ipo/cds/etl/theme/hydronode/messages.properties @@ -0,0 +1,2 @@ + + diff --git a/theme-hydronode/src/main/resources/nl/ipo/cds/etl/theme/hydronode/transform-bron-to-inspire.sql b/theme-hydronode/src/main/resources/nl/ipo/cds/etl/theme/hydronode/transform-bron-to-inspire.sql new file mode 100644 index 00000000..dcc96ca7 --- /dev/null +++ b/theme-hydronode/src/main/resources/nl/ipo/cds/etl/theme/hydronode/transform-bron-to-inspire.sql @@ -0,0 +1 @@ +-- Nothing so far \ No newline at end of file diff --git a/theme-hydronode/src/main/resources/nl/ipo/cds/etl/theme/hydronode/validator.messages b/theme-hydronode/src/main/resources/nl/ipo/cds/etl/theme/hydronode/validator.messages new file mode 100644 index 00000000..e663decf --- /dev/null +++ b/theme-hydronode/src/main/resources/nl/ipo/cds/etl/theme/hydronode/validator.messages @@ -0,0 +1,57 @@ +FEATURE=feature: ${0}, inspireIdLocalId: ${1} + +ATTRIBUTE_NULL=Het attribuut "${2}" ontbreekt, ${FEATURE} +ATTRIBUTE_EMPTY=Het attribuut "${2}" is leeg, ${FEATURE} +ATTRIBUTE_NOT_URL=De waarde "${2}" van het attribuut "${3}" is geen valide URL, ${FEATURE} +ATTRIBUTE_VALUE_NEGATIVE=De waarde "${2}" van het attribuut "${3}" is negatief, ${FEATURE} +ATTRIBUTE_CODE_CODESPACE_INVALID=De 'codeSpace' "${2}" van attribuut "${3}" is niet valide (verwacht: "${4}"), ${FEATURE} +ATTRIBUTE_CODE_INVALID=De code "${2}" van het attribuut "${3}" is niet valide met betrekking tot de code-lijst "${4}", ${FEATURE} +ATTRIBUTE_VALUE_TOO_LOW=De waarde "${2}" van het attribuut "${3}" is te laag (limiet "${4}"), ${FEATURE} +ATTRIBUTE_VALUE_TOO_HIGH=De waarde "${2}" van het attribuut "${3}" is te hoog (limiet "${4}"), ${FEATURE} +ATTRIBUTE_GROUP_INCONSISTENT=Het attribuut "${2}" kan niet worden weggelaten, als er één of meerdere andere attributen uit de groep (zoals "${3}") aanwezig zijn, ${FEATURE} + +GEOMETRY_NULL_BASE=geometrie ontbreekt +GEOMETRY_EMPTY_MULTIGEOMETRY_BASE=multi geometrie is leeg +GEOMETRY_ONLY_POINT_OR_MULTIPOINT_BASE=geometrie has wrong type: must be a point (or a multi point) +GEOMETRY_ONLY_CURVE_OR_MULTICURVE_BASE=geometrie has wrong type: must be a linestring (or a multi linestring) +GEOMETRY_ONLY_SURFACE_OR_MULTISURFACE_BASE=geometrie has wrong type: must be a polygon (or a multi polygon) +GEOMETRY_POINT_DUPLICATION_BASE=geometrie bevat duplicaat punten, locatie: ${2} +GEOMETRY_EXTERIOR_RING_CW_BASE=geometrie bevat een buitenring met CW oriëntatie +GEOMETRY_INTERIOR_RING_CCW_BASE=geometrie bevat een binnenring met CCW oriëntatie +GEOMETRY_DISCONTINUITY_BASE=geometrie bevat lijnelementen die niet aansluiten +GEOMETRY_SELF_INTERSECTION_BASE=geometrie bevat een lijn die zichzelf snijdt, locatie: ${2} +GEOMETRY_RING_NOT_CLOSED_BASE=geometrie bevat een niet gesloten ring +GEOMETRY_RING_SELF_INTERSECTION_BASE=geometrie bevat een ring die zichzelf snijdt, locatie: ${2} +GEOMETRY_INTERIOR_RINGS_TOUCH_BASE=geometrie bevat een binnenring die zichzelf raakt, locatie: ${2} +GEOMETRY_INTERIOR_RINGS_INTERSECT_BASE=geometrie bevat een binnenring die zichzelf snijdt, locatie: ${2} +GEOMETRY_INTERIOR_RINGS_WITHIN_BASE=geometrie bevat een binnenring binnen een andere binnenring +GEOMETRY_INTERIOR_RING_TOUCHES_EXTERIOR_BASE=geometrie bevat een binnenring die een buitenring raakt, locatie: ${2} +GEOMETRY_INTERIOR_RING_INTERSECTS_EXTERIOR_BASE=geometrie bevat een binnenring die een buitenring snijdt, locatie: ${2} +GEOMETRY_INTERIOR_RING_OUTSIDE_EXTERIOR_BASE=geometrie bevat een binnenring die niet binnen een buitenring ligt +GEOMETRY_INTERIOR_DISCONNECTED_BASE=geometrie bevat een verbroken polygoon +GEOMETRY_SRS_NULL_BASE=Het attribuut "srsName" ontbreekt bij het geometrie-element +GEOMETRY_SRS_NOT_RD_BASE=Het attribuut "srsName" bij element "geometry" heeft een andere waarde dan "EPSG:28992" (RD_New) + +GEOMETRY_NULL=${GEOMETRY_NULL_BASE}, ${FEATURE} +GEOMETRY_EMPTY_MULTIGEOMETRY=${GEOMETRY_EMPTY_MULTIGEOMETRY_BASE}, ${FEATURE} +GEOMETRY_ONLY_POINT_OR_MULTIPOINT=${GEOMETRY_ONLY_POINT_OR_MULTIPOINT_BASE}, ${FEATURE} +GEOMETRY_ONLY_CURVE_OR_MULTICURVE=${GEOMETRY_ONLY_CURVE_OR_MULTICURVE_BASE}, ${FEATURE} +GEOMETRY_ONLY_SURFACE_OR_MULTISURFACE=${GEOMETRY_ONLY_SURFACE_OR_MULTISURFACE_BASE}, ${FEATURE} +GEOMETRY_POINT_DUPLICATION=${GEOMETRY_POINT_DUPLICATION_BASE}, ${FEATURE} +GEOMETRY_EXTERIOR_RING_CW=${GEOMETRY_EXTERIOR_RING_CW_BASE}, ${FEATURE} +GEOMETRY_INTERIOR_RING_CCW=${GEOMETRY_INTERIOR_RING_CCW_BASE}, ${FEATURE} +GEOMETRY_DISCONTINUITY=${GEOMETRY_DISCONTINUITY_BASE}, ${FEATURE} +GEOMETRY_SELF_INTERSECTION=${GEOMETRY_SELF_INTERSECTION_BASE}, ${FEATURE} +GEOMETRY_RING_NOT_CLOSED=${GEOMETRY_RING_NOT_CLOSED_BASE}, ${FEATURE} +GEOMETRY_RING_SELF_INTERSECTION=${GEOMETRY_RING_SELF_INTERSECTION_BASE}, ${FEATURE} +GEOMETRY_INTERIOR_RINGS_TOUCH=${GEOMETRY_INTERIOR_RINGS_TOUCH_BASE}, ${FEATURE} +GEOMETRY_INTERIOR_RINGS_INTERSECT=${GEOMETRY_INTERIOR_RINGS_INTERSECT_BASE}, ${FEATURE} +GEOMETRY_INTERIOR_RINGS_WITHIN=${GEOMETRY_INTERIOR_RINGS_WITHIN_BASE}, ${FEATURE} +GEOMETRY_INTERIOR_RING_TOUCHES_EXTERIOR=${GEOMETRY_INTERIOR_RING_TOUCHES_EXTERIOR_BASE}, ${FEATURE} +GEOMETRY_INTERIOR_RING_INTERSECTS_EXTERIOR=${GEOMETRY_INTERIOR_RING_INTERSECTS_EXTERIOR_BASE}, ${FEATURE} +GEOMETRY_INTERIOR_RING_OUTSIDE_EXTERIOR=${GEOMETRY_INTERIOR_RING_OUTSIDE_EXTERIOR_BASE}, ${FEATURE} +GEOMETRY_INTERIOR_DISCONNECTED=${GEOMETRY_INTERIOR_DISCONNECTED_BASE}, ${FEATURE} +GEOMETRY_SRS_NULL=${GEOMETRY_SRS_NULL_BASE}, ${FEATURE} +GEOMETRY_SRS_NOT_RD=${GEOMETRY_SRS_NOT_RD_BASE} (gevonden waarde: ${1}), ${FEATURE} + +HAS_MORE_ERRORS=Er zijn meer meldingen die niet werden gerapporteerd diff --git a/theme-hydronode/src/main/sql/create-bron-schema-hydronode.sql b/theme-hydronode/src/main/sql/create-bron-schema-hydronode.sql new file mode 100644 index 00000000..33cf7cb0 --- /dev/null +++ b/theme-hydronode/src/main/sql/create-bron-schema-hydronode.sql @@ -0,0 +1,22 @@ + +create table bron.hydro_node ( + id serial, + job_id bigint, + gfid text, + + inspire_id_dataset_code text not null, + inspire_id_local_id text not null, + name text not null, + category text not null, + + primary key (id), + constraint fk_job_id foreign key (job_id) references manager.job (id) +); +SELECT AddGeometryColumn ('bron','hydro_node','geometry',28992,'GEOMETRY',2); +ALTER TABLE bron.hydro_node ALTER COLUMN "geometry" SET NOT NULL; + +CREATE INDEX idx_bron_hydro_node_geometry ON bron.hydro_node USING GIST (geometry); + +GRANT SELECT, INSERT, UPDATE, DELETE, TRIGGER ON bron.hydro_node TO inspire; +GRANT USAGE, SELECT, UPDATE ON SEQUENCE bron.hydro_node_id_seq TO inspire; +---------------------------------- diff --git a/theme-hydronode/src/main/sql/populate-manager-schema-hydronode.sql b/theme-hydronode/src/main/sql/populate-manager-schema-hydronode.sql new file mode 100644 index 00000000..8decfd98 --- /dev/null +++ b/theme-hydronode/src/main/sql/populate-manager-schema-hydronode.sql @@ -0,0 +1,12 @@ +-- +-- HydroNode +-- +-- Names must match constants defined corresponding ThemeConfig +insert into manager.thema (id, naam) values ((select nextval('manager.hibernate_sequence')), 'HydroNode'); + +insert into manager.datasettype (id, naam, thema_id) values ((select nextval('manager.hibernate_sequence')), 'HydroNodesNL', (select id from manager.thema t where t.naam = 'HydroNode')); + +insert into manager.bronhouder (id, code, contact_naam, contact_adres, contact_postcode, contact_plaats, naam, contact_emailadres, contact_telefoonnummer, common_name) select nextval('manager.hibernate_sequence'), 'elf', 'ELF Project', '', '', '', 'ELF Project', 'inspire@idgis.nl', '', 'elfproject' where not exists (select * from manager.bronhouder where code = 'elf'); + +insert into manager.themabronhouderauthorization (thema_id, bronhouder_id) values ( (select id from manager.thema where naam = 'HydroNode'), (select id from manager.bronhouder where code = 'elf') ); +-- diff --git a/theme-hydronode/src/main/sql/populate-metadata-schema-hydrography.sql b/theme-hydronode/src/main/sql/populate-metadata-schema-hydrography.sql new file mode 100644 index 00000000..8490cd73 --- /dev/null +++ b/theme-hydronode/src/main/sql/populate-metadata-schema-hydrography.sql @@ -0,0 +1,83 @@ + +-- +-- metadata Hydrography +-- + +-- One serviceprovider for all services of this INSPIRE theme +DELETE FROM metadata.si_keyword where serviceidentification_id IN (select serviceidentification_id from metadata.service where name='view_HY' OR name='download_HY'); +DELETE FROM metadata.si_accessconstraint where serviceidentification_id IN (select serviceidentification_id from metadata.service where name='view_HY' OR name='download_HY'); +DELETE FROM metadata.service_datasetmetadata where service_id IN (select id from metadata.service where name='view_HY' OR name='download_HY'); +DELETE FROM metadata.service where name='view_HY' OR name='download_HY'; +DELETE FROM metadata.serviceidentification where servicepath like '%view_HY%' OR servicepath like '%download_HY%'; +DELETE FROM metadata.extendedcapabilities where metadataurl like '%view_HY%' OR metadataurl like '%download_HY%'; + +DELETE FROM metadata.si_keyword where serviceidentification_id IN (select serviceidentification_id from metadata.service where name='wms_HY_NL' OR name='wfs_HY_NL'); +DELETE FROM metadata.si_accessconstraint where serviceidentification_id IN (select serviceidentification_id from metadata.service where name='wms_HY_NL' OR name='wfs_HY_NL'); +DELETE FROM metadata.service_datasetmetadata where service_id IN (select id from metadata.service where name='wms_HY_NL' OR name='wfs_HY_NL'); +DELETE FROM metadata.service where name='wms_HY_NL' OR name='wfs_HY_NL'; +DELETE FROM metadata.serviceidentification where servicepath like '%wms_HY_NL%' OR servicepath like '%wfs_HY_NL%'; +DELETE FROM metadata.extendedcapabilities where metadataurl like '%wms_HY_NL%' OR metadataurl like '%wfs_HY_NL%'; + +DELETE FROM metadata.sp_deliverypoint where serviceprovider_id IN (select id from metadata.serviceprovider where individualname like '%Hydrography%'); +DELETE FROM metadata.sp_emailaddress where serviceprovider_id IN (select id from metadata.serviceprovider where individualname like '%Hydrography%'); +DELETE FROM metadata.sp_faxnumber where serviceprovider_id IN (select id from metadata.serviceprovider where individualname like '%Hydrography%'); +DELETE FROM metadata.sp_phonenumber where serviceprovider_id IN (select id from metadata.serviceprovider where individualname like '%Hydrography%'); +DELETE FROM metadata.serviceprovider where individualname like '%Hydrography%'; + +INSERT INTO metadata.serviceprovider (id,administrativearea,city,contactinstructions,country,hoursofservice,individualname,onlineresource,organizationname,positionname,postalcode,providername,providersite,role) + VALUES ((select nextval('metadata.hibernate_sequence')), '', '', NULL, '', NULL, 'Functioneel beheerder, Hydrography', NULL, 'ELF Project', 'pointOfContact', '', NULL, NULL, NULL); + +-- INSPIRE View and Download service + +INSERT INTO metadata.extendedcapabilities (id,metadataurl) VALUES ((select nextval('metadata.hibernate_sequence')), 'view_HY'); +INSERT INTO metadata.extendedcapabilities (id,metadataurl) VALUES ((select nextval('metadata.hibernate_sequence')), 'download_HY'); + +INSERT INTO metadata.serviceidentification (id,abstract,fees,servicetype,servicepath,title) + VALUES ((select nextval('metadata.hibernate_sequence')), 'Deze View service heeft betrekking op Hydrography.', 'no conditions apply', 'WMS', 'Hydrography/services/view_HY', 'INSPIRE View service voor Hydrography'); +INSERT INTO metadata.serviceidentification (id,abstract,fees,servicetype,servicepath,title) + VALUES ((select nextval('metadata.hibernate_sequence')), 'Deze Download service heeft betrekking op Hydrography.', 'none', 'WFS', 'Hydrography/services/download_HY', 'INSPIRE Download service voor Hydrography'); + +INSERT INTO metadata.service (id,description,name,serviceidentification_id,serviceprovider_id, extendedcapabilities_id) VALUES ((select nextval('metadata.hibernate_sequence')), 'omschrijving view_HY', 'view_HY', (select id from metadata.serviceidentification where servicepath='Hydrography/services/view_HY'), (select id from metadata.serviceprovider where individualname like '%Hydrography%'), (select id from metadata.extendedcapabilities where metadataurl='view_HY')); +INSERT INTO metadata.service (id,description,name,serviceidentification_id,serviceprovider_id, extendedcapabilities_id) VALUES ((select nextval('metadata.hibernate_sequence')), 'omschrijving download_HY', 'download_HY', (select id from metadata.serviceidentification where servicepath='Hydrography/services/download_HY'), (select id from metadata.serviceprovider where individualname like '%Hydrography%'), (select id from metadata.extendedcapabilities where metadataurl='download_HY')); + +INSERT INTO metadata.service_datasetmetadata (service_id, name, namespace, url,"index") VALUES ((select id from metadata.service where name='view_HY'), 'HY.HydroNode', '', 'X', 0); +INSERT INTO metadata.service_datasetmetadata (service_id, name, namespace, url,"index") VALUES ((select id from metadata.service where name='view_HY'), 'HY.WaterCourseLink', '', 'X', 1); + +INSERT INTO metadata.si_accessconstraint (serviceidentification_id,accessconstraint,"index") VALUES ((select serviceidentification_id from metadata.service where name='view_HY'), 'anders', 0); + +INSERT INTO metadata.si_keyword (serviceidentification_id,codespace,"value","index" ) VALUES ((select serviceidentification_id from metadata.service where name='view_HY'), 'ISO', 'infoMapAccessService', 0); +INSERT INTO metadata.si_keyword (serviceidentification_id,codespace,"value","index" ) VALUES ((select serviceidentification_id from metadata.service where name='view_HY'), 'GEMET - INSPIRE themes, version 1.0', 'Hydrography', 1); +INSERT INTO metadata.si_keyword (serviceidentification_id,codespace,"value","index" ) VALUES ((select serviceidentification_id from metadata.service where name='download_HY'), 'ISO', 'infoFeatureAccessService', 0); +INSERT INTO metadata.si_keyword (serviceidentification_id,codespace,"value","index" ) VALUES ((select serviceidentification_id from metadata.service where name='download_HY'), 'GEMET - INSPIRE themes, version 1.0', 'Hydrography', 1); + +-- si-version is not filled + +INSERT INTO metadata.sp_deliverypoint (serviceprovider_id,deliverypoint,"index") VALUES ((select serviceprovider_id from metadata.service where name='view_HY'), '', 0); +INSERT INTO metadata.sp_emailaddress (serviceprovider_id, emailaddress,"index") VALUES ((select serviceprovider_id from metadata.service where name='view_HY'), 'inspire@idgis.nl', 0); +INSERT INTO metadata.sp_faxnumber (serviceprovider_id ,faxnumber,"index") VALUES ((select serviceprovider_id from metadata.service where name='view_HY'), '', 0); +INSERT INTO metadata.sp_phonenumber (serviceprovider_id,phonenumber,"index") VALUES ((select serviceprovider_id from metadata.service where name='view_HY'), '', 0); +-------------------------------- + +-- WMS & WFS with NL / flat structure + + +INSERT INTO metadata.extendedcapabilities (id,metadataurl) VALUES ((select nextval('metadata.hibernate_sequence')), 'wms_HY_NL'); +INSERT INTO metadata.extendedcapabilities (id,metadataurl) VALUES ((select nextval('metadata.hibernate_sequence')), 'wfs_HY_NL'); + +INSERT INTO metadata.serviceidentification (id,abstract,fees,servicetype,servicepath,title) + VALUES ((select nextval('metadata.hibernate_sequence')), 'Deze WMS service heeft betrekking op Hydrography.', 'no conditions apply', 'WMS', 'Hydrography/services/wms_HY_NL', 'WMS service voor Hydrography'); +INSERT INTO metadata.serviceidentification (id,abstract,fees,servicetype,servicepath,title) + VALUES ((select nextval('metadata.hibernate_sequence')), 'Deze WFS service heeft betrekking op Hydrography.', 'none', 'WFS', 'Hydrography/services/wfs_HY_NL', 'WFS service voor Hydrography'); + +INSERT INTO metadata.service (id,description,name,serviceidentification_id,serviceprovider_id, extendedcapabilities_id) VALUES ((select nextval('metadata.hibernate_sequence')), 'omschrijving wms_HY_NL', 'wms_HY_NL', (select id from metadata.serviceidentification where servicepath='Hydrography/services/wms_HY_NL'), (select id from metadata.serviceprovider where individualname like '%Hydrography%'), (select id from metadata.extendedcapabilities where metadataurl='wms_HY_NL')); +INSERT INTO metadata.service (id,description,name,serviceidentification_id,serviceprovider_id, extendedcapabilities_id) VALUES ((select nextval('metadata.hibernate_sequence')), 'omschrijving wfs_HY_NL', 'wfs_HY_NL', (select id from metadata.serviceidentification where servicepath='Hydrography/services/wfs_HY_NL'), (select id from metadata.serviceprovider where individualname like '%Hydrography%'), (select id from metadata.extendedcapabilities where metadataurl='wfs_HY_NL')); + +INSERT INTO metadata.service_datasetmetadata (service_id, name, namespace, url,"index") VALUES ((select id from metadata.service where name='wms_HY_NL'), 'HY.HydroNode_NL', '', 'X', 0); +INSERT INTO metadata.service_datasetmetadata (service_id, name, namespace, url,"index") VALUES ((select id from metadata.service where name='wms_HY_NL'), 'HY.WaterCourseLink_NL', '', 'X', 1); + +INSERT INTO metadata.si_accessconstraint (serviceidentification_id,accessconstraint,"index") VALUES ((select serviceidentification_id from metadata.service where name='wms_HY_NL'), 'anders', 0); + +INSERT INTO metadata.si_keyword (serviceidentification_id,codespace,"value","index" ) VALUES ((select serviceidentification_id from metadata.service where name='wms_HY_NL'), 'ISO', 'infoMapAccessService', 0); +INSERT INTO metadata.si_keyword (serviceidentification_id,codespace,"value","index" ) VALUES ((select serviceidentification_id from metadata.service where name='wms_HY_NL'), 'GEMET - INSPIRE themes, version 1.0', 'Hydrography', 1); +INSERT INTO metadata.si_keyword (serviceidentification_id,codespace,"value","index" ) VALUES ((select serviceidentification_id from metadata.service where name='wfs_HY_NL'), 'ISO', 'infoFeatureAccessService', 0); +INSERT INTO metadata.si_keyword (serviceidentification_id,codespace,"value","index" ) VALUES ((select serviceidentification_id from metadata.service where name='wfs_HY_NL'), 'GEMET - INSPIRE themes, version 1.0', 'Hydrography', 1); diff --git a/theme-hydronode/src/test/java/nl/ipo/cds/etl/theme/hydronode/HydroNodeValidatorTest.java b/theme-hydronode/src/test/java/nl/ipo/cds/etl/theme/hydronode/HydroNodeValidatorTest.java new file mode 100644 index 00000000..086f3b1e --- /dev/null +++ b/theme-hydronode/src/test/java/nl/ipo/cds/etl/theme/hydronode/HydroNodeValidatorTest.java @@ -0,0 +1,114 @@ +package nl.ipo.cds.etl.theme.hydronode; + +import static nl.ipo.cds.etl.theme.hydronode.Message.ATTRIBUTE_CODE_CODESPACE_INVALID; +import static nl.ipo.cds.etl.theme.hydronode.Message.ATTRIBUTE_CODE_INVALID; +import static nl.ipo.cds.etl.theme.hydronode.Message.ATTRIBUTE_EMPTY; +import static nl.ipo.cds.etl.theme.hydronode.Message.ATTRIBUTE_NULL; +import static nl.ipo.cds.etl.theme.hydronode.Message.GEOMETRY_SRS_NOT_RD; +import static nl.ipo.cds.etl.theme.hydronode.Message.GEOMETRY_SRS_NULL; + +import java.util.Collections; + +import nl.ipo.cds.etl.test.GeometryConstants; +import nl.ipo.cds.etl.test.ValidationRunner; + +import org.deegree.commons.tom.ows.CodeType; +import org.junit.Before; +import org.junit.Test; + +public class HydroNodeValidatorTest { + + private HydroNodeValidator validator; + private ValidationRunner runner; + private GeometryConstants geom; + + @Before + public void createValidator() throws Exception { + validator = new HydroNodeValidator(Collections.emptyMap()); + runner = new ValidationRunner<>(validator, HydroNode.class); + geom = new GeometryConstants("EPSG:28992"); + } + + private ValidationRunner.Runner run(final String validationName) { + return runner.validation(validationName); + } + + @Test + public void getInspireIdDatasetCodeValidator () throws Throwable { + + run ("inspireIdDatasetCode") + .with (null) + .assertOnlyKey (ATTRIBUTE_NULL); + + run ("inspireIdDatasetCode") + .with (new CodeType("")) + .assertOnlyKey (ATTRIBUTE_EMPTY); + + run ("inspireIdDatasetCode") + .with (new CodeType("bogus")) + .assertOnlyKey (ATTRIBUTE_CODE_CODESPACE_INVALID); + +// run ("inspireIdDatasetCode") +// .withCodeList ("http://www.inspire-provincies.nl/codeList/DatasetTypeCode/ProductionFacility", "lgrinr") +// .with (new CodeType("value1", "http://www.inspire-provincies.nl/codeList/DatasetTypeCode/ProductionFacility")) +// .assertOnlyKey (ATTRIBUTE_CODE_INVALID); +// +// run ("inspireIdDatasetCode") +// .withCodeList ("http://www.inspire-provincies.nl/codeList/DatasetTypeCode/ProductionFacility", "lgrinr") +// .with (new CodeType("lgrinr", "http://www.inspire-provincies.nl/codeList/DatasetTypeCode/ProductionFacility")) +// .assertNoMessages(); + } + + @Test + public void getInspireIdLocalIdValidator () throws Throwable { + + run ("inspireIdLocalId") + .with (null) + .assertOnlyKey (ATTRIBUTE_NULL); + + run ("inspireIdLocalId") + .with ("") + .assertOnlyKey (ATTRIBUTE_EMPTY); + + run ("inspireIdLocalId") + .with ("nl1000") + .assertNoMessages(); + } + + @Test + public void testGeometry () throws Exception { + + run ("geometry") + .with (null) + .assertOnlyKey (ATTRIBUTE_NULL); + + run ("geometry") + .with (geom.lineString (null)) + .assertOnlyKey (GEOMETRY_SRS_NULL); + + run ("geometry") + .with (geom.lineString (geom.getSrs ("EPSG:3857"))) + .assertOnlyKey (GEOMETRY_SRS_NOT_RD); + + run ("geometry") + .with (geom.point (1,2)) + .assertNoMessages (); + } + + @Test + public void getNameValidator () throws Throwable { + + run ("name") + .with (null) + .assertOnlyKey (ATTRIBUTE_NULL); + + run ("name") + .with ("") + .assertOnlyKey (ATTRIBUTE_EMPTY); + + run ("name") + .with ("nl1000") + .assertNoMessages(); + } + +} diff --git a/theme-hydronode/src/test/java/nl/ipo/cds/etl/theme/hydronode/ValidatorsValidTest.java b/theme-hydronode/src/test/java/nl/ipo/cds/etl/theme/hydronode/ValidatorsValidTest.java new file mode 100644 index 00000000..80205302 --- /dev/null +++ b/theme-hydronode/src/test/java/nl/ipo/cds/etl/theme/hydronode/ValidatorsValidTest.java @@ -0,0 +1,16 @@ +package nl.ipo.cds.etl.theme.hydronode; + +import java.util.Collections; + +import nl.ipo.cds.etl.theme.hydronode.HydroNodeValidator; + +import org.junit.Test; + +public class ValidatorsValidTest { + + @Test + public void testValidatorValid () throws Exception { + new HydroNodeValidator (Collections.emptyMap ()); + } + +} diff --git a/theme-watercourselink/pom.xml b/theme-watercourselink/pom.xml new file mode 100644 index 00000000..2d14c93d --- /dev/null +++ b/theme-watercourselink/pom.xml @@ -0,0 +1,42 @@ + + 4.0.0 + + nl.ipo.cds + cds-parent + 2.2-SNAPSHOT + + theme-watercourselink + CDS - Theme WatercourseLink + + + + maven-assembly-plugin + + + + single + + package + + + + true + + src/main/assembly/assembly-sql.xml + + + + + + + + nl.ipo.cds + etl-proces + + + nl.ipo.cds + etl-test + test + + + diff --git a/theme-watercourselink/src/main/assembly/assembly-sql.xml b/theme-watercourselink/src/main/assembly/assembly-sql.xml new file mode 100644 index 00000000..922dd489 --- /dev/null +++ b/theme-watercourselink/src/main/assembly/assembly-sql.xml @@ -0,0 +1,18 @@ + + + sql + + zip + + false + + + + src/main/sql + sql + + **/*.* + + + + \ No newline at end of file diff --git a/theme-watercourselink/src/main/feeds/datasettypecodes.xml b/theme-watercourselink/src/main/feeds/datasettypecodes.xml new file mode 100644 index 00000000..a4f6e599 --- /dev/null +++ b/theme-watercourselink/src/main/feeds/datasettypecodes.xml @@ -0,0 +1,33 @@ + + + + http://www.inspire-provincies.nl/codeList/DatasetTypeCode/ProductionFacility + DatasetTypeCode Production Facility + + + http://www.inspire-provincies.nl/codeList/DatasetTypeCode/ProductionFacility/lgrinr + LGR Inrichtingen + + + + http://www.inspire-provincies.nl/codeList/DatasetTypeCode/ProductionFacility/lgrins + LGR Installaties + + + + http://www.inspire-provincies.nl/codeList/DatasetTypeCode/ProductionFacility/lgrput + LGR Put + + + + http://www.inspire-provincies.nl/codeList/DatasetTypeCode/ProductionFacility/lgrlus + LGR Bodemlus + + + + http://www.inspire-provincies.nl/codeList/DatasetTypeCode/ProductionFacility/rkinr + Risicokaart Inrichtingen + + + + diff --git a/theme-watercourselink/src/main/java/nl/ipo/cds/etl/theme/watercourselink/Context.java b/theme-watercourselink/src/main/java/nl/ipo/cds/etl/theme/watercourselink/Context.java new file mode 100644 index 00000000..40282bce --- /dev/null +++ b/theme-watercourselink/src/main/java/nl/ipo/cds/etl/theme/watercourselink/Context.java @@ -0,0 +1,15 @@ +package nl.ipo.cds.etl.theme.watercourselink; + +import nl.ipo.cds.validation.DefaultValidatorContext; +import nl.ipo.cds.validation.ValidationReporter; +import nl.ipo.cds.validation.gml.codelists.CodeListFactory; + +public class Context extends DefaultValidatorContext { + + public Context ( + final CodeListFactory codeListFactory, + final ValidationReporter reporter) { + super (codeListFactory, reporter); + } + +} diff --git a/theme-watercourselink/src/main/java/nl/ipo/cds/etl/theme/watercourselink/Message.java b/theme-watercourselink/src/main/java/nl/ipo/cds/etl/theme/watercourselink/Message.java new file mode 100644 index 00000000..b84881da --- /dev/null +++ b/theme-watercourselink/src/main/java/nl/ipo/cds/etl/theme/watercourselink/Message.java @@ -0,0 +1,114 @@ +package nl.ipo.cds.etl.theme.watercourselink; + +import java.util.ArrayList; +import java.util.List; + +import nl.idgis.commons.jobexecutor.JobLogger.LogLevel; +import nl.ipo.cds.etl.ValidatorMessageKey; +import nl.ipo.cds.validation.AttributeExpression; +import nl.ipo.cds.validation.Expression; + +public enum Message implements ValidatorMessageKey { + + ATTRIBUTE_NULL, + ATTRIBUTE_EMPTY, + ATTRIBUTE_NOT_URL, + ATTRIBUTE_VALUE_NEGATIVE, + ATTRIBUTE_VALUE_TOO_LOW, + ATTRIBUTE_VALUE_TOO_HIGH, + ATTRIBUTE_CODE_CODESPACE_INVALID, + ATTRIBUTE_CODE_INVALID, + ATTRIBUTE_GROUP_INCONSISTENT, + + GEOMETRY_EMPTY_MULTIGEOMETRY, + GEOMETRY_ONLY_POINT_OR_MULTIPOINT, + GEOMETRY_ONLY_CURVE_OR_MULTICURVE, + GEOMETRY_ONLY_SURFACE_OR_MULTISURFACE, + GEOMETRY_POINT_NOT_ALLOWED, + GEOMETRY_POINT_DUPLICATION(Integer.MAX_VALUE, true), + GEOMETRY_EXTERIOR_RING_CW(LogLevel.WARNING), + GEOMETRY_INTERIOR_RING_CCW(LogLevel.WARNING), + GEOMETRY_DISCONTINUITY(Integer.MAX_VALUE, true), + GEOMETRY_SELF_INTERSECTION(Integer.MAX_VALUE, true), + GEOMETRY_RING_NOT_CLOSED(Integer.MAX_VALUE, true), + GEOMETRY_RING_SELF_INTERSECTION(Integer.MAX_VALUE, true), + GEOMETRY_INTERIOR_RINGS_TOUCH(Integer.MAX_VALUE, true), + GEOMETRY_INTERIOR_RINGS_INTERSECT(Integer.MAX_VALUE, true), + GEOMETRY_INTERIOR_RINGS_WITHIN(Integer.MAX_VALUE, true), + GEOMETRY_INTERIOR_RING_TOUCHES_EXTERIOR(Integer.MAX_VALUE, true), + GEOMETRY_INTERIOR_RING_INTERSECTS_EXTERIOR(Integer.MAX_VALUE, true), + GEOMETRY_INTERIOR_RING_OUTSIDE_EXTERIOR(Integer.MAX_VALUE, true), + GEOMETRY_INTERIOR_DISCONNECTED(Integer.MAX_VALUE, true), + GEOMETRY_SRS_NULL, + GEOMETRY_SRS_NOT_RD("EPSG:28992"), + + HAS_MORE_ERRORS(LogLevel.WARNING) + ; + + private final String[] params; + + private final LogLevel logLevel; + + private final int maxMessageLog; + + private final boolean addToShapeFile; + + private Message(LogLevel logLevel, Integer maxMessageLog, boolean addToShapeFile, String... params) { + this.maxMessageLog = maxMessageLog == null ? 10 : maxMessageLog; + this.logLevel = logLevel == null ? LogLevel.ERROR : logLevel; + this.addToShapeFile = addToShapeFile; + this.params = params; + } + + private Message(LogLevel logLevel, Integer maxMessageLog, String... params) { + this(logLevel, maxMessageLog, false, params); + } + + private Message(Integer maxMessageLog, boolean addToShapeFile, String... params) { + this(null, maxMessageLog, addToShapeFile, params); + } + + private Message(LogLevel logLevel) { + this(logLevel, null, false); + } + + private Message(String... params) { + this(null, null, false, params); + } + + @Override + public boolean isBlocking() { + return getLogLevel ().equals (LogLevel.ERROR); + } + + @Override + public List> getMessageParameters () { + final List> params = new ArrayList<> (); + // why twice??? + params.add (new AttributeExpression ("id", String.class)); + params.add (new AttributeExpression ("id", String.class)); + params.add (new AttributeExpression ("inspireIdLocalId", String.class)); + return params; + } + + @Override + public int getMaxMessageLog() { + return maxMessageLog; + } + + @Override + public boolean isAddToShapeFile () { + return addToShapeFile; + } + + @Override + public LogLevel getLogLevel() { + return logLevel; + } + + @Override + public Message getMaxMessageKey() { + return HAS_MORE_ERRORS; + } + +} diff --git a/theme-watercourselink/src/main/java/nl/ipo/cds/etl/theme/watercourselink/WatercourseLink.java b/theme-watercourselink/src/main/java/nl/ipo/cds/etl/theme/watercourselink/WatercourseLink.java new file mode 100644 index 00000000..5802239d --- /dev/null +++ b/theme-watercourselink/src/main/java/nl/ipo/cds/etl/theme/watercourselink/WatercourseLink.java @@ -0,0 +1,95 @@ +package nl.ipo.cds.etl.theme.watercourselink; + +import nl.ipo.cds.etl.PersistableFeature; +import nl.ipo.cds.etl.db.annotation.Column; +import nl.ipo.cds.etl.db.annotation.Table; +import nl.ipo.cds.etl.theme.annotation.CodeSpace; +import nl.ipo.cds.etl.theme.annotation.MappableAttribute; + +import org.deegree.commons.tom.ows.CodeType; +import org.deegree.geometry.Geometry; + +@Table(name = "watercourse_link", schema = "bron") +public class WatercourseLink extends PersistableFeature { + + @Column(name = "inspire_id_dataset_code") + private CodeType inspireIdDatasetCode; + + @Column(name = "inspire_id_local_id") + private String inspireIdLocalId; + + @Column(name = "geometry") + private Geometry geometry; + + @Column(name = "name") + private String name; + + @Column(name = "end_node_local_id") + private String endNodeLocalId; + + @Column(name = "start_node_local_id") + private String startNodeLocalId; + + @MappableAttribute + @CodeSpace("http://www.inspire-provincies.nl/codeList/DatasetTypeCode/WatercourseLink") + public CodeType getInspireIdDatasetCode() { + return inspireIdDatasetCode; + } + + @MappableAttribute + @CodeSpace("http://www.inspire-provincies.nl/codeList/DatasetTypeCode/WatercourseLink") + public void setInspireIdDatasetCode(CodeType inspireIdDatasetCode) { + this.inspireIdDatasetCode = inspireIdDatasetCode; + } + + @MappableAttribute + public String getInspireIdLocalId() { + return inspireIdLocalId; + } + + @MappableAttribute + public void setInspireIdLocalId(String inspireIdLocalId) { + this.inspireIdLocalId = inspireIdLocalId; + } + + @MappableAttribute + public Geometry getGeometry() { + return geometry; + } + + @MappableAttribute + public void setGeometry(Geometry geometry) { + this.geometry = geometry; + } + + @MappableAttribute + public String getName() { + return name; + } + + @MappableAttribute + public void setName(String name) { + this.name = name; + } + + @MappableAttribute + public String getEndNodeLocalId() { + return endNodeLocalId; + } + + @MappableAttribute + public void setEndNodeLocalId(String endNodeLocalId) { + this.endNodeLocalId = endNodeLocalId; + } + + @MappableAttribute + public String getStartNodeLocalId() { + return startNodeLocalId; + } + + @MappableAttribute + public void setStartNodeLocalId(String startNodeLocalId) { + this.startNodeLocalId = startNodeLocalId; + } + +} diff --git a/theme-watercourselink/src/main/java/nl/ipo/cds/etl/theme/watercourselink/WatercourseLinkValidator.java b/theme-watercourselink/src/main/java/nl/ipo/cds/etl/theme/watercourselink/WatercourseLinkValidator.java new file mode 100644 index 00000000..76546b6d --- /dev/null +++ b/theme-watercourselink/src/main/java/nl/ipo/cds/etl/theme/watercourselink/WatercourseLinkValidator.java @@ -0,0 +1,111 @@ +package nl.ipo.cds.etl.theme.watercourselink; + +import static nl.ipo.cds.etl.theme.watercourselink.Message.ATTRIBUTE_CODE_CODESPACE_INVALID; +import static nl.ipo.cds.etl.theme.watercourselink.Message.ATTRIBUTE_EMPTY; +import static nl.ipo.cds.etl.theme.watercourselink.Message.ATTRIBUTE_NULL; +import static nl.ipo.cds.etl.theme.watercourselink.Message.GEOMETRY_SRS_NOT_RD; +import static nl.ipo.cds.etl.theme.watercourselink.Message.GEOMETRY_SRS_NULL; + +import java.util.Map; + +import nl.ipo.cds.domain.EtlJob; +import nl.ipo.cds.etl.AbstractValidator; +import nl.ipo.cds.validation.AttributeExpression; +import nl.ipo.cds.validation.ValidationReporter; +import nl.ipo.cds.validation.Validator; +import nl.ipo.cds.validation.constants.Constant; +import nl.ipo.cds.validation.execute.CompilerException; +import nl.ipo.cds.validation.geometry.GeometryExpression; +import nl.ipo.cds.validation.gml.CodeExpression; +import nl.ipo.cds.validation.gml.codelists.CodeListFactory; + +import org.deegree.geometry.Geometry; + +public class WatercourseLinkValidator extends AbstractValidator { + + private final CodeExpression inspireIdDatasetCode = code ("inspireIdDatasetCode"); + + private final AttributeExpression inspireIdLocalId = stringAttr ("inspireIdLocalId"); + + private final GeometryExpression geometry = geometry ("geometry"); + + private final AttributeExpression name = stringAttr ("name"); + + private final AttributeExpression endNodeLocalId = stringAttr ("endNodeLocalId"); + + private final AttributeExpression startNodeLocalId = stringAttr ("startNodeLocalId"); + + private final Constant inspireIdDatasetCodeSpace = constant ("http://www.inspire-provincies.nl/codeList/DatasetTypeCode/WatercourseLink"); + + public WatercourseLinkValidator(final Map validatorMessages) throws CompilerException { + super(Context.class, WatercourseLink.class, validatorMessages); + compile(); + } + + @Override + public Context beforeJob(final EtlJob job, final CodeListFactory codeListFactory, + final ValidationReporter reporter) { + return new Context(codeListFactory, reporter); + } + + public Validator getInspireIdDatasetCodeValidator () { + return validate ( + and( + validate (not (inspireIdDatasetCode.isNull ())).message (ATTRIBUTE_NULL, constant (inspireIdDatasetCode.name)), + validate (not (isBlank (inspireIdDatasetCode.code()))).message (ATTRIBUTE_EMPTY, constant (inspireIdDatasetCode.name)), + validate (inspireIdDatasetCode.hasCodeSpace (inspireIdDatasetCodeSpace)).message (ATTRIBUTE_CODE_CODESPACE_INVALID, inspireIdDatasetCode.codeSpace(), constant(inspireIdDatasetCode.name), inspireIdDatasetCodeSpace) + ).shortCircuit() + ); + } + + public Validator getInspireIdLocalIdValidator () { + return validate ( + and( + validate (not (inspireIdLocalId.isNull ())).message (ATTRIBUTE_NULL, constant(inspireIdLocalId.name)), + validate (not (isBlank (inspireIdLocalId))).message (ATTRIBUTE_EMPTY, constant(inspireIdLocalId.name)) + ).shortCircuit() + ); + } + + public Validator getGeometryValidator () { + return validate ( + and ( + // The following validations short-circuit, there must be a non-null and non-empty, non-point geometry: + validate (not (geometry.isNull ())).message (ATTRIBUTE_NULL, constant(geometry.name)), + // SRS validations: + and ( + validate (geometry.hasSrs ()).message (GEOMETRY_SRS_NULL), + validate (geometry.isSrs (constant ("28992"))).message (GEOMETRY_SRS_NOT_RD, geometry.srsName ()) + ).shortCircuit() + ).shortCircuit () + ); + } + + public Validator getNameValidator () { + return validate ( + and( + validate (not (name.isNull ())).message (ATTRIBUTE_NULL, constant(name.name)), + validate (not (isBlank (name))).message (ATTRIBUTE_EMPTY, constant(name.name)) + ).shortCircuit() + ); + } + + public Validator getEndNodeLocalIdValidator () { + return validate ( + and( + validate (not (endNodeLocalId.isNull ())).message (ATTRIBUTE_NULL, constant(endNodeLocalId.name)), + validate (not (isBlank (endNodeLocalId))).message (ATTRIBUTE_EMPTY, constant(endNodeLocalId.name)) + ).shortCircuit() + ); + } + + public Validator getStartNodeLocalIdValidator () { + return validate ( + and( + validate (not (startNodeLocalId.isNull ())).message (ATTRIBUTE_NULL, constant(startNodeLocalId.name)), + validate (not (isBlank (startNodeLocalId))).message (ATTRIBUTE_EMPTY, constant(startNodeLocalId.name)) + ).shortCircuit() + ); + } + +} diff --git a/theme-watercourselink/src/main/java/nl/ipo/cds/etl/theme/watercourselink/config/DatasetConfig.java b/theme-watercourselink/src/main/java/nl/ipo/cds/etl/theme/watercourselink/config/DatasetConfig.java new file mode 100644 index 00000000..edfe6dbb --- /dev/null +++ b/theme-watercourselink/src/main/java/nl/ipo/cds/etl/theme/watercourselink/config/DatasetConfig.java @@ -0,0 +1,60 @@ +package nl.ipo.cds.etl.theme.watercourselink.config; + +import java.util.Properties; + +import javax.inject.Inject; +import javax.inject.Named; + +import nl.ipo.cds.attributemapping.operations.discover.OperationDiscoverer; +import nl.ipo.cds.etl.Transformer; +import nl.ipo.cds.etl.theme.DefaultThemeConfig; +import nl.ipo.cds.etl.theme.ThemeConfig; +import nl.ipo.cds.etl.theme.watercourselink.WatercourseLink; +import nl.ipo.cds.etl.theme.watercourselink.WatercourseLinkValidator; +import nl.ipo.cds.etl.util.ScriptExecutor; +import nl.ipo.cds.etl.util.ScriptTransformer; +import nl.ipo.cds.validation.execute.CompilerException; + +import org.springframework.beans.factory.config.PropertiesFactoryBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.io.ClassPathResource; + +@Configuration (value = "watercourseLink.DatasetConfig") +public class DatasetConfig { + + private static final String THEME_NAME = "WatercourseLink"; + + @Bean + @Inject + public ThemeConfig watercourseLinkThemeConfig ( + final WatercourseLinkValidator validator, + final OperationDiscoverer operationDiscoverer) { + return new DefaultThemeConfig (THEME_NAME, WatercourseLink.class, validator, operationDiscoverer); + } + + @Bean + public Transformer watercourseLinkTransformer(final ScriptExecutor scriptExecutor) { + return new ScriptTransformer(scriptExecutor, new ClassPathResource ("nl/ipo/cds/etl/theme/watercourselink/transform-bron-to-inspire.sql"), THEME_NAME); + } + + @Configuration (value = "watercourseLink.Validators") + public static class Validators { + @Bean + @Inject + public WatercourseLinkValidator watercourseLinkValidator ( + final @Named ("watercourseLinkValidationMessages") Properties validatorMessages) throws CompilerException { + return new WatercourseLinkValidator (validatorMessages); + } + } + + @Configuration (value = "watercourseLink.Messages") + public static class Messages { + @Bean + public PropertiesFactoryBean watercourseLinkValidationMessages () { + final PropertiesFactoryBean properties = new PropertiesFactoryBean (); + properties.setLocation (new ClassPathResource ("nl/ipo/cds/etl/theme/watercourselink/validator.messages")); + return properties; + } + } +} diff --git a/theme-watercourselink/src/main/java/nl/ipo/cds/etl/theme/watercourselink/config/Package.java b/theme-watercourselink/src/main/java/nl/ipo/cds/etl/theme/watercourselink/config/Package.java new file mode 100644 index 00000000..e0923c46 --- /dev/null +++ b/theme-watercourselink/src/main/java/nl/ipo/cds/etl/theme/watercourselink/config/Package.java @@ -0,0 +1,4 @@ +package nl.ipo.cds.etl.theme.watercourselink.config; + +public interface Package { +} diff --git a/theme-watercourselink/src/main/resources/nl/ipo/cds/etl/theme/watercourselink/messages.properties b/theme-watercourselink/src/main/resources/nl/ipo/cds/etl/theme/watercourselink/messages.properties new file mode 100644 index 00000000..139597f9 --- /dev/null +++ b/theme-watercourselink/src/main/resources/nl/ipo/cds/etl/theme/watercourselink/messages.properties @@ -0,0 +1,2 @@ + + diff --git a/theme-watercourselink/src/main/resources/nl/ipo/cds/etl/theme/watercourselink/transform-bron-to-inspire.sql b/theme-watercourselink/src/main/resources/nl/ipo/cds/etl/theme/watercourselink/transform-bron-to-inspire.sql new file mode 100644 index 00000000..82072170 --- /dev/null +++ b/theme-watercourselink/src/main/resources/nl/ipo/cds/etl/theme/watercourselink/transform-bron-to-inspire.sql @@ -0,0 +1,24 @@ +delete from inspire.watercourse_link; + +insert into inspire.watercourse_link ( + id, + job_id, + gfid, + inspire_id_namespace, + inspire_id_local_id, + name, + end_node_href, + start_node_href, + geometry + ) +select + id, + job_id, + gfid, + 'NL.' || inspire_id_dataset_code, + inspire_id_local_id, + "name", + '#HY_N_HYDRO_NODE_' || end_node_local_id, + '#HY_N_HYDRO_NODE_' || start_node_local_id, + ST_LineMerge(geometry) +from bron.watercourse_link; diff --git a/theme-watercourselink/src/main/resources/nl/ipo/cds/etl/theme/watercourselink/validator.messages b/theme-watercourselink/src/main/resources/nl/ipo/cds/etl/theme/watercourselink/validator.messages new file mode 100644 index 00000000..e663decf --- /dev/null +++ b/theme-watercourselink/src/main/resources/nl/ipo/cds/etl/theme/watercourselink/validator.messages @@ -0,0 +1,57 @@ +FEATURE=feature: ${0}, inspireIdLocalId: ${1} + +ATTRIBUTE_NULL=Het attribuut "${2}" ontbreekt, ${FEATURE} +ATTRIBUTE_EMPTY=Het attribuut "${2}" is leeg, ${FEATURE} +ATTRIBUTE_NOT_URL=De waarde "${2}" van het attribuut "${3}" is geen valide URL, ${FEATURE} +ATTRIBUTE_VALUE_NEGATIVE=De waarde "${2}" van het attribuut "${3}" is negatief, ${FEATURE} +ATTRIBUTE_CODE_CODESPACE_INVALID=De 'codeSpace' "${2}" van attribuut "${3}" is niet valide (verwacht: "${4}"), ${FEATURE} +ATTRIBUTE_CODE_INVALID=De code "${2}" van het attribuut "${3}" is niet valide met betrekking tot de code-lijst "${4}", ${FEATURE} +ATTRIBUTE_VALUE_TOO_LOW=De waarde "${2}" van het attribuut "${3}" is te laag (limiet "${4}"), ${FEATURE} +ATTRIBUTE_VALUE_TOO_HIGH=De waarde "${2}" van het attribuut "${3}" is te hoog (limiet "${4}"), ${FEATURE} +ATTRIBUTE_GROUP_INCONSISTENT=Het attribuut "${2}" kan niet worden weggelaten, als er één of meerdere andere attributen uit de groep (zoals "${3}") aanwezig zijn, ${FEATURE} + +GEOMETRY_NULL_BASE=geometrie ontbreekt +GEOMETRY_EMPTY_MULTIGEOMETRY_BASE=multi geometrie is leeg +GEOMETRY_ONLY_POINT_OR_MULTIPOINT_BASE=geometrie has wrong type: must be a point (or a multi point) +GEOMETRY_ONLY_CURVE_OR_MULTICURVE_BASE=geometrie has wrong type: must be a linestring (or a multi linestring) +GEOMETRY_ONLY_SURFACE_OR_MULTISURFACE_BASE=geometrie has wrong type: must be a polygon (or a multi polygon) +GEOMETRY_POINT_DUPLICATION_BASE=geometrie bevat duplicaat punten, locatie: ${2} +GEOMETRY_EXTERIOR_RING_CW_BASE=geometrie bevat een buitenring met CW oriëntatie +GEOMETRY_INTERIOR_RING_CCW_BASE=geometrie bevat een binnenring met CCW oriëntatie +GEOMETRY_DISCONTINUITY_BASE=geometrie bevat lijnelementen die niet aansluiten +GEOMETRY_SELF_INTERSECTION_BASE=geometrie bevat een lijn die zichzelf snijdt, locatie: ${2} +GEOMETRY_RING_NOT_CLOSED_BASE=geometrie bevat een niet gesloten ring +GEOMETRY_RING_SELF_INTERSECTION_BASE=geometrie bevat een ring die zichzelf snijdt, locatie: ${2} +GEOMETRY_INTERIOR_RINGS_TOUCH_BASE=geometrie bevat een binnenring die zichzelf raakt, locatie: ${2} +GEOMETRY_INTERIOR_RINGS_INTERSECT_BASE=geometrie bevat een binnenring die zichzelf snijdt, locatie: ${2} +GEOMETRY_INTERIOR_RINGS_WITHIN_BASE=geometrie bevat een binnenring binnen een andere binnenring +GEOMETRY_INTERIOR_RING_TOUCHES_EXTERIOR_BASE=geometrie bevat een binnenring die een buitenring raakt, locatie: ${2} +GEOMETRY_INTERIOR_RING_INTERSECTS_EXTERIOR_BASE=geometrie bevat een binnenring die een buitenring snijdt, locatie: ${2} +GEOMETRY_INTERIOR_RING_OUTSIDE_EXTERIOR_BASE=geometrie bevat een binnenring die niet binnen een buitenring ligt +GEOMETRY_INTERIOR_DISCONNECTED_BASE=geometrie bevat een verbroken polygoon +GEOMETRY_SRS_NULL_BASE=Het attribuut "srsName" ontbreekt bij het geometrie-element +GEOMETRY_SRS_NOT_RD_BASE=Het attribuut "srsName" bij element "geometry" heeft een andere waarde dan "EPSG:28992" (RD_New) + +GEOMETRY_NULL=${GEOMETRY_NULL_BASE}, ${FEATURE} +GEOMETRY_EMPTY_MULTIGEOMETRY=${GEOMETRY_EMPTY_MULTIGEOMETRY_BASE}, ${FEATURE} +GEOMETRY_ONLY_POINT_OR_MULTIPOINT=${GEOMETRY_ONLY_POINT_OR_MULTIPOINT_BASE}, ${FEATURE} +GEOMETRY_ONLY_CURVE_OR_MULTICURVE=${GEOMETRY_ONLY_CURVE_OR_MULTICURVE_BASE}, ${FEATURE} +GEOMETRY_ONLY_SURFACE_OR_MULTISURFACE=${GEOMETRY_ONLY_SURFACE_OR_MULTISURFACE_BASE}, ${FEATURE} +GEOMETRY_POINT_DUPLICATION=${GEOMETRY_POINT_DUPLICATION_BASE}, ${FEATURE} +GEOMETRY_EXTERIOR_RING_CW=${GEOMETRY_EXTERIOR_RING_CW_BASE}, ${FEATURE} +GEOMETRY_INTERIOR_RING_CCW=${GEOMETRY_INTERIOR_RING_CCW_BASE}, ${FEATURE} +GEOMETRY_DISCONTINUITY=${GEOMETRY_DISCONTINUITY_BASE}, ${FEATURE} +GEOMETRY_SELF_INTERSECTION=${GEOMETRY_SELF_INTERSECTION_BASE}, ${FEATURE} +GEOMETRY_RING_NOT_CLOSED=${GEOMETRY_RING_NOT_CLOSED_BASE}, ${FEATURE} +GEOMETRY_RING_SELF_INTERSECTION=${GEOMETRY_RING_SELF_INTERSECTION_BASE}, ${FEATURE} +GEOMETRY_INTERIOR_RINGS_TOUCH=${GEOMETRY_INTERIOR_RINGS_TOUCH_BASE}, ${FEATURE} +GEOMETRY_INTERIOR_RINGS_INTERSECT=${GEOMETRY_INTERIOR_RINGS_INTERSECT_BASE}, ${FEATURE} +GEOMETRY_INTERIOR_RINGS_WITHIN=${GEOMETRY_INTERIOR_RINGS_WITHIN_BASE}, ${FEATURE} +GEOMETRY_INTERIOR_RING_TOUCHES_EXTERIOR=${GEOMETRY_INTERIOR_RING_TOUCHES_EXTERIOR_BASE}, ${FEATURE} +GEOMETRY_INTERIOR_RING_INTERSECTS_EXTERIOR=${GEOMETRY_INTERIOR_RING_INTERSECTS_EXTERIOR_BASE}, ${FEATURE} +GEOMETRY_INTERIOR_RING_OUTSIDE_EXTERIOR=${GEOMETRY_INTERIOR_RING_OUTSIDE_EXTERIOR_BASE}, ${FEATURE} +GEOMETRY_INTERIOR_DISCONNECTED=${GEOMETRY_INTERIOR_DISCONNECTED_BASE}, ${FEATURE} +GEOMETRY_SRS_NULL=${GEOMETRY_SRS_NULL_BASE}, ${FEATURE} +GEOMETRY_SRS_NOT_RD=${GEOMETRY_SRS_NOT_RD_BASE} (gevonden waarde: ${1}), ${FEATURE} + +HAS_MORE_ERRORS=Er zijn meer meldingen die niet werden gerapporteerd diff --git a/theme-watercourselink/src/main/sql/create-bron-schema-watercourselink.sql b/theme-watercourselink/src/main/sql/create-bron-schema-watercourselink.sql new file mode 100644 index 00000000..4b85be1a --- /dev/null +++ b/theme-watercourselink/src/main/sql/create-bron-schema-watercourselink.sql @@ -0,0 +1,23 @@ + +create table bron.watercourse_link ( + id serial, + job_id bigint, + gfid text, + + inspire_id_namespace text not null, + inspire_id_local_id text not null, + name text not null, + end_node_local_id text not null, + start_node_local_id text not null, + + primary key (id), + constraint fk_job_id foreign key (job_id) references manager.job (id) +); +SELECT AddGeometryColumn ('bron','watercourse_link','geometry',28992,'GEOMETRY',2); +ALTER TABLE bron.watercourse_link ALTER COLUMN "geometry" SET NOT NULL; + +CREATE INDEX idx_bron_watercourse_link_geometry ON bron.watercourse_link USING GIST (geometry); + +GRANT SELECT, INSERT, UPDATE, DELETE, TRIGGER ON bron.watercourse_link TO inspire; +GRANT USAGE, SELECT, UPDATE ON SEQUENCE bron.watercourse_link_id_seq TO inspire; +---------------------------------- diff --git a/theme-watercourselink/src/main/sql/create-inspire-schema-watercourselink.sql b/theme-watercourselink/src/main/sql/create-inspire-schema-watercourselink.sql new file mode 100644 index 00000000..83ef5129 --- /dev/null +++ b/theme-watercourselink/src/main/sql/create-inspire-schema-watercourselink.sql @@ -0,0 +1,23 @@ + +create table inspire.watercourse_link ( + id serial, + job_id bigint, + gfid text, + + inspire_id_namespace text not null, + inspire_id_local_id text not null, + name text not null, + end_node_href text not null, + start_node_href text not null, + + primary key (id), + constraint fk_job_id foreign key (job_id) references manager.job (id) +); +SELECT AddGeometryColumn ('inspire','watercourse_link','geometry',28992,'GEOMETRY',2); +CREATE INDEX watercourse_link_geometry_idx ON inspire.watercourse_link USING gist(geometry); + +ALTER TABLE inspire.watercourse_link ALTER COLUMN "geometry" SET NOT NULL; + +GRANT SELECT, INSERT, UPDATE, DELETE, TRIGGER ON inspire.watercourse_link TO inspire; +GRANT USAGE, SELECT, UPDATE ON SEQUENCE inspire.watercourse_link_id_seq TO inspire; +---------------------------------- diff --git a/theme-watercourselink/src/main/sql/populate-manager-schema-watercourselink.sql b/theme-watercourselink/src/main/sql/populate-manager-schema-watercourselink.sql new file mode 100644 index 00000000..b403228d --- /dev/null +++ b/theme-watercourselink/src/main/sql/populate-manager-schema-watercourselink.sql @@ -0,0 +1,12 @@ +-- +-- WatercourseLink +-- +-- Names must match constants defined corresponding ThemeConfig +insert into manager.thema (id, naam) values ((select nextval('manager.hibernate_sequence')), 'WatercourseLink'); + +insert into manager.datasettype (id, naam, thema_id) values ((select nextval('manager.hibernate_sequence')), 'WatercourseLinksNL', (select id from manager.thema t where t.naam = 'WatercourseLink')); + +insert into manager.bronhouder (id, code, contact_naam, contact_adres, contact_postcode, contact_plaats, naam, contact_emailadres, contact_telefoonnummer, common_name) select nextval('manager.hibernate_sequence'), 'elf', 'ELF Project', '', '', '', 'ELF Project', 'inspire@idgis.nl', '', 'elfproject' where not exists (select * from manager.bronhouder where code = 'elf'); + +insert into manager.themabronhouderauthorization (thema_id, bronhouder_id) values ( (select id from manager.thema where naam = 'WatercourseLink'), (select id from manager.bronhouder where code = 'elf') ); +-- diff --git a/theme-watercourselink/src/test/java/nl/ipo/cds/etl/theme/watercourselink/ValidatorsValidTest.java b/theme-watercourselink/src/test/java/nl/ipo/cds/etl/theme/watercourselink/ValidatorsValidTest.java new file mode 100644 index 00000000..e7d7a93d --- /dev/null +++ b/theme-watercourselink/src/test/java/nl/ipo/cds/etl/theme/watercourselink/ValidatorsValidTest.java @@ -0,0 +1,16 @@ +package nl.ipo.cds.etl.theme.watercourselink; + +import java.util.Collections; + +import nl.ipo.cds.etl.theme.watercourselink.WatercourseLinkValidator; + +import org.junit.Test; + +public class ValidatorsValidTest { + + @Test + public void testValidatorValid () throws Exception { + new WatercourseLinkValidator (Collections.emptyMap ()); + } + +} diff --git a/theme-watercourselink/src/test/java/nl/ipo/cds/etl/theme/watercourselink/WatercourseLinkValidatorTest.java b/theme-watercourselink/src/test/java/nl/ipo/cds/etl/theme/watercourselink/WatercourseLinkValidatorTest.java new file mode 100644 index 00000000..ac68792b --- /dev/null +++ b/theme-watercourselink/src/test/java/nl/ipo/cds/etl/theme/watercourselink/WatercourseLinkValidatorTest.java @@ -0,0 +1,97 @@ +package nl.ipo.cds.etl.theme.watercourselink; + +import static nl.ipo.cds.etl.theme.watercourselink.Message.ATTRIBUTE_CODE_CODESPACE_INVALID; +import static nl.ipo.cds.etl.theme.watercourselink.Message.ATTRIBUTE_EMPTY; +import static nl.ipo.cds.etl.theme.watercourselink.Message.ATTRIBUTE_NULL; +import static nl.ipo.cds.etl.theme.watercourselink.Message.GEOMETRY_SRS_NOT_RD; +import static nl.ipo.cds.etl.theme.watercourselink.Message.GEOMETRY_SRS_NULL; + +import java.util.Collections; + +import nl.ipo.cds.etl.test.GeometryConstants; +import nl.ipo.cds.etl.test.ValidationRunner; + +import org.deegree.commons.tom.ows.CodeType; +import org.junit.Before; +import org.junit.Test; + +public class WatercourseLinkValidatorTest { + + private WatercourseLinkValidator validator; + private ValidationRunner runner; + private GeometryConstants geom; + + @Before + public void createValidator() throws Exception { + validator = new WatercourseLinkValidator(Collections.emptyMap()); + runner = new ValidationRunner<>(validator, WatercourseLink.class); + geom = new GeometryConstants("EPSG:28992"); + } + + private ValidationRunner.Runner run(final String validationName) { + return runner.validation(validationName); + } + + @Test + public void getInspireIdDatasetCodeValidator () throws Throwable { + + run ("inspireIdDatasetCode") + .with (null) + .assertOnlyKey (ATTRIBUTE_NULL); + + run ("inspireIdDatasetCode") + .with (new CodeType("")) + .assertOnlyKey (ATTRIBUTE_EMPTY); + + run ("inspireIdDatasetCode") + .with (new CodeType("bogus")) + .assertOnlyKey (ATTRIBUTE_CODE_CODESPACE_INVALID); + +// run ("inspireIdDatasetCode") +// .withCodeList ("http://www.inspire-provincies.nl/codeList/DatasetTypeCode/ProductionFacility", "lgrinr") +// .with (new CodeType("value1", "http://www.inspire-provincies.nl/codeList/DatasetTypeCode/ProductionFacility")) +// .assertOnlyKey (ATTRIBUTE_CODE_INVALID); + + run ("inspireIdDatasetCode") + .withCodeList ("http://www.inspire-provincies.nl/codeList/DatasetTypeCode/WatercourseLink", "lgrinr") + .with (new CodeType("lgrinr", "http://www.inspire-provincies.nl/codeList/DatasetTypeCode/WatercourseLink")) + .assertNoMessages(); + } + + @Test + public void getInspireIdLocalIdValidator () throws Throwable { + + run ("inspireIdLocalId") + .with (null) + .assertOnlyKey (ATTRIBUTE_NULL); + + run ("inspireIdLocalId") + .with ("") + .assertOnlyKey (ATTRIBUTE_EMPTY); + + run ("inspireIdLocalId") + .with ("nl1000") + .assertNoMessages(); + } + + @Test + public void testGeometry () throws Exception { + + run ("geometry") + .with (null) + .assertOnlyKey (ATTRIBUTE_NULL); + + run ("geometry") + .with (geom.lineString (null)) + .assertOnlyKey (GEOMETRY_SRS_NULL); + + run ("geometry") + .with (geom.lineString (geom.getSrs ("EPSG:3857"))) + .assertOnlyKey (GEOMETRY_SRS_NOT_RD); + + run ("geometry") + .with (geom.lineString ()) + .assertNoMessages (); + } + +} diff --git a/themes/pom.xml b/themes/pom.xml index 1cade0ba..46a86e47 100644 --- a/themes/pom.xml +++ b/themes/pom.xml @@ -25,6 +25,11 @@ theme-habitat 2.2-SNAPSHOT + + nl.ipo.cds + theme-hydronode + 2.2-SNAPSHOT + nl.ipo.cds theme-hazardarea @@ -50,5 +55,10 @@ theme-riskzone 2.2-SNAPSHOT + + nl.ipo.cds + theme-watercourselink + 2.2-SNAPSHOT + \ No newline at end of file