All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.hsqldb.DatabaseURL Maven / Gradle / Ivy

There is a newer version: 2.7.4
Show newest version
/* Copyright (c) 2001-2021, The HSQL Development Group
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 *
 * Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * Neither the name of the HSQL Development Group nor the names of its
 * contributors may be used to endorse or promote products derived from this
 * software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG,
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */


package org.hsqldb;

import java.util.Locale;

import org.hsqldb.persist.HsqlProperties;
import org.hsqldb.server.ServerConstants;

/*
 * Parses a connection URL into parts.
 *
 * @author Fred Toussi (fredt@users dot sourceforge.net)
 * @version 2.5.0
 * @since 1.8.0
 */

// patch 1.9.0 by Blaine Simpson - IPv6 support
public final class DatabaseURL {

    public static final String S_DOT               = ".";
    public static final String S_MEM               = "mem:";
    public static final String S_FILE              = "file:";
    public static final String S_RES               = "res:";
    public static final String S_ALIAS             = "alias:";
    public static final String S_HSQL              = "hsql://";
    public static final String S_HSQLS             = "hsqls://";
    public static final String S_HTTP              = "http://";
    public static final String S_HTTPS             = "https://";
    public static final String S_URL_PREFIX        = "jdbc:hsqldb:";
    public static final String S_URL_INTERNAL      = "jdbc:default:connection";
    public static final String url_connection_type = "connection_type";
    public static final String url_database        = "database";

    /**
     * Returns true if type represents an in-process connection to database.
     */
    public static boolean isInProcessDatabaseType(String type) {

        if (S_FILE.equals(type) || S_RES.equals(type) || S_MEM.equals(type)) {
            return true;
        }
        return false;
    }

