View Javadoc
1   /*
2    * Copyright (C) 2022 B3Partners B.V.
3    *
4    * SPDX-License-Identifier: MIT
5    */
6   package org.tailormap.api.geotools.featuresources;
7   
8   import static org.geotools.data.sqlserver.SQLServerDataStoreFactory.GEOMETRY_METADATA_TABLE;
9   import static org.geotools.jdbc.JDBCDataStoreFactory.DATABASE;
10  import static org.geotools.jdbc.JDBCDataStoreFactory.DBTYPE;
11  import static org.geotools.jdbc.JDBCDataStoreFactory.EXPOSE_PK;
12  import static org.geotools.jdbc.JDBCDataStoreFactory.FETCHSIZE;
13  import static org.geotools.jdbc.JDBCDataStoreFactory.HOST;
14  import static org.geotools.jdbc.JDBCDataStoreFactory.MAXWAIT;
15  import static org.geotools.jdbc.JDBCDataStoreFactory.PASSWD;
16  import static org.geotools.jdbc.JDBCDataStoreFactory.PK_METADATA_TABLE;
17  import static org.geotools.jdbc.JDBCDataStoreFactory.PORT;
18  import static org.geotools.jdbc.JDBCDataStoreFactory.SCHEMA;
19  import static org.geotools.jdbc.JDBCDataStoreFactory.USER;
20  import static org.tailormap.api.persistence.json.JDBCConnectionProperties.DbtypeEnum.ORACLE;
21  import static org.tailormap.api.persistence.json.JDBCConnectionProperties.DbtypeEnum.POSTGIS;
22  import static org.tailormap.api.persistence.json.JDBCConnectionProperties.DbtypeEnum.SQLSERVER;
23  
24  import java.io.IOException;
25  import java.util.HashMap;
26  import java.util.Map;
27  import java.util.Objects;
28  import java.util.Optional;
29  import org.geotools.api.data.DataStore;
30  import org.geotools.data.postgis.PostgisNGDataStoreFactory;
31  import org.geotools.data.sqlserver.SQLServerDataStoreFactory;
32  import org.tailormap.api.persistence.TMFeatureSource;
33  import org.tailormap.api.persistence.json.JDBCConnectionProperties;
34  import org.tailormap.api.persistence.json.ServiceAuthentication;
35  
36  public class JDBCFeatureSourceHelper extends FeatureSourceHelper {
37    private static final Map<JDBCConnectionProperties.DbtypeEnum, Integer> defaultPorts =
38        Map.of(POSTGIS, 5432, ORACLE, 1521, SQLSERVER, 1433);
39  
40    @Override
41    public DataStore createDataStore(TMFeatureSource tmfs, Integer timeout) throws IOException {
42      if (tmfs.getProtocol() != TMFeatureSource.Protocol.JDBC) {
43        throw new IllegalArgumentException(tmfs.getProtocol().getValue());
44      }
45      Objects.requireNonNull(tmfs.getJdbcConnection());
46      Objects.requireNonNull(tmfs.getAuthentication());
47      if (tmfs.getAuthentication().getMethod() != ServiceAuthentication.MethodEnum.PASSWORD) {
48        throw new IllegalArgumentException(
49            tmfs.getAuthentication().getMethod().getValue());
50      }
51  
52      JDBCConnectionProperties c = tmfs.getJdbcConnection();
53      Objects.requireNonNull(c.getDbtype());
54      String connectionOpts = Optional.ofNullable(c.getAdditionalProperties().get("connectionOptions"))
55          .orElse("");
56  
57      Map<String, Object> params = new HashMap<>();
58      // database specific settings
59      switch (c.getDbtype()) {
60        case POSTGIS:
61          // use spatial index to estimate the extents
62          params.put(PostgisNGDataStoreFactory.ESTIMATED_EXTENTS.key, true);
63          if (!connectionOpts.contains("ApplicationName")) {
64            connectionOpts = connectionOpts + (connectionOpts.contains("?") ? "&amp;" : "?")
65                + "ApplicationName=tailormap-api";
66          }
67          break;
68        case SQLSERVER:
69          // use spatial index to estimate the extents
70          params.put(SQLServerDataStoreFactory.ESTIMATED_EXTENTS.key, true);
71          // we need this for mssql to determine a feature type on an empty table
72          params.put(GEOMETRY_METADATA_TABLE.key, "geometry_columns");
73          if (!connectionOpts.contains("applicationName")) {
74            // see
75            // https://learn.microsoft.com/en-us/sql/connect/jdbc/building-the-connection-url?view=sql-server-ver16
76            connectionOpts = connectionOpts + ";applicationName=tailormap-api";
77          }
78          break;
79        case ORACLE:
80          break;
81      }
82  
83      params.put(DBTYPE.key, c.getDbtype().getValue());
84      params.put(HOST.key, c.getHost());
85      params.put(PORT.key, c.getPort() != null ? c.getPort() : defaultPorts.get(c.getDbtype()));
86      params.put(DATABASE.key, c.getDatabase() + connectionOpts);
87      params.put(SCHEMA.key, c.getSchema());
88      params.put(USER.key, tmfs.getAuthentication().getUsername());
89      params.put(PASSWD.key, tmfs.getAuthentication().getPassword());
90      params.put(FETCHSIZE.key, c.getFetchSize());
91      params.put(EXPOSE_PK.key, true);
92      params.put(PK_METADATA_TABLE.key, c.getPrimaryKeyMetadataTable());
93      params.put(MAXWAIT.key, timeout);
94  
95      return openDatastore(params, PASSWD.key);
96    }
97  }