changeset 9672:b70b1bc0eece 3.2.x

Essentially rewrite MapUtils.getConnection() to cope with driver capabilities
author Tom Gottfried <tom@intevation.de>
date Sat, 23 May 2020 10:37:23 +0200
parents 9cfc495a9f40
children e04851177bb7
files artifacts/src/main/java/org/dive4elements/river/utils/MapUtils.java artifacts/src/test/java/org/dive4elements/river/utils/MapUtilsTest.java
diffstat 2 files changed, 150 insertions(+), 35 deletions(-) [+]
line wrap: on
line diff
--- a/artifacts/src/main/java/org/dive4elements/river/utils/MapUtils.java	Fri May 22 19:45:08 2020 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/utils/MapUtils.java	Sat May 23 10:37:23 2020 +0200
@@ -1,4 +1,4 @@
-/* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde
+/* Copyright (C) 2011, 2012, 2013, 2020 by Bundesanstalt für Gewässerkunde
  * Software engineering by Intevation GmbH
  *
  * This file is Free Software under the GNU AGPL (>=v3)
@@ -8,8 +8,8 @@
 
 package org.dive4elements.river.utils;
 
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
+import java.net.URI;
+import java.net.URISyntaxException;
 
 import org.apache.log4j.Logger;
 import org.hibernate.impl.SessionFactoryImpl;
@@ -21,8 +21,10 @@
 {
     private static final Logger log = Logger.getLogger(MapUtils.class);
 
-    public static final Pattern DB_URL_PATTERN =
-        Pattern.compile("(.*)\\/\\/(.*):([0-9]+)\\/([\\.a-zA-Z0-9_-]+)");
+    private static final String JDBC_SCHEME = "^jdbc:";
+
+    private static final String JDBC_DRV_PATTERN =
+        JDBC_SCHEME + "(postgresql|oracle:(thin|oci)):.*";
 
     /**
      * This method returns a connection string for databases used by
@@ -42,56 +44,83 @@
     }
 
     public static String getConnection(String user, String pass, String url) {
-        log.debug("Parse connection url: " + url);
+        log.info("Parse connection string: " + url);
 
-        Matcher m = DB_URL_PATTERN.matcher(url);
-        if (!m.matches()) {
-            log.warn("Could not parse Connection string");
+        if (!url.matches(JDBC_DRV_PATTERN)) {
+            log.error("Could not parse connection string: "
+                + "Not a JDBC URL with PostgreSQL or Oracle driver");
             return null;
         }
 
-        int groups = m.groupCount();
-
-        if (log.isDebugEnabled()) {
-            for (int i = 0; i <= groups; i++) {
-                log.debug("Group " + i + ": " + m.group(i));
-            }
+        URI uri = null;
+        try {
+            // Strip JDBC_SCHEME to let the driver be parsed as scheme
+            uri = new URI(url.replaceFirst(JDBC_SCHEME, ""));
         }
-
-        String connection = null;
-
-        if (groups < 4) {
-            log.warn("Could only partially parse connection string.");
+        catch (URISyntaxException e) {
+            log.error("Could not parse connection string: " + e.getMessage());
             return null;
         }
 
-        String host = m.group(2);
-        String port = m.group(3);
-        String db   = m.group(4);
+        String drv = uri.getScheme();
+        log.debug("Driver: " + drv);
 
-        if (url.startsWith("jdbc:oracle:")) {
-            connection = user + "/" + pass
-                + "@" + host + ":" + port + "/" + db;
+        String connection = null;
+        if (drv.equals("oracle")) {
+            try {
+                // Work-around the extra colon in the driver part of the scheme
+                String con = new URI(uri.getSchemeSpecificPart())
+                    .getSchemeSpecificPart().replaceFirst("^@(//)?", "");
+                log.debug("Database specifier: " + con);
+                connection = user + "/" + pass + "@" + con;
+            }
+            catch (URISyntaxException e) {
+                log.error("Could not parse Oracle connection string: "
+                    + e.getMessage());
+                return null;
+            }
         }
-        else {
+        else { // assume PostgreSQL
+            String host = uri.getHost();
+            if (host == null && uri.getSchemeSpecificPart().startsWith("//")) {
+                // invalid hostnames (e.g. containing '_') are not parsed!
+                log.error("Could not parse PostgreSQL connection string: "
+                    + "invalid host name");
+                return null;
+            }
+            String db = host == null
+                ? uri.getSchemeSpecificPart()
+                : uri.getPath();
+            int port = uri.getPort();
             connection = createConnectionString(user, pass, host, db, port);
         }
 
         return connection;
     }
 
-    public static String createConnectionString(
+    private static String createConnectionString(
         String user,
         String pass,
         String host,
         String db,
-        String port
+        int port
     ) {
         StringBuilder sb = new StringBuilder();
-        sb.append("dbname=").append(db);
-        sb.append(" host='").append(host).append("'");
+        // Required parameters
+        // defaults to user name in PostgreSQL JDBC:
+        if (db != null) {
+            db = db.replaceFirst("/", "");
+        }
+        sb.append("dbname=").append(db == null || db.equals("") ? user : db);
         sb.append(" user=").append(user);
-        sb.append(" port=").append(port);
+
+        // Optional parameters
+        if (host != null) {
+            sb.append(" host='").append(host).append("'");
+        }
+        if (port != -1) {
+            sb.append(" port=").append(port);
+        }
         // XXX: We need to escape this somehow.
         sb.append(" password='").append(pass).append("'");
         sb.append(" sslmode=disable");
--- a/artifacts/src/test/java/org/dive4elements/river/utils/MapUtilsTest.java	Fri May 22 19:45:08 2020 +0200
+++ b/artifacts/src/test/java/org/dive4elements/river/utils/MapUtilsTest.java	Sat May 23 10:37:23 2020 +0200
@@ -7,6 +7,7 @@
  */
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
 
 import org.junit.Test;
 
