diff --git a/deegree-datastores/deegree-featurestores/deegree-featurestore-sql/pom.xml b/deegree-datastores/deegree-featurestores/deegree-featurestore-sql/pom.xml index ed300108d0..b35207949c 100644 --- a/deegree-datastores/deegree-featurestores/deegree-featurestore-sql/pom.xml +++ b/deegree-datastores/deegree-featurestores/deegree-featurestore-sql/pom.xml @@ -77,6 +77,10 @@ net.gcardone.junidecode junidecode + + commons-io + commons-io + diff --git a/deegree-datastores/deegree-featurestores/deegree-featurestore-sql/src/main/java/org/deegree/feature/persistence/sql/config/MappedSchemaBuilderTable.java b/deegree-datastores/deegree-featurestores/deegree-featurestore-sql/src/main/java/org/deegree/feature/persistence/sql/config/MappedSchemaBuilderTable.java index b31c0c7a3e..8577e17347 100644 --- a/deegree-datastores/deegree-featurestores/deegree-featurestore-sql/src/main/java/org/deegree/feature/persistence/sql/config/MappedSchemaBuilderTable.java +++ b/deegree-datastores/deegree-featurestores/deegree-featurestore-sql/src/main/java/org/deegree/feature/persistence/sql/config/MappedSchemaBuilderTable.java @@ -48,18 +48,14 @@ import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; -import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; -import java.util.stream.Collectors; - import jakarta.xml.bind.JAXBElement; import javax.xml.namespace.QName; - import org.deegree.commons.jdbc.SQLIdentifier; import org.deegree.commons.jdbc.TableName; import org.deegree.commons.tom.gml.property.PropertyType; @@ -76,13 +72,17 @@ import org.deegree.feature.persistence.sql.FeatureTypeMapping; import org.deegree.feature.persistence.sql.GeometryStorageParams; import org.deegree.feature.persistence.sql.MappedAppSchema; -import org.deegree.sqldialect.SortCriterion; import org.deegree.feature.persistence.sql.expressions.TableJoin; import org.deegree.feature.persistence.sql.id.AutoIDGenerator; import org.deegree.feature.persistence.sql.id.FIDMapping; import org.deegree.feature.persistence.sql.id.IDGenerator; -import org.deegree.feature.persistence.sql.jaxb.*; +import org.deegree.feature.persistence.sql.jaxb.AbstractParticleJAXB; +import org.deegree.feature.persistence.sql.jaxb.FIDMappingJAXB; import org.deegree.feature.persistence.sql.jaxb.FIDMappingJAXB.ColumnJAXB; +import org.deegree.feature.persistence.sql.jaxb.FeatureTypeMappingJAXB; +import org.deegree.feature.persistence.sql.jaxb.GeometryParticleJAXB; +import org.deegree.feature.persistence.sql.jaxb.Join; +import org.deegree.feature.persistence.sql.jaxb.PrimitiveParticleJAXB; import org.deegree.feature.persistence.sql.rules.GeometryMapping; import org.deegree.feature.persistence.sql.rules.Mapping; import org.deegree.feature.persistence.sql.rules.PrimitiveMapping; @@ -95,6 +95,7 @@ import org.deegree.filter.expression.ValueReference; import org.deegree.gml.schema.GMLSchemaInfoSet; import org.deegree.sqldialect.SQLDialect; +import org.deegree.sqldialect.SortCriterion; import org.deegree.sqldialect.filter.DBField; import org.deegree.sqldialect.filter.MappingExpression; import org.deegree.workspace.Workspace; @@ -354,7 +355,7 @@ else if (propDecl instanceof GeometryParticleJAXB) { } pt = new SimplePropertyType(propName, minOccurs, maxOccurs, primType, null, null); m = new PrimitiveMapping(path, minOccurs == 0, mapping, ((SimplePropertyType) pt).getPrimitiveType(), jc, - null); + propDecl.getCustomConverter()); } else if (propDecl instanceof GeometryParticleJAXB) { GeometryParticleJAXB geomDecl = (GeometryParticleJAXB) propDecl; @@ -381,7 +382,8 @@ else if (propDecl instanceof GeometryParticleJAXB) { } CoordinateDimension dim = crs.getDimension() == 3 ? DIM_2 : DIM_3; pt = new GeometryPropertyType(propName, minOccurs, maxOccurs, null, null, type, dim, INLINE); - m = new GeometryMapping(path, minOccurs == 0, mapping, type, new GeometryStorageParams(crs, srid, dim), jc); + m = new GeometryMapping(path, minOccurs == 0, mapping, type, new GeometryStorageParams(crs, srid, dim), jc, + propDecl.getCustomConverter()); } else { LOG.warn("Unhandled property declaration '{}'. Skipping it.", propDecl.getClass()); diff --git a/deegree-datastores/deegree-featurestores/deegree-featurestore-sql/src/main/java/org/deegree/feature/persistence/sql/converter/AbstractStringPrimitiveConverter.java b/deegree-datastores/deegree-featurestores/deegree-featurestore-sql/src/main/java/org/deegree/feature/persistence/sql/converter/AbstractStringPrimitiveConverter.java new file mode 100644 index 0000000000..d428997a81 --- /dev/null +++ b/deegree-datastores/deegree-featurestores/deegree-featurestore-sql/src/main/java/org/deegree/feature/persistence/sql/converter/AbstractStringPrimitiveConverter.java @@ -0,0 +1,116 @@ +/*---------------------------------------------------------------------------- + This file is part of deegree, http://deegree.org/ + Copyright (C) 2001-2024 by: + - Department of Geography, University of Bonn - + and + - lat/lon GmbH - + and + - grit graphische Informationstechnik Beratungsgesellschaft mbH - + + This library is free software; you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License as published by the Free + Software Foundation; either version 2.1 of the License, or (at your option) + any later version. + This library is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + details. + You should have received a copy of the GNU Lesser General Public License + along with this library; if not, write to the Free Software Foundation, Inc., + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Contact information: + + grit graphische Informationstechnik Beratungsgesellschaft mbH + Landwehrstr. 143, 59368 Werne + Germany + https://www.grit.de/ + + lat/lon GmbH + Aennchenstr. 19, 53177 Bonn + Germany + http://lat-lon.de/ + + Department of Geography, University of Bonn + Prof. Dr. Klaus Greve + Postfach 1147, 53001 Bonn + Germany + http://www.geographie.uni-bonn.de/deegree/ + + e-mail: info@deegree.org + ----------------------------------------------------------------------------*/ +package org.deegree.feature.persistence.sql.converter; + +import static org.slf4j.LoggerFactory.getLogger; + +import org.deegree.commons.tom.primitive.BaseType; +import org.deegree.commons.tom.primitive.PrimitiveType; +import org.deegree.commons.tom.primitive.PrimitiveValue; +import org.deegree.feature.persistence.sql.SQLFeatureStore; +import org.deegree.feature.persistence.sql.jaxb.CustomConverterJAXB; +import org.deegree.feature.persistence.sql.rules.Mapping; +import org.deegree.feature.persistence.sql.rules.PrimitiveMapping; +import org.slf4j.Logger; + +/** + * Base for building a custom converter on top of primitive mappings of strings + * + * @see BinaryBase64PrimitiveConverter + * @see BinaryDataUrlPrimitiveConverter + * @see CharacterPrimitiveConverter + * @author Stephan Reichhelm + */ +public abstract class AbstractStringPrimitiveConverter implements CustomParticleConverter { + + private static final Logger LOG = getLogger(AbstractStringPrimitiveConverter.class); + + protected final PrimitiveType pt = new PrimitiveType(BaseType.STRING); + + private String column = null; + + protected int maxLen = 256 * 1024 * 1024; // Default limit of 256 MiB + + protected int sqlType; + + protected AbstractStringPrimitiveConverter(int defaultSqlType) { + this.sqlType = defaultSqlType; + } + + @Override + public String getSelectSnippet(String tableAlias) { + if (tableAlias != null) { + if (column.startsWith("'") || column.contains(" ")) { + return column.replace("$0", tableAlias); + } + return tableAlias + "." + column; + } + return column; + } + + @Override + public String getSetSnippet(PrimitiveValue particle) { + return "?"; + } + + @Override + public void init(Mapping mapping, SQLFeatureStore fs) { + if (mapping.getConverter() == null) { + return; + } + for (CustomConverterJAXB.Param p : mapping.getConverter().getParam()) { + if ("max-length".equalsIgnoreCase(p.getName())) { + maxLen = Math.max(1, Integer.parseInt(p.getValue())); + } + if ("sql-type".equalsIgnoreCase(p.getName())) { + sqlType = Integer.parseInt(p.getValue()); + } + } + if (mapping instanceof PrimitiveMapping) { + column = ((PrimitiveMapping) mapping).getMapping().toString(); + } + else { + LOG.error("Converter cannot be used for mapping path {}", mapping.getPath()); + } + } + +} diff --git a/deegree-datastores/deegree-featurestores/deegree-featurestore-sql/src/main/java/org/deegree/feature/persistence/sql/converter/BinaryBase64PrimitiveConverter.java b/deegree-datastores/deegree-featurestores/deegree-featurestore-sql/src/main/java/org/deegree/feature/persistence/sql/converter/BinaryBase64PrimitiveConverter.java new file mode 100644 index 0000000000..8c61855791 --- /dev/null +++ b/deegree-datastores/deegree-featurestores/deegree-featurestore-sql/src/main/java/org/deegree/feature/persistence/sql/converter/BinaryBase64PrimitiveConverter.java @@ -0,0 +1,146 @@ +/*---------------------------------------------------------------------------- + This file is part of deegree, http://deegree.org/ + Copyright (C) 2001-2024 by: + - Department of Geography, University of Bonn - + and + - lat/lon GmbH - + and + - grit graphische Informationstechnik Beratungsgesellschaft mbH - + + This library is free software; you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License as published by the Free + Software Foundation; either version 2.1 of the License, or (at your option) + any later version. + This library is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + details. + You should have received a copy of the GNU Lesser General Public License + along with this library; if not, write to the Free Software Foundation, Inc., + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Contact information: + + grit graphische Informationstechnik Beratungsgesellschaft mbH + Landwehrstr. 143, 59368 Werne + Germany + https://www.grit.de/ + + lat/lon GmbH + Aennchenstr. 19, 53177 Bonn + Germany + http://lat-lon.de/ + + Department of Geography, University of Bonn + Prof. Dr. Klaus Greve + Postfach 1147, 53001 Bonn + Germany + http://www.geographie.uni-bonn.de/deegree/ + + e-mail: info@deegree.org + ----------------------------------------------------------------------------*/ +package org.deegree.feature.persistence.sql.converter; + +import static org.slf4j.LoggerFactory.getLogger; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.SQLFeatureNotSupportedException; +import java.sql.Types; +import java.util.Base64; +import org.apache.commons.io.IOUtils; +import org.deegree.commons.tom.primitive.PrimitiveValue; +import org.deegree.feature.persistence.sql.SQLFeatureStore; +import org.deegree.feature.persistence.sql.rules.Mapping; +import org.slf4j.Logger; + +/** + * Converts binary database columns from/to primitive strings encoded as Base64 + *

+ * Note that the maximum length of allowed data is limited to prevent Denial of Service + * Attacks. The allowed maximum length can be set through the max-length parameter in + * bytes (see {@link AbstractStringPrimitiveConverter#init(Mapping, SQLFeatureStore)}). + *

+ * + * @see The Base16, Base32, and + * Base64 Data Encodings + * @author Stephan Reichhelm + */ +public class BinaryBase64PrimitiveConverter extends AbstractStringPrimitiveConverter { + + private static final Logger LOG = getLogger(BinaryBase64PrimitiveConverter.class); + + protected final Base64.Decoder decoder; + + protected final Base64.Encoder encoder; + + protected BinaryBase64PrimitiveConverter(Base64.Encoder enc, Base64.Decoder dec) { + super(Types.BLOB); + this.decoder = dec; + this.encoder = enc; + } + + public BinaryBase64PrimitiveConverter() { + this(Base64.getEncoder(), Base64.getDecoder()); + } + + String formatInput(String value) throws SQLException { + return value; + } + + String formatOutput(String value) throws SQLException { + return value; + } + + @Override + public PrimitiveValue toParticle(ResultSet rs, int colIndex) throws SQLException { + try (InputStream is = rs.getBinaryStream(colIndex)) { + if (is == null) { + return null; + } + byte[] raw = IOUtils.toByteArray(is); + return new PrimitiveValue(formatOutput(encoder.encodeToString(raw)), pt); + } + catch (IOException ioe) { + LOG.trace("Exception", ioe); + throw new SQLException("Conversation from binary to Base64 failed: " + ioe.getMessage()); + } + } + + @Override + public void setParticle(PreparedStatement stmt, PrimitiveValue particle, int paramIndex) throws SQLException { + final String val; + if (particle.getValue() != null) { + val = particle.getValue().toString(); + } + else { + val = null; + } + if (val == null) { + try { + stmt.setNull(paramIndex, sqlType); + } + catch (SQLFeatureNotSupportedException ignored) { + stmt.setString(paramIndex, null); + } + } + else if (val.length() > (((float) maxLen / 3) * 4 * 1.1)) { + // NOTE encoded is 4/3 the size of the not encoded content, but 10 percent is + // added for linebreak etc. + throw new SQLException("Maximum length of " + maxLen + " bytes exceeded in pre check."); + } + else { + byte[] raw = decoder.decode(formatInput(val)); + if (raw.length > maxLen) { + throw new SQLException("Maximum length of " + maxLen + " bytes exceeded."); + } + + stmt.setBinaryStream(paramIndex, new ByteArrayInputStream(raw), raw.length); + } + } + +} diff --git a/deegree-datastores/deegree-featurestores/deegree-featurestore-sql/src/main/java/org/deegree/feature/persistence/sql/converter/BinaryDataUrlPrimitiveConverter.java b/deegree-datastores/deegree-featurestores/deegree-featurestore-sql/src/main/java/org/deegree/feature/persistence/sql/converter/BinaryDataUrlPrimitiveConverter.java new file mode 100644 index 0000000000..90c1b6c5de --- /dev/null +++ b/deegree-datastores/deegree-featurestores/deegree-featurestore-sql/src/main/java/org/deegree/feature/persistence/sql/converter/BinaryDataUrlPrimitiveConverter.java @@ -0,0 +1,147 @@ +/*---------------------------------------------------------------------------- + This file is part of deegree, http://deegree.org/ + Copyright (C) 2001-2024 by: + - Department of Geography, University of Bonn - + and + - lat/lon GmbH - + and + - grit graphische Informationstechnik Beratungsgesellschaft mbH - + + This library is free software; you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License as published by the Free + Software Foundation; either version 2.1 of the License, or (at your option) + any later version. + This library is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + details. + You should have received a copy of the GNU Lesser General Public License + along with this library; if not, write to the Free Software Foundation, Inc., + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Contact information: + + grit graphische Informationstechnik Beratungsgesellschaft mbH + Landwehrstr. 143, 59368 Werne + Germany + https://www.grit.de/ + + lat/lon GmbH + Aennchenstr. 19, 53177 Bonn + Germany + http://lat-lon.de/ + + Department of Geography, University of Bonn + Prof. Dr. Klaus Greve + Postfach 1147, 53001 Bonn + Germany + http://www.geographie.uni-bonn.de/deegree/ + + e-mail: info@deegree.org + ----------------------------------------------------------------------------*/ +package org.deegree.feature.persistence.sql.converter; + +import static org.slf4j.LoggerFactory.getLogger; + +import java.sql.SQLException; +import java.util.Base64; +import java.util.HashMap; +import java.util.Map; +import java.util.regex.Pattern; +import org.apache.commons.codec.binary.Hex; +import org.deegree.commons.utils.StringUtils; +import org.deegree.feature.persistence.sql.SQLFeatureStore; +import org.deegree.feature.persistence.sql.jaxb.CustomConverterJAXB; +import org.deegree.feature.persistence.sql.rules.Mapping; +import org.slf4j.Logger; + +/** + * Converts binary database columns from/to primitive strings encoded as data URL + *

+ * Note that the maximum length of allowed data is limited to prevent Denial of Service + * Attacks. The allowed maximum length can be set through the max-length parameter in + * bytes (see {@link AbstractStringPrimitiveConverter#init(Mapping, SQLFeatureStore)}). + * Currently, only some generic image file types are configured by default. Additional + * mime mappings can be added by supplied by adding magic numbers with mime type as + * parameter. These parameter keys have to start with magic- followed by the + * magic bytes in hex and the corresponding mime type. + *

+ * + * @see RFC 2397 The "data" URL scheme + * @author Stephan Reichhelm + */ +public class BinaryDataUrlPrimitiveConverter extends BinaryBase64PrimitiveConverter { + + private static final Logger LOG = getLogger(BinaryDataUrlPrimitiveConverter.class); + + private static final Pattern PAT_NON_HEX = Pattern.compile("[^0-9a-fA-F]+"); + + private final Map magicBytesToMimeType = new HashMap<>(); + + private void addImageMapping(String hexInput, String mimeType) { + try { + String hex = PAT_NON_HEX.matcher(hexInput).replaceAll(""); + byte[] magic = Hex.decodeHex(hex); + String result = encoder.encodeToString(magic); + // remove padding + String base64 = StringUtils.trim(result, "="); + magicBytesToMimeType.put(base64, mimeType); + } + catch (Exception ex) { + LOG.error("Failed to add image magic '{}' for mime-type '{}' to lookup map .", hexInput, mimeType); + LOG.trace("Exception", ex); + } + } + + public BinaryDataUrlPrimitiveConverter() { + super(Base64.getEncoder(), Base64.getDecoder()); + + // https://en.wikipedia.org/wiki/List_of_file_signatures + LOG.trace("Adding default mappings for gif, jpg and png"); + addImageMapping("47 49 46 38 37 61", "image/gif"); + addImageMapping("47 49 46 38 39 61", "image/gif"); + addImageMapping("FF D8 FF DB", "image/jpg"); + addImageMapping("FF D8 FF E0", "image/jpg"); + addImageMapping("FF D8 FF E1", "image/jpg"); + addImageMapping("FF D8 FF EE", "image/jpg"); + addImageMapping("89 50 4E 47 0D 0A 1A 0A", "image/png"); + } + + @Override + String formatInput(String value) throws SQLException { + if (value == null) { + return null; + } + String search = value.substring(0, Math.min(200, value.length())); + int pos = search.indexOf(";base64,"); + if (!search.startsWith("data:") || pos == -1) { + throw new SQLException("Input data is not encoded in base64!"); + } + return super.formatInput(value.substring(pos + 8)); + } + + @Override + String formatOutput(String value) { + String mime = magicBytesToMimeType.entrySet() + .stream() + .filter(kv -> value.startsWith(kv.getKey())) + .map(Map.Entry::getValue) + .findFirst() + .orElse("application/octet-stream"); + return "data:" + mime + ";base64," + value; + } + + @Override + public void init(Mapping mapping, SQLFeatureStore fs) { + super.init(mapping, fs); + if (mapping.getConverter() == null) { + return; + } + for (CustomConverterJAXB.Param p : mapping.getConverter().getParam()) { + if (p.getName() != null && p.getName().toLowerCase().startsWith("magic-") && p.getName().length() > 7) { + addImageMapping(p.getName().substring(6), p.getValue()); + } + } + } + +} diff --git a/deegree-datastores/deegree-featurestores/deegree-featurestore-sql/src/main/java/org/deegree/feature/persistence/sql/converter/CharacterPrimitiveConverter.java b/deegree-datastores/deegree-featurestores/deegree-featurestore-sql/src/main/java/org/deegree/feature/persistence/sql/converter/CharacterPrimitiveConverter.java new file mode 100644 index 0000000000..d1acf2fd0a --- /dev/null +++ b/deegree-datastores/deegree-featurestores/deegree-featurestore-sql/src/main/java/org/deegree/feature/persistence/sql/converter/CharacterPrimitiveConverter.java @@ -0,0 +1,117 @@ +/*---------------------------------------------------------------------------- + This file is part of deegree, http://deegree.org/ + Copyright (C) 2001-2024 by: + - Department of Geography, University of Bonn - + and + - lat/lon GmbH - + and + - grit graphische Informationstechnik Beratungsgesellschaft mbH - + + This library is free software; you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License as published by the Free + Software Foundation; either version 2.1 of the License, or (at your option) + any later version. + This library is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + details. + You should have received a copy of the GNU Lesser General Public License + along with this library; if not, write to the Free Software Foundation, Inc., + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Contact information: + + grit graphische Informationstechnik Beratungsgesellschaft mbH + Landwehrstr. 143, 59368 Werne + Germany + https://www.grit.de/ + + lat/lon GmbH + Aennchenstr. 19, 53177 Bonn + Germany + http://lat-lon.de/ + + Department of Geography, University of Bonn + Prof. Dr. Klaus Greve + Postfach 1147, 53001 Bonn + Germany + http://www.geographie.uni-bonn.de/deegree/ + + e-mail: info@deegree.org + ----------------------------------------------------------------------------*/ +package org.deegree.feature.persistence.sql.converter; + +import static org.slf4j.LoggerFactory.getLogger; + +import java.io.IOException; +import java.io.Reader; +import java.io.StringReader; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.SQLFeatureNotSupportedException; +import java.sql.Types; +import org.apache.commons.io.IOUtils; +import org.deegree.commons.tom.primitive.PrimitiveValue; +import org.deegree.feature.persistence.sql.SQLFeatureStore; +import org.deegree.feature.persistence.sql.rules.Mapping; +import org.slf4j.Logger; + +/** + * Converts large character type database columns from/to primitive strings + *

+ * Note that the maximum length of allowed data is limited to prevent Denial of Service + * Attacks. The allowed maximum length can be set through the max-length parameter in + * bytes (see {@link AbstractStringPrimitiveConverter#init(Mapping, SQLFeatureStore)}). + *

+ * + * @author Stephan Reichhelm + */ +public class CharacterPrimitiveConverter extends AbstractStringPrimitiveConverter { + + private static final Logger LOG = getLogger(CharacterPrimitiveConverter.class); + + public CharacterPrimitiveConverter() { + super(Types.CLOB); + } + + @Override + public PrimitiveValue toParticle(ResultSet rs, int colIndex) throws SQLException { + try (Reader rdr = rs.getCharacterStream(colIndex)) { + if (rdr == null) { + return null; + } + return new PrimitiveValue(IOUtils.toString(rdr), pt); + } + catch (IOException ioe) { + LOG.trace("Exception", ioe); + throw new SQLException("Failed to read CLOB: " + ioe.getMessage()); + } + } + + @Override + public void setParticle(PreparedStatement stmt, PrimitiveValue particle, int paramIndex) throws SQLException { + final String val; + if (particle.getValue() != null) { + val = particle.getValue().toString(); + } + else { + val = null; + } + if (val == null) { + try { + stmt.setNull(paramIndex, sqlType); + } + catch (SQLFeatureNotSupportedException ignored) { + stmt.setString(paramIndex, null); + } + } + else if (val.length() > maxLen) { + throw new SQLException("Maximum length of " + maxLen + " bytes exceeded."); + } + else { + stmt.setCharacterStream(paramIndex, new StringReader(val), val.length()); + } + } + +} diff --git a/deegree-services/deegree-webservices-handbook/src/main/asciidoc/appendix.adoc b/deegree-services/deegree-webservices-handbook/src/main/asciidoc/appendix.adoc index df3edadcba..909a6e1a86 100644 --- a/deegree-services/deegree-webservices-handbook/src/main/asciidoc/appendix.adoc +++ b/deegree-services/deegree-webservices-handbook/src/main/asciidoc/appendix.adoc @@ -92,4 +92,54 @@ This chapter is only intended as an entry point to make it easier to reach these |org.deegree.services.wms.controller.plugins.GetFeatureInfoProvider |org.deegree.services.wms.controller.plugins.DefaultGetFeatureInfoProvider |0..1 -|=== \ No newline at end of file +|=== + +[[anchor-appendix-customconverter]] +=== Custom converters for the SQL feature store + +Custom converters provide an extension point for plugins to provide a specialized DB-to-ObjectModel converter implementation. + +The configuration is not defined as an XML schema, but consists of the specification of the class and an optional list of parameters, +which in turn consist of keys and values. + +A configuration might look something like this: + +[source,xml] +---- + + RED + 42 + +---- + +The following table lists converter that are already available for use or as a reference. + +[width="100%",cols="35%,15%,40%",options="header",] +|=== +|Class |Parameter |Description + +|org.deegree.feature.persistence.sql.converter.BinaryBase64PrimitiveConverter | |Converts binary database columns from/to primitive strings encoded as Base64 (RFC 4648) +| |max-length |The maximum length of allowed data is limited to prevent Denial of Service Attacks. Specified in bytes and defaults to 256 MiB. + +|org.deegree.feature.persistence.sql.converter.BinaryDataUrlPrimitiveConverter | |Converts binary database columns from/to primitive strings encoded as data URL (RFC 2397) +| |max-length |The maximum length of allowed data is limited to prevent Denial of Service Attacks. Specified in bytes and defaults to 256 MiB. +| |magic-XX |Mime type for records which data start with the magic numbers (`XX`) encoded as a hexadecimal value. The converter contains some common magic numbers for PNG, JPEG and GIF. + +|org.deegree.feature.persistence.sql.converter.CharacterPrimitiveConverter | |Converts large character type database columns from/to primitive strings +| |max-length |The maximum length of allowed data is limited to prevent Denial of Service Attacks. Specified in bytes and defaults to 256 MiB. + +|=== + +Here's an example: + +[source,xml] +---- + + + + + image/bmp + + + +---- \ No newline at end of file diff --git a/deegree-services/deegree-webservices-handbook/src/main/asciidoc/featurestores.adoc b/deegree-services/deegree-webservices-handbook/src/main/asciidoc/featurestores.adoc index ca19fbf0a4..c1fc322502 100644 --- a/deegree-services/deegree-webservices-handbook/src/main/asciidoc/featurestores.adoc +++ b/deegree-services/deegree-webservices-handbook/src/main/asciidoc/featurestores.adoc @@ -908,7 +908,7 @@ __ and __: |__ |0..1 |Complex |Defines a change in the table context -|__ |0..1 |Complex |Plugs-in a specialized +|__ |0..1 |Complex |Plug-ins a specialized DB-to-ObjectModel converter implementation |__ |0..1 |Complex |CRS of stored geometries and database @@ -920,6 +920,10 @@ special chars from this charset in the mapping (e.g. the property Straße can be stored in the column 'strasse' or 'straße'). Required is that the database supports UTF-8 as well. +NOTE: Since __ plug-ins require specific knowledge about +the used database, drivers and configuration, these are described in the +appendix at <>. + ==== Mapping GML application schemas The former section assumed a mapping configuration that didn't use a