    /**
     * Parses the url into components that are returned in a properties object.
     *
     * The following components are isolated:

* * url: the original url *

    * *
  • connection_type: a static string that indicate the protocol. If the * url does not begin with a valid protocol, null is returned by this method * instead of the properties object. * *
  • host: name of host in networked modes in lowercase * *
  • port: port number in networked mode, or 0 if not present * *
  • path: path of the resource on server in networked modes, minimum * (slash) with path elements appended apart from servlet path which is * (slash) plus the name of the servlet * *
  • database: database name. For memory, networked modes, * this is returned in lowercase, for file: and res: databases the original case of * characters is preserved. Returns empty string if name is not present in * the url. * *
  • Additional connection properties specified as key/value pairs. *
* * @return null returned if the part that should represent the port is not * an integer or the part for database name is empty. Empty * HsqlProperties returned if if url does not begin with valid protocol * and could refer to another JDBC driver. * @param url String * @param hasPrefix indicates URL prefix is present * @param noPath indicates empty path and verbatim use of path elements as * database */ public static HsqlProperties parseURL(String url, boolean hasPrefix, boolean noPath) { String urlImage = url.toLowerCase(Locale.ENGLISH); HsqlProperties props = new HsqlProperties(); HsqlProperties extraProps = null; String arguments = null; int pos = 0; String type = null; int port = 0; String database; String path; boolean isNetwork = false; if (hasPrefix) { if (urlImage.startsWith(S_URL_PREFIX)) { pos = S_URL_PREFIX.length(); } else { return props; } } while (true) { int replacePos = url.indexOf("${"); if (replacePos == -1) { break; } int endPos = url.indexOf("}", replacePos); if (endPos == -1) { break; } String varName = url.substring(replacePos + 2, endPos); String varValue = null; try { varValue = System.getProperty(varName); } catch (SecurityException e) {} if (varValue == null) { break; } url = url.substring(0, replacePos) + varValue + url.substring(endPos + 1); urlImage = url.toLowerCase(Locale.ENGLISH); } props.setProperty("url", url); int postUrlPos = url.length(); // postUrlPos is the END position in url String, // wrt what remains to be processed. // I.e., if postUrlPos is 100, url no longer needs to examined at // index 100 or later. int semiPos = url.indexOf(';', pos); if (semiPos > -1) { arguments = url.substring(semiPos + 1, urlImage.length()); postUrlPos = semiPos; extraProps = HsqlProperties.delimitedArgPairsToProps(arguments, "=", ";", null); // validity checks are performed by engine props.addProperties(extraProps); } if (postUrlPos == pos + 1 && urlImage.startsWith(S_DOT, pos)) { type = S_DOT; } else if (urlImage.startsWith(S_MEM, pos)) { type = S_MEM; } else if (urlImage.startsWith(S_FILE, pos)) { type = S_FILE; } else if (urlImage.startsWith(S_RES, pos)) { type = S_RES; } else if (urlImage.startsWith(S_ALIAS, pos)) { type = S_ALIAS; } else if (urlImage.startsWith(S_HSQL, pos)) { type = S_HSQL; port = ServerConstants.SC_DEFAULT_HSQL_SERVER_PORT; isNetwork = true; } else if (urlImage.startsWith(S_HSQLS, pos)) { type = S_HSQLS; port = ServerConstants.SC_DEFAULT_HSQLS_SERVER_PORT; isNetwork = true; } else if (urlImage.startsWith(S_HTTP, pos)) { type = S_HTTP; port = ServerConstants.SC_DEFAULT_HTTP_SERVER_PORT; isNetwork = true; } else if (urlImage.startsWith(S_HTTPS, pos)) { type = S_HTTPS; port = ServerConstants.SC_DEFAULT_HTTPS_SERVER_PORT; isNetwork = true; } if (type == null) { type = S_FILE; } else if (type == S_DOT) { type = S_MEM; // keep pos } else { pos += type.length(); } props.setProperty("connection_type", type); if (isNetwork) { // First capture 3 segments: host + port + path String pathSeg = null; String hostSeg = null; String portSeg = null; int endPos = url.indexOf('/', pos); if (endPos > 0 && endPos < postUrlPos) { pathSeg = url.substring(endPos, postUrlPos); // N.b. pathSeg necessarily begins with /. } else { endPos = postUrlPos; } // Processing different for ipv6 host address and all others: if (url.charAt(pos) == '[') { // ipv6 int endIpv6 = url.indexOf(']', pos + 2); // Notice 2 instead of 1 to require non-empty addr segment if (endIpv6 < 0 || endIpv6 >= endPos) { return null; // Wish could throw something with a useful message for user // here. } hostSeg = urlImage.substring(pos + 1, endIpv6); if (endPos > endIpv6 + 1) { portSeg = url.substring(endIpv6 + 1, endPos); } } else { // non-ipv6 int colPos = url.indexOf(':', pos + 1); if (colPos > -1 && colPos < endPos) { // portSeg will be non-empty, but could contain just ":" portSeg = url.substring(colPos, endPos); } else { colPos = -1; } hostSeg = urlImage.substring(pos, (colPos > 0) ? colPos : endPos); } // At this point, the entire url has been parsed into // hostSeg + portSeg + pathSeg. if (portSeg != null) { if (portSeg.length() < 2 || portSeg.charAt(0) != ':') { // Wish could throw something with a useful message for user // here. return null; } try { port = Integer.parseInt(portSeg.substring(1)); } catch (NumberFormatException e) { // System.err.println("NFE for (" + portSeg + ')'); debug return null; } } if (noPath) { path = ""; database = pathSeg; } else if (pathSeg == null) { path = "/"; database = ""; } else { int lastSlashPos = pathSeg.lastIndexOf('/'); if (lastSlashPos < 1) { path = "/"; database = pathSeg.substring(1).toLowerCase(Locale.ENGLISH); } else { path = pathSeg.substring(0, lastSlashPos); database = pathSeg.substring(lastSlashPos + 1); } } /* Just for debug. Remove once stable: System.err.println("Host seg (" + hostSeg + "), Port val (" + port + "), Path val (" + pathSeg + "), path (" + path + "), db (" + database + ')'); */ props.setProperty("port", port); props.setProperty("host", hostSeg); props.setProperty("path", path); if (!noPath && extraProps != null) { String filePath = extraProps.getProperty("filepath"); if (filePath != null && database.length() != 0) { database += ";" + filePath; } else { if (url.indexOf(S_MEM) == postUrlPos + 1 || url.indexOf(S_FILE) == postUrlPos + 1) { database += url.substring(postUrlPos); } } } } else { if (type == S_MEM) { database = urlImage.substring(pos, postUrlPos); } else if (type == S_RES) { database = url.substring(pos, postUrlPos); if (database.indexOf('/') != 0) { database = '/' + database; } } else { database = url.substring(pos, postUrlPos); if (database.startsWith("~")) { String userHome = "~"; try { userHome = System.getProperty("user.home"); } catch (SecurityException e) {} database = userHome + database.substring(1); } } if (database.isEmpty()) { return null; } } pos = database.indexOf("&password="); if (pos != -1) { String password = database.substring(pos + "&password=".length()); props.setProperty("password", password); database = database.substring(0, pos); } pos = database.indexOf("?user="); if (pos != -1) { String user = database.substring(pos + "?user=".length()); props.setProperty("user", user); database = database.substring(0, pos); } props.setProperty("database", database); return props; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy