001: /*
002: * Geotools2 - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2002, Geotools Project Managment Committee (PMC)
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation;
009: * version 2.1 of the License.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: *
016: */
017: package org.geotools.data.geometryless.wrapper;
018:
019: import java.sql.SQLException;
020: import java.util.Enumeration;
021: import java.util.Properties;
022: import java.util.logging.Logger;
023:
024: //import javax.sql.ConnectionPoolDataSource;
025:
026: /**
027: * <p>
028: * Wraps a Postgres ConnectionPoolDataSource implementation to support the setURL()
029: * method
030: * </p>
031: * <p>
032: * The jdbc3 8.0x driver includes org.postgresql.jdbc2.optional.ConnectionPool,
033: * which wrappers org.postgresql.ds.PGConnectionPool, so you could use that as
034: * the extension class for 8.0x driver, ie instead of
035: * org.postgresql.jdbc2.optional.ConnectionPool, but it does't really matter,
036: * however that's why this class has the name it has
037: * </p>
038: * <p>
039: * in info.xml, you need to set <parameter name="driver" value=
040: * "org.geotools.data.geometryless.wrapper.PGConnectionPool"/>
041: * </p>
042: *
043: * @author Rob Atkinson rob@socialchange.net.NOSPAM.au
044: * @author Peter Barrs@socialchange.net.NOSPAM.au
045: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/unsupported/geometryless/src/main/java/org/geotools/data/geometryless/wrapper/PGConnectionPool.java $
046: */
047: public class PGConnectionPool extends
048: org.postgresql.jdbc2.optional.ConnectionPool {
049:
050: /**
051: *
052: */
053: private static final long serialVersionUID = -1157879368880510850L;
054:
055: /** Standard logging instance */
056: private static final Logger LOGGER = org.geotools.util.logging.Logging
057: .getLogger("org.geotools.data.geometryless");
058:
059: //private ConnectionPoolDataSource _nativePool;
060:
061: /** Creates configuration-driven JDBC driver class. */
062:
063: private String _dbURL;
064:
065: //private String _username = "";
066:
067: //private String _password = "";
068:
069: /**
070: * Sets the JDBC database login credentials.
071: *
072: * @param complete
073: * JDBC connectionURL
074: */
075: public void setURL(String dbURL) throws SQLException {
076:
077: _dbURL = dbURL;
078: try {
079: // _nativePool.getClass().getMethod("setURL", new Class [] {
080: // String.class } ).invoke( _nativePool, new Object [] { _dbURL } );
081: Properties props = parseURL(_dbURL, new Properties());
082:
083: LOGGER.finer("setting ServerName = "
084: + props.getProperty("ServerName"));
085: setServerName(props.getProperty("ServerName"));
086:
087: if (props.getProperty("PortNumber") != null
088: || !props.getProperty("PortNumber").equals("")) {
089: LOGGER.finer("setting ServerName = "
090: + props.getProperty("PortNumber"));
091: setPortNumber(Integer.parseInt(props
092: .getProperty("PortNumber")));
093: }
094:
095: LOGGER.finer("setting DatabaseName = "
096: + props.getProperty("DatabaseName"));
097: setDatabaseName(props.getProperty("DatabaseName"));
098:
099: } catch (Exception e) {
100: LOGGER
101: .severe("Failed to instantiate connection pool using "
102: + _dbURL);
103: throw new SQLException(
104: "Failed to instantiate connection pool using "
105: + _dbURL + "(" + e + ")");
106: }
107: }
108:
109: /**
110: * Parse the driver URL and extract the properties.
111: *
112: * @param url
113: * The URL to parse.
114: * @param info
115: * Any existing properties already loaded in a Properties object.
116: * @return The URL properties as a <code>Properties</code> object.
117: */
118: private static Properties parseURL(String url, Properties info) {
119: Properties props = new Properties();
120:
121: // Take local copy of existing properties
122: for (Enumeration e = info.keys(); e.hasMoreElements();) {
123: String key = (String) e.nextElement();
124: String value = info.getProperty(key);
125:
126: if (value != null) {
127: props.setProperty(key.toUpperCase(), value);
128: }
129: }
130:
131: StringBuffer token = new StringBuffer(128);
132: int pos = 0;
133:
134: pos = nextToken(url, pos, token);
135: // LOGGER.fine(token.toString());
136:
137: if (!token.toString().equalsIgnoreCase("jdbc")) {
138: LOGGER.severe("expected token jdbc in urlprefix " + url);
139: return null; // jdbc: missing
140: }
141:
142: pos = nextToken(url, pos, token); // Skip jtds
143: // LOGGER.fine(token.toString());
144:
145: if (!token.toString().equalsIgnoreCase("postgresql")) {
146: LOGGER.severe("expected token postgresql in urlprefix "
147: + url);
148: return null; // postgresql: missing
149: }
150:
151: pos = nextToken(url, pos, token); // Null token between : and //
152: if (token.length() > 0) {
153: LOGGER
154: .severe("There should be no token between : and // in urlprefix "
155: + url);
156: return null; // There should not be one!
157: }
158:
159: pos = nextToken(url, pos, token); // Get server name
160: // LOGGER.fine(token.toString());
161:
162: String host = token.toString();
163: if (host == null || host.length() == 0) {
164: LOGGER.severe("Missing server (host) name in urlprefix "
165: + url);
166: return null; // Server name missing
167: }
168: props.setProperty("ServerName", host);
169:
170: if (url.charAt(pos - 1) == ':' && pos < url.length()) {
171: pos = nextToken(url, pos, token); // Get port number
172: // LOGGER.fine(token.toString());
173:
174: try {
175: int port = Integer.parseInt(token.toString());
176: props.setProperty("PortNumber", Integer.toString(port));
177: } catch (NumberFormatException e) {
178: LOGGER.severe("Bad port number in urlprefix " + url);
179: return null; // Bad port number
180: }
181: }
182:
183: if (url.charAt(pos - 1) == '/' && pos < url.length()) {
184: pos = nextToken(url, pos, token); // Get database name
185: // LOGGER.fine(token.toString());
186: props.setProperty("DatabaseName", token.toString());
187: }
188:
189: //
190: // Process any additional properties in URL
191: //
192:
193: // but we ignore anyway - pb
194: /*
195: while (url.charAt(pos - 1) == ';' && pos < url.length()) {
196: pos = nextToken(url, pos, token);
197: String tmp = token.toString();
198: int index = tmp.indexOf('=');
199:
200: if (index > 0 && index < tmp.length() - 1) {
201: props.setProperty(tmp.substring(0, index).toUpperCase(), tmp
202: .substring(index + 1));
203: } else {
204: props.setProperty(tmp.toUpperCase(), "");
205: }
206: }
207: */
208: return props;
209: }
210:
211: /**
212: * Extract the next lexical token from the URL.
213: *
214: * @param url
215: * The URL being parsed
216: * @param pos
217: * The current position in the URL string.
218: * @param token
219: * The buffer containing the extracted token.
220: * @return The updated position as an <code>int</code>.
221: */
222: private static int nextToken(String url, int pos, StringBuffer token) {
223: token.setLength(0);
224:
225: while (pos < url.length()) {
226: char ch = url.charAt(pos++);
227:
228: if (ch == ':' || ch == ';') {
229: break;
230: }
231:
232: if (ch == '/') {
233: if (pos < url.length() && url.charAt(pos) == '/') {
234: pos++;
235: }
236:
237: break;
238: }
239:
240: token.append(ch);
241: }
242:
243: return pos;
244: }
245:
246: }
|