KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > derby > jdbc > InternalDriver


1
2 /*
3
4    Derby - Class org.apache.derby.jdbc.InternalDriver
5
6    Licensed to the Apache Software Foundation (ASF) under one or more
7    contributor license agreements. See the NOTICE file distributed with
8    this work for additional information regarding copyright ownership.
9    The ASF licenses this file to You under the Apache License, Version 2.0
10    (the "License"); you may not use this file except in compliance with
11    the License. You may obtain a copy of the License at
12
13       http://www.apache.org/licenses/LICENSE-2.0
14
15    Unless required by applicable law or agreed to in writing, software
16    distributed under the License is distributed on an "AS IS" BASIS,
17    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18    See the License for the specific language governing permissions and
19    limitations under the License.
20
21  */

22
23 package org.apache.derby.jdbc;
24
25 import org.apache.derby.iapi.reference.Attribute;
26 import org.apache.derby.iapi.reference.SQLState;
27 import org.apache.derby.iapi.reference.MessageId;
28 import org.apache.derby.iapi.services.io.FormatableProperties;
29
30 import org.apache.derby.iapi.jdbc.ConnectionContext;
31
32 import org.apache.derby.iapi.services.monitor.ModuleControl;
33 import org.apache.derby.iapi.services.monitor.Monitor;
34 import org.apache.derby.iapi.services.context.ContextService;
35 import org.apache.derby.iapi.services.context.ContextManager;
36 import org.apache.derby.iapi.services.sanity.SanityManager;
37 import org.apache.derby.iapi.error.StandardException;
38 import org.apache.derby.iapi.services.i18n.MessageService;
39
40 import org.apache.derby.iapi.sql.ResultSet;
41
42 import org.apache.derby.iapi.jdbc.AuthenticationService;
43 import org.apache.derby.iapi.sql.ResultColumnDescriptor;
44
45 import org.apache.derby.impl.jdbc.*;
46
47 import java.sql.Connection JavaDoc;
48 import java.sql.DatabaseMetaData JavaDoc;
49 import java.sql.SQLException JavaDoc;
50
51 import java.util.Properties JavaDoc;
52 import java.util.StringTokenizer JavaDoc;
53
54
55 /**
56     Abstract factory class and api for JDBC objects.
57     @author djd
58 */

