001: /* Copyright (c) 2001-2005, The HSQL Development Group
002: * All rights reserved.
003: *
004: * Redistribution and use in source and binary forms, with or without
005: * modification, are permitted provided that the following conditions are met:
006: *
007: * Redistributions of source code must retain the above copyright notice, this
008: * list of conditions and the following disclaimer.
009: *
010: * Redistributions in binary form must reproduce the above copyright notice,
011: * this list of conditions and the following disclaimer in the documentation
012: * and/or other materials provided with the distribution.
013: *
014: * Neither the name of the HSQL Development Group nor the names of its
015: * contributors may be used to endorse or promote products derived from this
016: * software without specific prior written permission.
017: *
018: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
019: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
020: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
021: * ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG,
022: * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
023: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
024: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
025: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
026: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
027: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
028: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
029: */
030:
031: package org.hsqldb;
032:
033: import java.util.Locale;
034:
035: import org.hsqldb.persist.HsqlProperties;
036:
037: /*
038: * Parses a connection URL into parts.
039: *
040: * @author fredt@users
041: * @version 1.8.0
042: * @since 1.8.0
043: */
044: public class DatabaseURL {
045:
046: static final String S_DOT = ".";
047: public static final String S_MEM = "mem:";
048: public static final String S_FILE = "file:";
049: public static final String S_RES = "res:";
050: public static final String S_ALIAS = "alias:";
051: public static final String S_HSQL = "hsql://";
052: public static final String S_HSQLS = "hsqls://";
053: public static final String S_HTTP = "http://";
054: public static final String S_HTTPS = "https://";
055: public static final String S_URL_PREFIX = "jdbc:hsqldb:";
056:
057: /**
058: * Returns true if type represents an in-process connection to a file backed
059: * database.
060: */
061: public static boolean isFileBasedDatabaseType(String url) {
062:
063: if (url == S_FILE || url == S_RES) {
064: return true;
065: }
066:
067: return false;
068: }
069:
070: /**
071: * Returns true if type represents an in-process connection to database.
072: */
073: public static boolean isInProcessDatabaseType(String url) {
074:
075: if (url == S_FILE || url == S_RES || url == S_MEM) {
076: return true;
077: }
078:
079: return false;
080: }
081:
082: /**
083: * Parses the url into components that are returned in a properties
084: * object. <p>
085: *
086: * The following components are isolated: <p>
087: *
088: * <ul>
089: * url: the original url<p>
090: * connection_type: a static string that indicate the protocol. If the
091: * url does not begin with a valid protocol, null is returned by this
092: * method instead of the properties object.<p>
093: * host: name of host in networked modes in lowercase<p>
094: * port: port number in networked mode, or 0 if not present<p>
095: * path: path of the resource on server in networked modes,
096: * / (slash) in all cases apart from
097: * servlet path which is / (slash) plus the name of the servlet<p>
098: * database: database name. For memory, resource and networked modes,
099: * this is returned in lowercase, for file databases the original
100: * case of characters is preserved. Returns empty string if name is not
101: * present in the url.<p>
102: * for each protocol if port number is not in the url<p>
103: * Additional connection properties specified as key/value pairs.
104: * </ul>
105: * @return null returned if the part that should represent the port is not
106: * an integer or the part for database name is empty.
107: * Empty HsqlProperties returned if if url does not begin with valid
108: * protocol and could refer to another JDBC driver.
109: *
110: */
111: public static HsqlProperties parseURL(String url, boolean hasPrefix) {
112:
113: String urlImage = url.toLowerCase(Locale.ENGLISH);
114: HsqlProperties props = new HsqlProperties();
115: HsqlProperties extraProps = null;
116: String arguments = null;
117: int pos = 0;
118:
119: if (hasPrefix) {
120: if (urlImage.startsWith(S_URL_PREFIX)) {
121: pos = S_URL_PREFIX.length();
122: } else {
123: return props;
124: }
125: }
126:
127: String type = null;
128: String host;
129: int port = 0;
130: String database;
131: String path;
132: boolean isNetwork = false;
133:
134: props.setProperty("url", url);
135:
136: int semicolpos = url.indexOf(';', pos);
137:
138: if (semicolpos < 0) {
139: semicolpos = url.length();
140: } else {
141: arguments = urlImage.substring(semicolpos + 1, urlImage
142: .length());
143: extraProps = HsqlProperties.delimitedArgPairsToProps(
144: arguments, "=", ";", null);
145:
146: //todo - check if properties have valid names / values
147: props.addProperties(extraProps);
148: }
149:
150: if (semicolpos == pos + 1 && urlImage.startsWith(S_DOT, pos)) {
151: type = S_DOT;
152: } else if (urlImage.startsWith(S_MEM, pos)) {
153: type = S_MEM;
154: } else if (urlImage.startsWith(S_FILE, pos)) {
155: type = S_FILE;
156: } else if (urlImage.startsWith(S_RES, pos)) {
157: type = S_RES;
158: } else if (urlImage.startsWith(S_ALIAS, pos)) {
159: type = S_ALIAS;
160: } else if (urlImage.startsWith(S_HSQL, pos)) {
161: type = S_HSQL;
162: port = ServerConstants.SC_DEFAULT_HSQL_SERVER_PORT;
163: isNetwork = true;
164: } else if (urlImage.startsWith(S_HSQLS, pos)) {
165: type = S_HSQLS;
166: port = ServerConstants.SC_DEFAULT_HSQLS_SERVER_PORT;
167: isNetwork = true;
168: } else if (urlImage.startsWith(S_HTTP, pos)) {
169: type = S_HTTP;
170: port = ServerConstants.SC_DEFAULT_HTTP_SERVER_PORT;
171: isNetwork = true;
172: } else if (urlImage.startsWith(S_HTTPS, pos)) {
173: type = S_HTTPS;
174: port = ServerConstants.SC_DEFAULT_HTTPS_SERVER_PORT;
175: isNetwork = true;
176: }
177:
178: if (type == null) {
179: type = S_FILE;
180: } else if (type == S_DOT) {
181: type = S_MEM;
182:
183: // keep pos
184: } else {
185: pos += type.length();
186: }
187:
188: props.setProperty("connection_type", type);
189:
190: if (isNetwork) {
191: int slashpos = url.indexOf('/', pos);
192:
193: if (slashpos < pos || slashpos > semicolpos) {
194: slashpos = semicolpos;
195: }
196:
197: int colonpos = url.indexOf(':', pos);
198:
199: if (colonpos < pos || colonpos > slashpos) {
200: colonpos = slashpos;
201: } else {
202: try {
203: port = Integer.parseInt(url.substring(colonpos + 1,
204: slashpos));
205: } catch (NumberFormatException e) {
206: return null;
207: }
208: }
209:
210: host = urlImage.substring(pos, colonpos);
211:
212: int secondslashpos = url.lastIndexOf('/', semicolpos);
213:
214: if (secondslashpos < pos) {
215: path = "/";
216: database = "";
217: } else if (secondslashpos == slashpos) {
218: path = "/";
219: database = urlImage.substring(secondslashpos + 1,
220: semicolpos);
221: } else {
222: path = url.substring(slashpos, secondslashpos);
223: database = urlImage.substring(secondslashpos + 1,
224: semicolpos);
225: }
226:
227: props.setProperty("port", port);
228: props.setProperty("host", host);
229: props.setProperty("path", path);
230:
231: if (extraProps != null) {
232: String filePath = extraProps.getProperty("filepath");
233:
234: if (filePath != null && database.length() != 0) {
235: database += ";" + filePath;
236: }
237: }
238: } else {
239: if (type == S_MEM || type == S_RES) {
240: database = urlImage.substring(pos, semicolpos)
241: .toLowerCase();
242:
243: if (type == S_RES) {
244: if (database.indexOf('/') != 0) {
245: database = '/' + database;
246: }
247: }
248: } else {
249: database = url.substring(pos, semicolpos);
250: }
251:
252: if (database.length() == 0) {
253: return null;
254: }
255: }
256:
257: props.setProperty("database", database);
258:
259: return props;
260: }
261: /*
262: public static void main(String[] argv) {
263:
264: parseURL(
265: "JDBC:hsqldb:hsql://myhost:1777/mydb;filepath=c:/myfile/database/db",
266: true);
267: parseURL("JDBC:hsqldb:../data/mydb.db", true);
268: parseURL("JDBC:hsqldb:../data/mydb.db;ifexists=true", true);
269: parseURL("JDBC:hsqldb:HSQL://localhost:9000/mydb", true);
270: parseURL(
271: "JDBC:hsqldb:Http://localhost:8080/servlet/org.hsqldb.Servlet/mydb;ifexists=true",
272: true);
273: parseURL("JDBC:hsqldb:Http://localhost/servlet/org.hsqldb.Servlet/",
274: true);
275: parseURL("JDBC:hsqldb:hsql://myhost", true);
276: }
277: */
278: }
|