@@ -26,24 +27,109 @@
     private static final String PG_CON_SUFFIX = " sslmode=disable";
 
     @Test
+    public void noJDBCURL() {
+        String con = MapUtils.getConnection(USER, PSWD, "xx");
+        assertNull(con);
+    }
+
+    @Test
+    public void invalidHostPG() {
+        String con = MapUtils.getConnection(
+            USER, PSWD, DRV_PG + "//invalid_host_name/");
+        assertNull(con);
+    }
+
+    @Test
+    public void localNamedPG() {
+        String con = MapUtils.getConnection(
+            USER, PSWD, DRV_PG + DB);
+        assertEquals(
+            "dbname=" + DB
+            + " user=" + USER
+            + " password='" + PSWD + "'" + PG_CON_SUFFIX,
+            con);
+    }
+
+    @Test
+    public void localUserPG() {
+        String con = MapUtils.getConnection(
+            USER, PSWD, DRV_PG + "/");
+        assertEquals(
+            "dbname=" + USER
+            + " user=" + USER
+            + " password='" + PSWD + "'" + PG_CON_SUFFIX,
+            con);
+    }
+
+    @Test
+    public void hostNamedPG() {
+        String con = MapUtils.getConnection(
+            USER, PSWD, DRV_PG + "//" + HOST + "/" + DB);
+        assertEquals(
+            "dbname=" + DB
+            + " user=" + USER
+            + " host='" + HOST + "'"
+            + " password='" + PSWD + "'" + PG_CON_SUFFIX,
+            con);
+    }
+
+    @Test
+    public void hostUserPG() {
+        String con = MapUtils.getConnection(
+            USER, PSWD, DRV_PG + "//" + HOST + "/");
+        assertEquals(
+            "dbname=" + USER
+            + " user=" + USER
+            + " host='" + HOST + "'"
+            + " password='" + PSWD + "'" + PG_CON_SUFFIX,
+            con);
+    }
+
+    @Test
+    public void hostPortUserPG() {
+        String con = MapUtils.getConnection(
+            USER, PSWD, DRV_PG + "//" + HOST + ":" + PORT + "/");
+        assertEquals(
+            "dbname=" + USER
+            + " user=" + USER
+            + " host='" + HOST + "' port=" + PORT
+            + " password='" + PSWD + "'" + PG_CON_SUFFIX,
+            con);
+    }
+
+    @Test
     public void hostPortNamedPG() {
-        MapUtils mu = new MapUtils();
         String con = MapUtils.getConnection(
             USER, PSWD, DRV_PG + "//" + HOST + ":" + PORT + "/" + DB);
         assertEquals(
             "dbname=" + DB
-            + " host='" + HOST + "' user=" + USER + " port=" + PORT
+            + " user=" + USER
+            + " host='" + HOST + "' port=" + PORT
             + " password='" + PSWD + "'" + PG_CON_SUFFIX,
             con);
     }
 
     @Test
     public void serviceNameORA() {
-        MapUtils mu = new MapUtils();
         String con = MapUtils.getConnection(
             USER, PSWD, DRV_ORA + "@//" + HOST + ":" + PORT + "/" + DB);
         assertEquals(
             USER + "/" + PSWD + "@" + HOST + ":" + PORT + "/" + DB,
             con);
     }
+
+    @Test
+    public void connectDescriptorORA() {
+        String con = MapUtils.getConnection(
+            USER, PSWD, DRV_ORA
+            + "@(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST="
+            + HOST + ")(PORT=" + PORT + "))(CONNECT_DATA=(SERVICE_NAME="
+            + DB + ")))");
+        assertEquals(
+            USER + "/" + PSWD
+            + "@(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST="
+            + HOST + ")(PORT=" + PORT + "))(CONNECT_DATA=(SERVICE_NAME="
+            + DB + ")))",
+            con);
+    }
 }

http://dive4elements.wald.intevation.org