59
60 public abstract class InternalDriver implements ModuleControl {
61     
62     private static final Object JavaDoc syncMe = new Object JavaDoc();
63     private static InternalDriver activeDriver;
64
65     protected boolean active;
66     private ContextService contextServiceFactory;
67     private AuthenticationService authenticationService;
68
69     public static final InternalDriver activeDriver()
70     {
71         return activeDriver;
72     }
73
74     public InternalDriver() {
75         contextServiceFactory = ContextService.getFactory();
76     }
77
78     /*
79     ** Methods from ModuleControl
80     */

81
82     public void boot(boolean create, Properties properties) throws StandardException {
83
84         synchronized (InternalDriver.syncMe)
85         {
86             InternalDriver.activeDriver = this;
87         }
88
89         active = true;
90     }
91
92     public void stop() {
93
94         synchronized (InternalDriver.syncMe)
95         {
96             InternalDriver.activeDriver = null;
97         }
98
99         active = false;
100
101         contextServiceFactory = null;
102     }
103
104     /*
105     ** Methods from java.sql.Driver
106     */

107     public boolean acceptsURL(String JavaDoc url) {
108         return active && embeddedDriverAcceptsURL( url );
109     }
110
111     /*
112     ** This method can be called by AutoloadedDriver so that we
113     ** don't accidentally boot Derby while answering the question "Can
114     ** you handle this URL?"
115     */

116     public static boolean embeddedDriverAcceptsURL(String JavaDoc url) {
117         return
118         // need to reject network driver's URL's
119
!url.startsWith(Attribute.JCC_PROTOCOL) && !url.startsWith(Attribute.DNC_PROTOCOL) &&
120         (url.startsWith(Attribute.PROTOCOL) || url.equals(Attribute.SQLJ_NESTED));
121                 
122     }
123
124     public Connection JavaDoc connect(String JavaDoc url, Properties info)
125          throws SQLException JavaDoc
126     {
127         if (!acceptsURL(url)) { return null; }
128         
129         /**
130          * If we are below the low memory watermark for obtaining
131          * a connection, then don't even try. Just throw an exception.
132          */

133         if (EmbedConnection.memoryState.isLowMemory())
134         {
135             throw EmbedConnection.NO_MEM;
136         }
137                     
138         /*
139         ** A url "jdbc:default:connection" means get the current
140         ** connection. From within a method called from JSQL, the
141         ** "current" connection is the one that is running the
142         ** JSQL statement containing the method call.
143         */

144         boolean current = url.equals(Attribute.SQLJ_NESTED);
145         
146         /* If jdbc:default:connection, see if user already has a
147          * connection. All connection attributes are ignored.
148          */

149         if (current) {
150
151             ConnectionContext connContext = getConnectionContext();
152
153             if (connContext != null) {
154                         
155                 return connContext.getNestedConnection(false);
156                 
157             }
158             // there is no cloudscape connection, so
159
// return null, as we are not the driver to handle this
160
return null;
161         }
162
163         // convert the ;name=value attributes in the URL into
164
// properties.
165
FormatableProperties finfo = null;
166         
167         try {
168             
169             finfo = getAttributes(url, info);
170             info = null; // ensure we don't use this reference directly again.
171

172             /*
173             ** A property "shutdown=true" means shut the system or database down
174             */

175             boolean shutdown = Boolean.valueOf(finfo.getProperty(Attribute.SHUTDOWN_ATTR)).booleanValue();
176             
177             if (shutdown) {
178                 
179                 // If we are shutting down the system don't attempt to create
180
// a connection; but we validate users credentials if we have to.
181
// In case of datbase shutdown, we ask the database authentication
182
// service to authenticate the user. If it is a system shutdown,
183
// then we ask the Driver to do the authentication.
184
//
185
if (InternalDriver.getDatabaseName(url, finfo).length() == 0) {
186                     //
187
// We need to authenticate the user if authentication is
188
// ON. Note that this is a system shutdown.
189
// check that we do have a authentication service
190
// it is _always_ expected.
191
if (this.getAuthenticationService() == null)
192                         throw Util.generateCsSQLException(
193                         SQLState.LOGIN_FAILED,
194                         MessageService.getTextMessage(MessageId.AUTH_NO_SERVICE_FOR_SYSTEM));
195                     
196                         
197                     if (!this.getAuthenticationService().authenticate((String JavaDoc) null, finfo)) {
198
199                         // not a valid user
200
throw Util.generateCsSQLException(
201                                   SQLState.LOGIN_FAILED, MessageService.getTextMessage(MessageId.AUTH_INVALID));
202                     }
203
204                     Monitor.getMonitor().shutdown();
205                     throw Util.generateCsSQLException(
206                                          SQLState.CLOUDSCAPE_SYSTEM_SHUTDOWN);
207                 }
208             }
209             
210             EmbedConnection conn = getNewEmbedConnection(url, finfo);
211
212             // if this is not the correct driver a EmbedConnection
213
// object is returned in the closed state.
214
if (conn.isClosed()) {
215                 return null;
216             }
217
218             return conn;
219         }
220         catch (OutOfMemoryError JavaDoc noMemory)
221         {
222             EmbedConnection.memoryState.setLowMemory();
223             throw EmbedConnection.NO_MEM;
224         }
225         finally {
226             // break any link with the user's Properties set.
227
if (finfo != null)
228                 finfo.clearDefaults();
229         }
230     }
231
232     public int getMajorVersion() {
233         return Monitor.getMonitor().getEngineVersion().getMajorVersion();
234     }
235     
236     public int getMinorVersion() {
237         return Monitor.getMonitor().getEngineVersion().getMinorVersion();
238     }
239
240     public boolean jdbcCompliant() {
241         return true;
242     }
243
244     /*
245     ** URL manipulation
246     */

247
248     /**
249         Convert all the attributes in the url into properties and
250         combine them with the set provided.
251         <BR>
252         If the caller passed in a set of attributes (info != null)
253         then we set that up as the default of the returned property
254         set as the user's set. This means we can easily break the link
255         with the user's set, ensuring that we don't hang onto the users object.
256         It also means that we don't add our attributes into the user's
257         own property object.
258
259         @exception SQLException thrown if URL form bad
260     */

261     protected FormatableProperties getAttributes(String JavaDoc url, Properties info)
262         throws SQLException JavaDoc {
263
264         // We use FormatableProperties here to take advantage
265
// of the clearDefaults, method.
266
FormatableProperties finfo = new FormatableProperties(info);
267         info = null; // ensure we don't use this reference directly again.
268

269
270         StringTokenizer JavaDoc st = new StringTokenizer JavaDoc(url, ";");
271         st.nextToken(); // skip the first part of the url
272

273         while (st.hasMoreTokens()) {
274
275             String JavaDoc v = st.nextToken();
276
277             int eqPos = v.indexOf('=');
278             if (eqPos == -1)
279                 throw Util.generateCsSQLException(
280                                             SQLState.MALFORMED_URL, url);
281
282             //if (eqPos != v.lastIndexOf('='))
283
// throw Util.malformedURL(url);
284

285             finfo.put((v.substring(0, eqPos)).trim(),
286                      (v.substring(eqPos + 1)).trim()
287                     );
288         }
289
290         // now validate any attributes we can
291
//
292
// Boolean attributes -
293
// dataEncryption,create,createSource,convertToSource,shutdown,upgrade,current
294

295
296         checkBoolean(finfo, Attribute.DATA_ENCRYPTION);
297         checkBoolean(finfo, Attribute.CREATE_ATTR);
298         checkBoolean(finfo, Attribute.SHUTDOWN_ATTR);
299         checkBoolean(finfo, Attribute.UPGRADE_ATTR);
300
301         return finfo;
302     }
303
304     private static void checkBoolean(Properties set, String JavaDoc attribute) throws SQLException JavaDoc
305     {
306         final String JavaDoc[] booleanChoices = {"true", "false"};
307         checkEnumeration( set, attribute, booleanChoices);
308     }
309
310
311     private static void checkEnumeration(Properties set, String JavaDoc attribute, String JavaDoc[] choices) throws SQLException JavaDoc
312     {
313         String JavaDoc value = set.getProperty(attribute);
314         if (value == null)
315             return;
316
317         for( int i = 0; i < choices.length; i++)
318         {
319             if( value.toUpperCase(java.util.Locale.ENGLISH).equals( choices[i].toUpperCase(java.util.Locale.ENGLISH)))
320                 return;
321         }
322
323         // The attribute value is invalid. Construct a string giving the choices for
324
// display in the error message.
325
String JavaDoc choicesStr = "{";
326         for( int i = 0; i < choices.length; i++)
327         {
328             if( i > 0)
329                 choicesStr += "|";
330             choicesStr += choices[i];
331         }
332         
333         throw Util.generateCsSQLException(
334                 SQLState.INVALID_ATTRIBUTE, attribute, value, choicesStr + "}");
335     }
336
337
338     /**
339         Get the database name from the url.
340         Copes with three forms
341
342         jdbc:derby:dbname
343         jdbc:derby:dbname;...
344         jdbc:derby:;subname=dbname
345
346         @param url The url being used for the connection
347         @param info The properties set being used for the connection, must include
348         the properties derived from the attributes in the url
349
350         @return a String containing the database name or an empty string ("") if
351         no database name is present in the URL.
352     */

353     public static String JavaDoc getDatabaseName(String JavaDoc url, Properties info) {
354
355         if (url.equals(Attribute.SQLJ_NESTED))
356         {
357             return "";
358         }
359         
360         // skip the jdbc:derby:
361
int attributeStart = url.indexOf(';');
362         String JavaDoc dbname;
363         if (attributeStart == -1)
364             dbname = url.substring(Attribute.PROTOCOL.length());
365         else
366             dbname = url.substring(Attribute.PROTOCOL.length(), attributeStart);
367
368         // For security reasons we rely on here an non-null string being
369
// taken as the database name, before the databaseName connection
370
// attribute. Specifically, even if dbname is blank we still we
371
// to use it rather than the connection attribute, even though
372
// it will end up, after the trim, as a zero-length string.
373
// See EmbeddedDataSource.update()
374

375         if (dbname.length() == 0) {
376             if (info != null)
377                 dbname = info.getProperty(Attribute.DBNAME_ATTR, dbname);
378         }
379         // Beetle 4653 - trim database name to remove blanks that might make a difference on finding the database
380
// on unix platforms
381
dbname = dbname.trim();
382
383         return dbname;
384     }
385
386     public final ContextService getContextServiceFactory() {
387         return contextServiceFactory;
388     }
389
390     // returns the authenticationService handle
391
public AuthenticationService getAuthenticationService() {
392         //
393
// If authenticationService handle not cached in yet, then
394
// ask the monitor to find it for us and set it here in its
395
// attribute.
396
//
397
if (this.authenticationService == null) {
398             this.authenticationService = (AuthenticationService)
399                 Monitor.findService(AuthenticationService.MODULE,
400                                     "authentication"
401                                    );
402         }
403
404         // We should have a Authentication Service (always)
405
//
406
if (SanityManager.DEBUG)
407         {
408             SanityManager.ASSERT(this.authenticationService != null,
409                 "Unexpected - There is no valid authentication service!");
410         }
411         return this.authenticationService;
412     }
413
414     /*
415         Methods to be overloaded in sub-implementations such as
416         a tracing driver.
417      */

418     protected abstract EmbedConnection getNewEmbedConnection(String JavaDoc url, Properties info)
419          throws SQLException JavaDoc ;
420
421
422     private ConnectionContext getConnectionContext() {
423
424         /*
425         ** The current connection is the one in the current
426         ** connection context, so get the context.
427         */

428         ContextManager cm = getCurrentContextManager();
429
430         ConnectionContext localCC = null;
431
432         /*
433             cm is null the very first time, and whenever
434             we aren't actually nested.
435          */

436         if (cm != null) {
437             localCC = (ConnectionContext)
438                 (cm.getContext(ConnectionContext.CONTEXT_ID));
439         }
440
441         return localCC;
442     }
443
444     private ContextManager getCurrentContextManager() {
445         return getContextServiceFactory().getCurrentContextManager();
446     }
447
448
449     /**
450         Return true if this driver is active. Package private method.
451     */

452     public boolean isActive() {
453         return active;
454     }
455
456     /**
457      * Get a new nested connection.
458      *
459      * @param conn The EmbedConnection.
460      *
461      * @return A nested connection object.
462      *
463      */

464     public abstract Connection JavaDoc getNewNestedConnection(EmbedConnection conn);
465
466     /*
467     ** methods to be overridden by subimplementations wishing to insert
468     ** their classes into the mix.
469     */

470
471     public java.sql.Statement JavaDoc newEmbedStatement(
472                 EmbedConnection conn,
473                 boolean forMetaData,
474                 int resultSetType,
475                 int resultSetConcurrency,
476                 int resultSetHoldability)
477     {
478         return new EmbedStatement(conn, forMetaData, resultSetType, resultSetConcurrency,
479         resultSetHoldability);
480     }
481     /**
482         @exception SQLException if fails to create statement
483      */

484     public abstract java.sql.PreparedStatement JavaDoc newEmbedPreparedStatement(
485                 EmbedConnection conn,
486                 String JavaDoc stmt,
487                 boolean forMetaData,
488                 int resultSetType,
489                 int resultSetConcurrency,
490                 int resultSetHoldability,
491                 int autoGeneratedKeys,
492                 int[] columnIndexes,
493                 String JavaDoc[] columnNames)
494         throws SQLException JavaDoc;
495
496     /**
497         @exception SQLException if fails to create statement
498      */

499     public abstract java.sql.CallableStatement JavaDoc newEmbedCallableStatement(
500                 EmbedConnection conn,
501                 String JavaDoc stmt,
502                 int resultSetType,
503                 int resultSetConcurrency,
504                 int resultSetHoldability)
505         throws SQLException JavaDoc;
506
507     /**
508      * Return a new java.sql.DatabaseMetaData instance for this implementation.
509         @exception SQLException on failure to create.
510      */

511     public DatabaseMetaData JavaDoc newEmbedDatabaseMetaData(EmbedConnection conn,
512         String JavaDoc dbname) throws SQLException JavaDoc {
513         return new EmbedDatabaseMetaData(conn,dbname);
514     }
515
516     /**
517      * Return a new java.sql.ResultSet instance for this implementation.
518      * @param conn Owning connection
519      * @param results Top level of language result set tree
520      * @param forMetaData Is this for meta-data
521      * @param statement The statement that is creating the SQL ResultSet
522      * @param isAtomic
523      * @return a new java.sql.ResultSet
524      * @throws SQLException
525      */

526     public abstract EmbedResultSet
527         newEmbedResultSet(EmbedConnection conn, ResultSet results, boolean forMetaData, EmbedStatement statement, boolean isAtomic) throws SQLException JavaDoc;
528         
529         /**
530          * Returns a new java.sql.ResultSetMetaData for this implementation
531          *
532          * @param columnInfo a ResultColumnDescriptor that stores information
533          * about the columns in a ResultSet
534          */

535         public EmbedResultSetMetaData newEmbedResultSetMetaData
536                            (ResultColumnDescriptor[] columnInfo) {
537             return new EmbedResultSetMetaData(columnInfo);
538         }
539 }
540
541
542
543
Popular Tags