001 /*
002
003 Derby - Class org.apache.derby.jdbc.ClientDriver
004
005 Copyright (c) 2001, 2005 The Apache Software Foundation or its licensors, where applicable.
006
007 Licensed under the Apache License, Version 2.0 (the "License");
008 you may not use this file except in compliance with the License.
009 You may obtain a copy of the License at
010
011 http://www.apache.org/licenses/LICENSE-2.0
012
013 Unless required by applicable law or agreed to in writing, software
014 distributed under the License is distributed on an "AS IS" BASIS,
015 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016 See the License for the specific language governing permissions and
017 limitations under the License.
018
019 */
020
021 package org.apache.derby.jdbc;
022
023 import org.apache.derby.client.am.Configuration;
024 import org.apache.derby.client.am.ResourceUtilities;
025 import org.apache.derby.client.am.SqlException;
026 import org.apache.derby.client.am.Utils;
027 import org.apache.derby.client.am.Version;
028 import org.apache.derby.client.resources.ResourceKeys;
029
030
031 public class ClientDriver implements java.sql.Driver {
032 private transient int traceFileSuffixIndex_ = 0;
033
034 private final static int DERBY_REMOTE_PROTOCOL = 1;
035
036 static private SqlException exceptionsOnLoadDriver__ = null;
037 // Keep track of the registere driver so that we can deregister it if we're a stored proc.
038 static private ClientDriver registeredDriver__ = null;
039
040 static {
041 // This may possibly hit the race-condition bug of java 1.1.
042 // The Configuration static clause should execute before the following line does.
043 if (Configuration.exceptionsOnLoadResources != null) {
044 exceptionsOnLoadDriver__ =
045 Utils.accumulateSQLException(Configuration.exceptionsOnLoadResources,
046 exceptionsOnLoadDriver__);
047 }
048 try {
049 registeredDriver__ = new ClientDriver();
050 java.sql.DriverManager.registerDriver(registeredDriver__);
051 } catch (java.sql.SQLException e) {
052 // A null log writer is passed, because jdbc 1 sql exceptions are automatically traced
053 exceptionsOnLoadDriver__ =
054 new SqlException(null, "Error occurred while trying to register Dnc driver with JDBC 1 Driver Manager");
055 exceptionsOnLoadDriver__.setNextException(e);
056 }
057 }
058
059 public ClientDriver() {
060 }
061
062 public java.sql.Connection connect(String url,
063 java.util.Properties properties) throws java.sql.SQLException {
064 if (exceptionsOnLoadDriver__ != null) {
065 throw exceptionsOnLoadDriver__;
066 }
067
068 if (properties == null) {
069 properties = new java.util.Properties();
070 }
071
072 java.util.StringTokenizer urlTokenizer =
073 new java.util.StringTokenizer(url, "/:= \t\n\r\f", true);
074
075 int protocol = tokenizeProtocol(url, urlTokenizer);
076 if (protocol == 0) {
077 return null; // unrecognized database URL prefix.
078 }
079
080 String slashOrNull = null;
081 if (protocol == DERBY_REMOTE_PROTOCOL) {
082 try {
083 slashOrNull = urlTokenizer.nextToken(":/");
084 } catch (java.util.NoSuchElementException e) {
085 // A null log writer is passed, because jdbc 1 sqlexceptions are automatically traced
086 throw new SqlException(null, e, "Invalid database url syntax: " + url);
087 }
088 }
089 String server = tokenizeServerName(urlTokenizer, url); // "/server"
090 int port = tokenizeOptionalPortNumber(urlTokenizer, url); // "[:port]/"
091 if (port == 0) {
092 port = ClientDataSource.propertyDefault_portNumber;
093 }
094
095 // longDatabase is the databaseName and attributes. This will be
096 // sent to network server as the databaseName
097 String database = tokenizeDatabase(urlTokenizer, url); // "database"
098 java.util.Properties augmentedProperties = tokenizeURLProperties(url, properties);
099
100
101 int traceLevel;
102 try {
103 traceLevel = ClientDataSource.getTraceLevel(augmentedProperties);
104 } catch (java.lang.NumberFormatException e) {
105 // A null log writer is passed, because jdbc 1 sqlexceptions are automatically traced
106 throw new SqlException(null, e, "trouble reading traceLevel connection property");
107 }
108
109 // Jdbc 1 connections will write driver trace info on a
110 // driver-wide basis using the jdbc 1 driver manager log writer.
111 // This log writer may be narrowed to the connection-level
112 // This log writer will be passed to the agent constructor.
113 org.apache.derby.client.am.LogWriter dncLogWriter =
114 ClientDataSource.computeDncLogWriterForNewConnection(java.sql.DriverManager.getLogWriter(),
115 ClientDataSource.getTraceDirectory(augmentedProperties),
116 ClientDataSource.getTraceFile(augmentedProperties),
117 ClientDataSource.getTraceFileAppend(augmentedProperties),
118 traceLevel,
119 "_driver",
120 traceFileSuffixIndex_++);
121
122 org.apache.derby.client.net.NetConnection conn =
123 new org.apache.derby.client.net.NetConnection((org.apache.derby.client.net.NetLogWriter) dncLogWriter,
124 java.sql.DriverManager.getLoginTimeout(),
125 server,
126 port,
127 database,
128 augmentedProperties);
129 return conn;
130 }
131
132 public boolean acceptsURL(String url) throws java.sql.SQLException {
133 java.util.StringTokenizer urlTokenizer = new java.util.StringTokenizer(url, "/:=; \t\n\r\f", true);
134 int protocol = tokenizeProtocol(url, urlTokenizer);
135 return protocol != 0;
136 }
137
138 public java.sql.DriverPropertyInfo[] getPropertyInfo(String url,
139 java.util.Properties properties) throws java.sql.SQLException {
140 java.sql.DriverPropertyInfo driverPropertyInfo[] = new java.sql.DriverPropertyInfo[2];
141
142 // If there are no properties set already,
143 // then create a dummy properties just to make the calls go thru.
144 if (properties == null) {
145 properties = new java.util.Properties();
146 }
147
148 driverPropertyInfo[0] =
149 new java.sql.DriverPropertyInfo(ClientDataSource.propertyKey_user,
150 properties.getProperty(ClientDataSource.propertyKey_user, ClientDataSource.propertyDefault_user));
151
152 driverPropertyInfo[1] =
153 new java.sql.DriverPropertyInfo(ClientDataSource.propertyKey_password,
154 properties.getProperty(ClientDataSource.propertyKey_password));
155
156 driverPropertyInfo[0].description =
157 ResourceUtilities.getResource(ResourceKeys.propertyDescription__user);
158 driverPropertyInfo[1].description =
159 ResourceUtilities.getResource(ResourceKeys.propertyDescription__password);
160
161 driverPropertyInfo[0].required = true;
162 driverPropertyInfo[1].required = false; // depending on the security mechanism
163
164 return driverPropertyInfo;
165 }
166
167 public int getMajorVersion() {
168 return Version.getMajorVersion();
169 }
170
171 public int getMinorVersion() {
172 return Version.getMinorVersion();
173 }
174
175 public boolean jdbcCompliant() {
176 return Configuration.jdbcCompliant;
177 }
178
179 // ----------------helper methods---------------------------------------------
180
181 // Tokenize one of the following:
182 // "jdbc:derby:"
183 // and return 0 if the protcol is unrecognized
184 // return DERBY_PROTOCOL for "jdbc:derby"
185 private static int tokenizeProtocol(String url, java.util.StringTokenizer urlTokenizer) throws SqlException {
186 // Is this condition necessary, StringTokenizer constructor may do this for us
187 if (url == null) {
188 return 0;
189 }
190
191 if (urlTokenizer == null) {
192 return 0;
193 }
194
195 try {
196 String jdbc = urlTokenizer.nextToken(":");
197 if (!jdbc.equals("jdbc")) {
198 return 0;
199 }
200 if (!urlTokenizer.nextToken(":").equals(":")) {
201 return 0; // Skip over the first colon in jdbc:derby:
202 }
203 String dbname = urlTokenizer.nextToken(":");
204 int protocol = 0;
205 if (dbname.equals("derby") && (url.indexOf("derby://") != -1)) {
206 // For Derby AS need to check for // since jdbc:derby: is also the
207 // embedded prefix
208 protocol = DERBY_REMOTE_PROTOCOL;
209 } else {
210 return 0;
211 }
212
213 if (!urlTokenizer.nextToken(":").equals(":")) {
214 return 0; // Skip over the second colon in jdbc:derby:
215 }
216
217 return protocol;
218 } catch (java.util.NoSuchElementException e) {
219 return 0;
220 }
221 }
222
223 // tokenize "/server" from URL jdbc:derby://server:port/
224 // returns server name
225 private static String tokenizeServerName(java.util.StringTokenizer urlTokenizer,
226 String url) throws SqlException {
227 try {
228 if (!urlTokenizer.nextToken("/").equals("/"))
229 // A null log writer is passed, because jdbc 1 sqlexceptions are automatically traced
230 {
231 throw new SqlException(null, "Invalid database url syntax: " + url);
232 }
233 return urlTokenizer.nextToken("/:");
234 } catch (java.util.NoSuchElementException e) {
235 // A null log writer is passed, because jdbc 1 sqlexceptions are automatically traced
236 throw new SqlException(null, e, "Invalid database url syntax: " + url);
237 }
238 }
239
240 // tokenize "[:portNumber]/" from URL jdbc:derby://server[:port]/
241 // returns the portNumber or zero if portNumber is not specified.
242 private static int tokenizeOptionalPortNumber(java.util.StringTokenizer urlTokenizer,
243 String url) throws SqlException {
244 try {
245 String firstToken = urlTokenizer.nextToken(":/");
246 if (firstToken.equals(":")) {
247 String port = urlTokenizer.nextToken("/");
248 if (!urlTokenizer.nextToken("/").equals("/")) {
249 // A null log writer is passed, because jdbc 1 sqlexceptions are automatically traced
250 throw new SqlException(null, "Invalid database url syntax: " + url);
251 }
252 return Integer.parseInt(port);
253 } else if (firstToken.equals("/")) {
254 return 0;
255 } else {
256 // A null log writer is passed, because jdbc 1 sqlexceptions are automatically traced
257 throw new SqlException(null, "Invalid database url syntax: " + url);
258 }
259 } catch (java.util.NoSuchElementException e) {
260 // A null log writer is passed, because jdbc 1 sqlexceptions are automatically traced
261 throw new SqlException(null, e, "Invalid database url syntax: " + url);
262 }
263 }
264
265 //return database name and attributes
266 private static String tokenizeDatabase(java.util.StringTokenizer urlTokenizer,
267 String url) throws SqlException {
268 try {
269 String databaseName = urlTokenizer.nextToken(" \t\n\r\f");
270 return databaseName;
271 } catch (java.util.NoSuchElementException e) {
272 // A null log writer is passed, because jdbc 1 sqlexceptions are automatically traced
273 throw new SqlException(null, e, "Invalid database url syntax: " + url);
274 }
275 }
276
277 private static java.util.Properties tokenizeURLProperties(String url,
278 java.util.Properties properties)
279 throws SqlException {
280 String attributeString = null;
281 int attributeIndex = -1;
282
283 if ((url != null) &&
284 ((attributeIndex = url.indexOf(";")) != -1)) {
285 attributeString = url.substring(attributeIndex);
286 }
287 return ClientDataSource.tokenizeAttributes(attributeString, properties);
288 }
289
290
291 }
292
293
|