# HG changeset patch # User Tom Gottfried # Date 1590223043 -7200 # Node ID b70b1bc0eecec2f760862da90a6f247d8f63c757 # Parent 9cfc495a9f40b1a64d58c609076be47a8f2e1cc3 Essentially rewrite MapUtils.getConnection() to cope with driver capabilities diff -r 9cfc495a9f40 -r b70b1bc0eece artifacts/src/main/java/org/dive4elements/river/utils/MapUtils.java --- 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"); diff -r 9cfc495a9f40 -r b70b1bc0eece artifacts/src/test/java/org/dive4elements/river/utils/MapUtilsTest.java --- 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); + } }