KickJava   Java API By Example, From Geeks To Geeks.

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


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

21
22 package org.apache.derby.jdbc;
23
24 import java.io.Serializable JavaDoc;
25 import java.io.PrintWriter JavaDoc;
26 import java.util.Enumeration JavaDoc;
27 import java.util.Properties JavaDoc;
28 import java.util.StringTokenizer JavaDoc;
29 import java.util.NoSuchElementException JavaDoc;
30 import java.lang.reflect.Field JavaDoc;
31 import java.lang.reflect.InvocationTargetException JavaDoc;
32 import java.lang.reflect.Method JavaDoc;
33 import java.lang.reflect.Modifier JavaDoc;
34
35 import javax.naming.RefAddr JavaDoc;
36 import javax.naming.Referenceable JavaDoc;
37 import javax.naming.Reference JavaDoc;
38 import javax.naming.NamingException JavaDoc;
39 import javax.naming.StringRefAddr JavaDoc;
40
41 import org.apache.derby.client.am.Configuration;
42 import org.apache.derby.client.am.LogWriter;
43 import org.apache.derby.client.am.SqlException;
44 import org.apache.derby.client.am.Connection;
45 import org.apache.derby.client.am.ClientMessageId;
46 import org.apache.derby.client.net.NetConfiguration;
47 import org.apache.derby.client.net.NetLogWriter;
48 import org.apache.derby.client.ClientDataSourceFactory;
49 import org.apache.derby.shared.common.reference.Attribute;
50 import org.apache.derby.shared.common.reference.SQLState;
51
52 /**
53  * Base class for client-side DataSource implementations.
54  */

55 public abstract class ClientBaseDataSource implements Serializable JavaDoc, Referenceable JavaDoc {
56     private static final long serialVersionUID = -7660172643035173692L;
57
58     // Spec requires DH algorithm with 32bytes prime to be used
59
// Not all JCE implementations have support for this. E.g.
60
// Sun JCE does not support DH(prime of 32bytes).
61
// store information if client JVM has JCE loaded that
62
// can support the necessary algorithms required for EUSRIDPWD
63
// (encrypted userid and password) security mechanism
64
// this information is needed to decide if security mechanism
65
// can be upgraded to EUSRIDPWD or not
66
// See getUpgradedSecurityMechanism()
67
static boolean SUPPORTS_EUSRIDPWD = false;
68     
69     static
70     {
71         try
72         {
73             // The EncryptionManager class will instantiate objects of the required
74
// security algorithms that are needed for EUSRIDPWD
75
// An exception will be thrown if support is not available
76
// in the JCE implementation in the JVM in which the client
77
// is loaded.
78
new org.apache.derby.client.am.EncryptionManager(null);
79             SUPPORTS_EUSRIDPWD = true;
80         }catch(Exception JavaDoc e)
81         {
82             // if an exception is thrown, ignore exception.
83
// set SUPPORTS_EUSRIDPWD to false indicating that the client
84
// does not support EUSRIDPWD security mechanism
85
SUPPORTS_EUSRIDPWD = false;
86         }
87     }
88     
89     // The loginTimeout jdbc 2 data source property is not supported as a jdbc 1 connection property,
90
// because loginTimeout is set by the jdbc 1 api via java.sql.DriverManager.setLoginTimeout().
91
// The databaseName, serverName, and portNumber data source properties are also not supported as connection properties
92
// because they are extracted from the jdbc 1 database url passed on the connection request.
93
// However, all other data source properties should probably also be supported as connection properties.
94

95     //---------------------contructors/finalizers---------------------------------
96

97     // This class is abstract, hide the default constructor
98
ClientBaseDataSource() {
99     }
100
101     // ---------------------------- loginTimeout -----------------------------------
102
//
103
// was serialized in 1.0 release
104
/**
105      * The time in seconds to wait for a connection request on this data source. The default value of zero indicates
106      * that either the system time out be used or no timeout limit.
107      *
108      * @serial
109      */

110     private int loginTimeout;
111
112     public synchronized void setLoginTimeout(int seconds) {
113         this.loginTimeout = seconds;
114     }
115
116     public int getLoginTimeout() {
117         return this.loginTimeout;
118     }
119
120     // ---------------------------- logWriter -----------------------------------
121
//
122
/**
123      * The log writer is declared transient, and is not serialized or stored under JNDI.
124      *
125      * @see #traceLevel
126      */

127     private transient PrintWriter JavaDoc logWriter;
128
129     public synchronized void setLogWriter(PrintWriter JavaDoc logWriter) {
130         this.logWriter = logWriter;
131     }
132
133     public PrintWriter JavaDoc getLogWriter() {
134         return this.logWriter;
135     }
136
137     // ---------------------------- databaseName -----------------------------------
138
//
139
// Stores the relational database name, RDBNAME.
140
// The length of the database name may be limited to 18 bytes
141
// and therefore may throw an SQLException.
142
//
143
//
144
private String JavaDoc databaseName;
145     
146     // databaseName is not permitted in a properties object
147

148
149     // ---------------------------- description ------------------------------
150
// A description of this data source.
151
private String JavaDoc description;
152     
153     // ---------------------------- dataSourceName -----------------------------------
154
//
155
// A data source name;
156
// used to name an underlying XADataSource,
157
// or ConnectionPoolDataSource when pooling of connections is done.
158
//
159
private String JavaDoc dataSourceName;
160     
161     // ---------------------------- portNumber -----------------------------------
162
//
163
private int portNumber = propertyDefault_portNumber;
164     public final static int propertyDefault_portNumber = 1527;
165     
166     // ---------------------------- serverName -----------------------------------
167
//
168
// Derby-410 fix.
169
private String JavaDoc serverName = propertyDefault_serverName;
170     public final static String JavaDoc propertyDefault_serverName = "localhost";
171    
172     // serverName is not permitted in a properties object
173

174     // ---------------------------- user -----------------------------------
175
//
176
// This property can be overwritten by specifing the
177
// username parameter on the DataSource.getConnection() method
178
// call. If user is specified, then password must also be
179
// specified, either in the data source object or provided on
180
// the DataSource.getConnection() call.
181
//
182
// Each data source implementation subclass will maintain it's own <code>password</code> property.
183
// This password property may or may not be declared transient, and therefore may be serialized
184
// to a file in clear-text, care must taken by the user to prevent security breaches.
185
// Derby-406 fix
186
private String JavaDoc user = propertyDefault_user;
187     public final static String JavaDoc propertyDefault_user = "APP";
188
189     public static String JavaDoc getUser(Properties JavaDoc properties) {
190         String JavaDoc userString = properties.getProperty(Attribute.USERNAME_ATTR);
191         return parseString(userString, propertyDefault_user);
192     }
193
194     // ---------------------------- securityMechanism -----------------------------------
195
//
196
// The source security mechanism to use when connecting to this data source.
197
// <p>
198
// Security mechanism options are:
199
// <ul>
200
// <li> USER_ONLY_SECURITY
201
// <li> CLEAR_TEXT_PASSWORD_SECURITY
202
// <li> ENCRYPTED_PASSWORD_SECURITY
203
// <li> ENCRYPTED_USER_AND_PASSWORD_SECURITY - both password and user are encrypted
204
// <li> STRONG_PASSWORD_SUBSTITUTE_SECURITY
205
// </ul>
206
// The default security mechanism is USER_ONLY_SECURITY.
207
// <p>
208
// If the application specifies a security
209
// mechanism then it will be the only one attempted.
210
// If the specified security mechanism is not supported by the conversation
211
// then an exception will be thrown and there will be no additional retries.
212
// <p>
213
// This property is currently only available for the DNC driver.
214
// <p>
215
// Both user and password need to be set for all security mechanism except USER_ONLY_SECURITY
216
// When using USER_ONLY_SECURITY, only the user property needs to be specified.
217
//
218

219     // constant to indicate that the security mechanism has not been
220
// explicitly set, either on connection request when using DriverManager
221
// or on the Client DataSource object
222
private final static short SECMEC_HAS_NOT_EXPLICITLY_SET = 0;
223     
224     // Security Mechanism can be specified explicitly either when obtaining a
225
// connection via a DriverManager or via Datasource.
226
// Via DriverManager, securityMechanism can be set on the connection request using
227
// the 'securityMechanism' attribute.
228
// Via DataSource, securityMechanism can be set by calling setSecurityMechanism()
229
// on the ClientDataSource
230
// If the security mechanism is not explicitly set as mentioned above, in that case
231
// the Client will try to upgrade the security mechanism to a more secure one, if possible.
232
// @see #getUpgradedSecurityMechanism
233
// Therefore, need to keep track if the securityMechanism has been explicitly set
234
protected short securityMechanism = SECMEC_HAS_NOT_EXPLICITLY_SET;
235
236     // Default security mechanism is USER_ONLY_SECURITY.
237
public final static short propertyDefault_securityMechanism =
238                                     (short) NetConfiguration.SECMEC_USRIDONL;
239
240     
241     // We use the NET layer constants to avoid a mapping for the NET driver.
242
/**
243      * Return security mechanism if it is set, else upgrade the security mechanism
244      * if possible and return the upgraded security mechanism
245      * @param properties Look in the properties if securityMechanism is set or not
246      * if set, return this security mechanism
247      * @return security mechanism
248      */

249     public static short getSecurityMechanism(Properties JavaDoc properties) {
250         short secmec;
251         String JavaDoc securityMechanismString =
252             properties.getProperty(Attribute.CLIENT_SECURITY_MECHANISM);
253
254         if ( securityMechanismString != null )
255         {
256             // security mechanism has been set, do not override, but instead return
257
// the security mechanism that has been set (DERBY-962)
258
secmec = Short.parseShort(securityMechanismString);
259         }
260         else
261         {
262             // if securityMechanismString is null, this means that
263
// security mechanism has not been set explicitly and not available in
264
// properties. Hence, do an upgrade of security mechanism if possible
265
// The logic for upgrade of security mechanism uses information about
266
// if password is available or not, so pass this information also.
267
String JavaDoc passwordString = properties.getProperty(Attribute.PASSWORD_ATTR);
268             secmec = getUpgradedSecurityMechanism(passwordString);
269         }
270         return secmec;
271     }
272
273     /**
274      * This method has logic to upgrade security mechanism to a better (more secure)
275      * one if it is possible. Currently derby server only has support for USRIDPWD,
276      * USRIDONL, EUSRIDPWD and USRSSBPWD (10.2+) - this method only considers these
277      * possibilities. USRIDPWD, EUSRIDPWD and USRSSBPWD require a password, USRIDONL
278      * is the only security mechanism which does not require password.
279      * 1. if password is not available, then security mechanism possible is USRIDONL
280      * 2. if password is available,then USRIDPWD is returned.
281      *
282      * @param password password argument
283      * @return upgraded security mechanism if possible
284      */

285     public static short getUpgradedSecurityMechanism(String JavaDoc password) {
286         // if password is null, in that case the only acceptable security
287
// mechanism is USRIDONL, which is the default security mechanism.
288
if ( password == null )
289             return propertyDefault_securityMechanism;
290
291         // when we have support for more security mechanisms on server
292
// and client, we should update this upgrade logic to pick
293
// secure security mechanisms before trying out the USRIDPWD
294

295         /*
296         // -----------------------
297         // PLEASE NOTE:
298         // When DERBY-1517, DERBY-1755 is fixed, there might be a way to use EUSRIDPWD
299         // when both client and server vm's have support for it. Hence the below
300         // if statement is commented out.
301         if (SUPPORTS_EUSRIDPWD)
302             return (short)NetConfiguration.SECMEC_EUSRIDPWD;
303         else
304             // IMPORTANT NOTE:
305             // --------------
306             // If DERBY-1517 can be fixed, we should default to
307             // SECMEC_USRSSBPWD (strong password substitute).
308             // Until then, connecting with a 10.2+ client to
309             // a derby server < 10.2, and hence does not support
310             // SECMEC_USRSSBPWD as a SECMEC, will cause a DRDA protocol
311             // exception, as described in DERBY-926).
312             //
313             // return (short)NetConfiguration.SECMEC_USRSSBPWD;
314          // ----------------------
315          */

316          return (short)NetConfiguration.SECMEC_USRIDPWD;
317
318     }
319
320     // ---------------------------- getServerMessageTextOnGetMessage -----------------------------------
321
//
322
private boolean retrieveMessageText = propertyDefault_retrieveMessageText;
323     public final static boolean propertyDefault_retrieveMessageText = true;
324
325     public static boolean getRetrieveMessageText(Properties JavaDoc properties) {
326         String JavaDoc retrieveMessageTextString = properties.getProperty(Attribute.CLIENT_RETIEVE_MESSAGE_TEXT);
327         return parseBoolean(retrieveMessageTextString, propertyDefault_retrieveMessageText);
328     }
329
330     // ---------------------------- traceFile -----------------------------------
331
//
332
private String JavaDoc traceFile;
333     
334     public static String JavaDoc getTraceFile(Properties JavaDoc properties) {
335         return properties.getProperty(Attribute.CLIENT_TRACE_FILE);
336     }
337
338     // ---------------------------- traceDirectory -----------------------------------
339
// For the suffix of the trace file when traceDirectory is enabled.
340
private transient int traceFileSuffixIndex_ = 0;
341     //
342
private String JavaDoc traceDirectory;
343     
344     public static String JavaDoc getTraceDirectory(Properties JavaDoc properties) {
345         return properties.getProperty(Attribute.CLIENT_TRACE_DIRECTORY);
346     }
347
348     // ---------------------------- traceFileAppend -----------------------------------
349
//
350
private boolean traceFileAppend = propertyDefault_traceFileAppend;
351     public final static boolean propertyDefault_traceFileAppend = false;
352     
353     public static boolean getTraceFileAppend(Properties JavaDoc properties) {
354         String JavaDoc traceFileAppendString = properties.getProperty(Attribute.CLIENT_TRACE_APPEND);
355         return parseBoolean(traceFileAppendString, propertyDefault_traceFileAppend);
356     }
357
358     // ---------------------------- password -----------------------------------
359
//
360
// The password property is defined in subclasses, but the method
361
// getPassword (java.util.Properties properties) is in this class to eliminate
362
// dependencies on j2ee for connections that go thru the driver manager.
363

364     public static String JavaDoc getPassword(Properties JavaDoc properties) {
365         return properties.getProperty("password");
366     }
367
368     private String JavaDoc password;
369
370     synchronized public final void setPassword(String JavaDoc password) {
371         this.password = password;
372     }
373     
374     public final String JavaDoc getPassword() {
375         return password;
376     }
377
378     //------------------------ interface methods ---------------------------------
379

380     public Reference JavaDoc getReference() throws NamingException JavaDoc {
381         // This method creates a new Reference object to represent this data source.
382
// The class name of the data source object is saved in the Reference,
383
// so that an object factory will know that it should create an instance
384
// of that class when a lookup operation is performed. The class
385
// name of the object factory, org.apache.derby.client.ClientBaseDataSourceFactory,
386
// is also stored in the reference.
387
// This is not required by JNDI, but is recommend in practice.
388
// JNDI will always use the object factory class specified in the reference when
389
// reconstructing an object, if a class name has been specified.
390
// See the JNDI SPI documentation
391
// for further details on this topic, and for a complete description of the Reference
392
// and StringRefAddr classes.
393
//
394
// This ClientBaseDataSource class provides several standard JDBC properties.
395
// The names and values of the data source properties are also stored
396
// in the reference using the StringRefAddr class.
397
// This is all the information needed to reconstruct a ClientBaseDataSource object.
398

399         Reference JavaDoc ref = new Reference JavaDoc(this.getClass().getName(), ClientDataSourceFactory.class.getName(), null);
400
401         addBeanProperties(ref);
402         return ref;
403     }
404     
405     /**
406      * Add Java Bean properties to the reference using
407      * StringRefAddr for each property. List of bean properties
408      * is defined from the public getXXX() methods on this object
409      * that take no arguments and return short, int, boolean or String.
410      * The StringRefAddr has a key of the Java bean property name,
411      * converted from the method name. E.g. traceDirectory for
412      * traceDirectory.
413      *
414       */

415     private void addBeanProperties(Reference JavaDoc ref)
416     {
417         // Look for all the getXXX methods in the class that take no arguments.
418
Method JavaDoc[] methods = this.getClass().getMethods();
419         
420         for (int i = 0; i < methods.length; i++) {
421
422             Method JavaDoc m = methods[i];
423
424             // only look for simple getter methods.
425
if (m.getParameterTypes().length != 0)
426                 continue;
427
428             // only non-static methods
429
if (Modifier.isStatic(m.getModifiers()))
430                 continue;
431
432             // Only getXXX methods
433
String JavaDoc methodName = m.getName();
434             if ((methodName.length() < 5) || !methodName.startsWith("get"))
435                 continue;
436
437             Class JavaDoc returnType = m.getReturnType();
438
439             if (Integer.TYPE.equals(returnType)
440                     || Short.TYPE.equals(returnType)
441                     || String JavaDoc.class.equals(returnType)
442                     || Boolean.TYPE.equals(returnType)) {
443
444                 // setSomeProperty
445
// 01234
446

447                 String JavaDoc propertyName = methodName.substring(3, 4).toLowerCase(
448                         java.util.Locale.ENGLISH).concat(
449                         methodName.substring(4));
450
451                 try {
452                     Object JavaDoc ov = m.invoke(this, null);
453                     String JavaDoc value = ov == null ? null : ov.toString();
454                     ref.add(new StringRefAddr JavaDoc(propertyName, value));
455                 } catch (IllegalAccessException JavaDoc iae) {
456                 } catch (InvocationTargetException JavaDoc ite) {
457                 }
458
459             }
460         }
461     }
462
463     // ----------------------supplemental methods---------------------------------
464

465
466     //---------------------- helper methods --------------------------------------
467

468     // The java.io.PrintWriter overrides the traceFile setting.
469
// If neither traceFile nor jdbc logWriter are set, then null is returned.
470
// logWriterInUseSuffix used only for trace directories to indicate whether
471
// log writer is use is from xads, cpds, sds, ds, driver, config, reset.
472
LogWriter computeDncLogWriterForNewConnection(String JavaDoc logWriterInUseSuffix) throws SqlException {
473         return computeDncLogWriterForNewConnection(logWriter, traceDirectory, traceFile, traceFileAppend, traceLevel, logWriterInUseSuffix, traceFileSuffixIndex_++);
474     }
475
476     // Called on for connection requests.
477
// The java.io.PrintWriter overrides the traceFile setting.
478
// If neither traceFile, nor logWriter, nor traceDirectory are set, then null is returned.
479
static LogWriter computeDncLogWriterForNewConnection(PrintWriter JavaDoc logWriter, String JavaDoc traceDirectory, String JavaDoc traceFile, boolean traceFileAppend, int traceLevel, String JavaDoc logWriterInUseSuffix, int traceFileSuffixIndex) throws SqlException {
480         int globaltraceFileSuffixIndex = Configuration.traceFileSuffixIndex__++;
481
482         // compute regular dnc log writer if there is any
483
LogWriter dncLogWriter = computeDncLogWriter(logWriter, traceDirectory, traceFile, traceFileAppend, logWriterInUseSuffix, traceFileSuffixIndex, traceLevel);
484         if (dncLogWriter != null) {
485             return dncLogWriter;
486         }
487         // compute global default dnc log writer if there is any
488
dncLogWriter = computeDncLogWriter(null, Configuration.traceDirectory__, Configuration.traceFile__, Configuration.traceFileAppend__, "_global", globaltraceFileSuffixIndex, Configuration.traceLevel__);
489         return dncLogWriter;
490     }
491
492     // Compute a DNC log writer before a connection is created.
493
static LogWriter computeDncLogWriter(PrintWriter JavaDoc logWriter, String JavaDoc traceDirectory, String JavaDoc traceFile, boolean traceFileAppend, String JavaDoc logWriterInUseSuffix, int traceFileSuffixIndex, int traceLevel) throws SqlException {
494         // Otherwise, the trace file will still be created even TRACE_NONE.
495
if (traceLevel == TRACE_NONE) {
496             return null;
497         }
498
499         PrintWriter JavaDoc printWriter = computePrintWriter(logWriter, traceDirectory, traceFile, traceFileAppend, logWriterInUseSuffix, traceFileSuffixIndex);
500         if (printWriter == null) {
501             return null;
502         }
503
504         LogWriter dncLogWriter = new NetLogWriter(printWriter, traceLevel);
505         if (printWriter != logWriter && traceDirectory != null)
506         // When printWriter is an internal trace file and
507
// traceDirectory is not null, each connection has
508
// its own trace file and the trace file is not cached,
509
// so we can close it when DNC log writer is closed.
510
{
511             dncLogWriter.printWriterNeedsToBeClosed_ = true;
512         }
513         return dncLogWriter;
514     }
515
516     // Compute a DNC log writer after a connection is created.
517
// Declared public for use by am.Connection. Not a public external.
518
public static LogWriter computeDncLogWriter(Connection connection, PrintWriter JavaDoc logWriter, String JavaDoc traceDirectory, String JavaDoc traceFile, boolean traceFileAppend, String JavaDoc logWriterInUseSuffix, int traceFileSuffixIndex, int traceLevel) throws SqlException {
519         // Otherwise, the trace file will still be created even TRACE_NONE.
520
if (traceLevel == TRACE_NONE) {
521             return null;
522         }
523
524         PrintWriter JavaDoc printWriter = computePrintWriter(logWriter, traceDirectory, traceFile, traceFileAppend, logWriterInUseSuffix, traceFileSuffixIndex);
525         if (printWriter == null) {
526             return null;
527         }
528
529         LogWriter dncLogWriter = connection.agent_.newLogWriter_(printWriter, traceLevel);
530         if (printWriter != logWriter && traceDirectory != null)
531         // When printWriter is an internal trace file and
532
// traceDirectory is not null, each connection has
533
// its own trace file and the trace file is not cached,
534
// so we can close it when DNC log writer is closed.
535
{
536             dncLogWriter.printWriterNeedsToBeClosed_ = true;
537         }
538         return dncLogWriter;
539     }
540
541     // This method handles all the override semantics.
542
// The logWriter overrides the traceFile, and traceDirectory settings.
543
// If neither traceFile, nor logWriter, nor traceDirectory are set, then null is returned.
544
static PrintWriter JavaDoc computePrintWriter(PrintWriter JavaDoc logWriter, String JavaDoc traceDirectory, String JavaDoc traceFile, boolean traceFileAppend, String JavaDoc logWriterInUseSuffix, int traceFileSuffixIndex) throws SqlException {
545         if (logWriter != null) // java.io.PrintWriter is specified
546
{
547             return logWriter;
548         } else { // check trace file setting.
549
if (traceDirectory != null) {
550                 String JavaDoc fileName;
551                 if (traceFile == null) {
552                     fileName = traceDirectory + "/" + logWriterInUseSuffix + "_" + traceFileSuffixIndex;
553                 } else {
554                     fileName = traceDirectory + "/" + traceFile + logWriterInUseSuffix + "_" + traceFileSuffixIndex;
555                 }
556                 return LogWriter.getPrintWriter(fileName, true); // no file append and not enable caching.
557
} else if (traceFile != null) {
558                 return LogWriter.getPrintWriter(traceFile, traceFileAppend);
559             }
560         }
561         return null;
562     }
563
564     private static boolean parseBoolean(String JavaDoc boolString, boolean defaultBool) {
565         if (boolString != null) {
566             return (boolString.equalsIgnoreCase("true") || boolString.equalsIgnoreCase("yes"));
567         }
568         return defaultBool;
569     }
570
571     private static String JavaDoc parseString(String JavaDoc string, String JavaDoc defaultString) {
572         if (string != null) {
573             return string;
574         }
575         return defaultString;
576     }
577
578     private static short parseShort(String JavaDoc shortString, short defaultShort) {
579         if (shortString != null) {
580             return Short.parseShort(shortString);
581         }
582         return defaultShort;
583     }
584
585     private static int parseInt(String JavaDoc intString, int defaultInt) {
586         if (intString != null) {
587             return Integer.parseInt(intString);
588         }
589         return defaultInt;
590     }
591
592     // tokenize "property=value;property=value..." and returns new properties object
593
//This method is used both by ClientDriver to parse the url and
594
// ClientDataSource.setConnectionAttributes
595
static Properties JavaDoc tokenizeAttributes(String JavaDoc attributeString, Properties JavaDoc properties) throws SqlException {
596         Properties JavaDoc augmentedProperties;
597
598         if (attributeString == null) {
599             return properties;
600         }
601
602         if (properties != null) {
603             augmentedProperties = (Properties JavaDoc) properties.clone();
604         } else {
605             augmentedProperties = new Properties JavaDoc();
606         }
607         try {
608             StringTokenizer JavaDoc attrTokenizer = new StringTokenizer JavaDoc(attributeString, ";");
609             while (attrTokenizer.hasMoreTokens()) {
610                 String JavaDoc v = attrTokenizer.nextToken();
611
612                 int eqPos = v.indexOf('=');
613                 if (eqPos == -1) {
614                     throw new SqlException(null,
615                         new ClientMessageId(SQLState.INVALID_ATTRIBUTE_SYNTAX),
616                         attributeString);
617                 }
618
619                 augmentedProperties.setProperty((v.substring(0, eqPos)).trim(), (v.substring(eqPos + 1)).trim());
620             }
621         } catch (NoSuchElementException JavaDoc e) {
622             // A null log writer is passed, because jdbc 1 sqlexceptions are automatically traced
623
throw new SqlException(null,
624                 new ClientMessageId(SQLState.INVALID_ATTRIBUTE_SYNTAX),
625                 attributeString, e);
626         }
627         checkBoolean(augmentedProperties, Attribute.CLIENT_RETIEVE_MESSAGE_TEXT);
628         return augmentedProperties;
629
630     }
631
632     private static void checkBoolean(Properties JavaDoc set, String JavaDoc attribute) throws SqlException {
633         final String JavaDoc[] booleanChoices = {"true", "false"};
634         checkEnumeration(set, attribute, booleanChoices);
635     }
636
637
638     private static void checkEnumeration(Properties JavaDoc set, String JavaDoc attribute, String JavaDoc[] choices) throws SqlException {
639         String JavaDoc value = set.getProperty(attribute);
640         if (value == null) {
641             return;
642         }
643
644         for (int i = 0; i < choices.length; i++) {
645             if (value.toUpperCase(java.util.Locale.ENGLISH).equals(choices[i].toUpperCase(java.util.Locale.ENGLISH))) {
646                 return;
647             }
648         }
649
650 // The attribute value is invalid. Construct a string giving the choices for
651
// display in the error message.
652
String JavaDoc choicesStr = "{";
653         for (int i = 0; i < choices.length; i++) {
654             if (i > 0) {
655                 choicesStr += "|";
656             }
657             choicesStr += choices[i];
658         }
659
660         throw new SqlException(null,
661             new ClientMessageId(SQLState.INVALID_ATTRIBUTE),
662             attribute, value, choicesStr);
663     }
664
665     /*
666      * Properties to be seen by Bean - access thru reflection.
667      */

668
669     // -- Stardard JDBC DataSource Properties
670

671     public synchronized void setDatabaseName(String JavaDoc databaseName) {
672         this.databaseName = databaseName;
673     }
674
675     public String JavaDoc getDatabaseName() {
676         return this.databaseName;
677     }
678
679
680     public synchronized void setDataSourceName(String JavaDoc dataSourceName) {
681         this.dataSourceName = dataSourceName;
682     }
683
684     public String JavaDoc getDataSourceName() {
685         return this.dataSourceName;
686     }
687
688     public synchronized void setDescription(String JavaDoc description) {
689         this.description = description;
690     }
691
692     public String JavaDoc getDescription() {
693         return this.description;
694     }
695
696
697     public synchronized void setPortNumber(int portNumber) {
698         this.portNumber = portNumber;
699     }
700
701     public int getPortNumber() {
702         return this.portNumber;
703     }
704
705     public synchronized void setServerName(String JavaDoc serverName) {
706         this.serverName = serverName;
707     }
708
709     public String JavaDoc getServerName() {
710         return this.serverName;
711     }
712
713
714     public synchronized void setUser(String JavaDoc user) {
715         this.user = user;
716     }
717
718     public String JavaDoc getUser() {
719         return this.user;
720     }
721
722     synchronized public void setRetrieveMessageText(boolean retrieveMessageText) {
723         this.retrieveMessageText = retrieveMessageText;
724     }
725
726     public boolean getRetrieveMessageText() {
727         return this.retrieveMessageText;
728     }
729
730     // ---------------------------- securityMechanism -----------------------------------
731
/**
732      * The source security mechanism to use when connecting to this data source.
733      * <p/>
734      * Security mechanism options are: <ul>
735      * <li> USER_ONLY_SECURITY
736      * <li> CLEAR_TEXT_PASSWORD_SECURITY
737      * <li> ENCRYPTED_PASSWORD_SECURITY
738      * <li> ENCRYPTED_USER_AND_PASSWORD_SECURITY - both password and user are encrypted
739      * <li> STRONG_PASSWORD_SUBSTITUTE_SECURITY
740      * </ul> The default security mechanism is USER_ONLY SECURITY
741      * <p/>
742      * If the application specifies a security mechanism then it will be the only one attempted. If the specified
743      * security mechanism is not supported by the conversation then an exception will be thrown and there will be no
744      * additional retries.
745      * <p/>
746      * This property is currently only available for the DNC driver.
747      * <p/>
748      * Both user and password need to be set for all security mechanism except USER_ONLY_SECURITY
749      */

750     // We use the NET layer constants to avoid a mapping for the NET driver.
751
public final static short USER_ONLY_SECURITY = (short) NetConfiguration.SECMEC_USRIDONL;
752     public final static short CLEAR_TEXT_PASSWORD_SECURITY = (short) NetConfiguration.SECMEC_USRIDPWD;
753     public final static short ENCRYPTED_PASSWORD_SECURITY = (short) NetConfiguration.SECMEC_USRENCPWD;
754     public final static short ENCRYPTED_USER_AND_PASSWORD_SECURITY = (short) NetConfiguration.SECMEC_EUSRIDPWD;
755     public final static short STRONG_PASSWORD_SUBSTITUTE_SECURITY = (short) NetConfiguration.SECMEC_USRSSBPWD;
756
757     /**
758      * sets the security mechanism
759      * @param securityMechanism to set
760      */

761     synchronized public void setSecurityMechanism(short securityMechanism) {
762         this.securityMechanism = securityMechanism;
763     }
764
765     /**
766      * return the security mechanism
767      * if security mechanism has not been set explicitly on datasource
768      * then upgrade the security mechanism to a more secure one if possible
769      * @see #getUpgradedSecurityMechanism(String)
770      * @return the security mechanism
771      */

772     public short getSecurityMechanism() {
773         return getSecurityMechanism(getPassword());
774     }
775
776     /**
777      * return the security mechanism for this datasource object
778      * if security mechanism has not been set explicitly on datasource
779      * then upgrade the security mechanism to a more secure one if possible
780      * @param password password of user
781      * @see #getUpgradedSecurityMechanism(String)
782      * @return the security mechanism
783      */

784     public short getSecurityMechanism(String JavaDoc password) {
785         
786         // if security mechanism has not been set explicitly on
787
// datasource, then upgrade the security mechanism if possible
788
// DERBY-962
789
if ( securityMechanism == SECMEC_HAS_NOT_EXPLICITLY_SET )
790             return getUpgradedSecurityMechanism(password);
791         
792         return securityMechanism;
793     }
794
795     protected String JavaDoc connectionAttributes = null;
796
797     /**
798      * Set this property to pass in more Derby specific connection URL attributes.
799      * <BR>
800      * Any attributes that can be set using a property of this DataSource implementation
801      * (e.g user, password) should not be set in connectionAttributes. Conflicting
802      * settings in connectionAttributes and properties of the DataSource will lead to
803      * unexpected behaviour.
804      *
805      * @param prop set to the list of Cloudscape connection attributes separated by semi-colons. E.g., to specify an
806      * encryption bootPassword of "x8hhk2adf", and set upgrade to true, do the following: <PRE>
807      * ds.setConnectionAttributes("bootPassword=x8hhk2adf;upgrade=true"); </PRE> See Derby documentation for
808      * complete list.
809      */

810     public final void setConnectionAttributes(String JavaDoc prop) {
811         connectionAttributes = prop;
812     }
813
814     /**
815      * @return Derby specific connection URL attributes
816      */

817     public final String JavaDoc getConnectionAttributes() {
818         return connectionAttributes;
819     }
820
821
822     // ---------------------------- traceLevel -----------------------------------
823
//
824

825     public final static int TRACE_NONE = 0x0;
826     public final static int TRACE_CONNECTION_CALLS = 0x1;
827     public final static int TRACE_STATEMENT_CALLS = 0x2;
828     public final static int TRACE_RESULT_SET_CALLS = 0x4;
829     public final static int TRACE_DRIVER_CONFIGURATION = 0x10;
830     public final static int TRACE_CONNECTS = 0x20;
831     public final static int TRACE_PROTOCOL_FLOWS = 0x40;
832     public final static int TRACE_RESULT_SET_META_DATA = 0x80;
833     public final static int TRACE_PARAMETER_META_DATA = 0x100;
834     public final static int TRACE_DIAGNOSTICS = 0x200;
835     public final static int TRACE_XA_CALLS = 0x800;
836     public final static int TRACE_ALL = 0xFFFFFFFF;
837
838     public final static int propertyDefault_traceLevel = TRACE_ALL;
839     
840     protected int traceLevel = propertyDefault_traceLevel;
841
842     public static int getTraceLevel(Properties JavaDoc properties) {
843         String JavaDoc traceLevelString = properties.getProperty(Attribute.CLIENT_TRACE_LEVEL);
844         return parseInt(traceLevelString, propertyDefault_traceLevel);
845     }
846
847     synchronized public void setTraceLevel(int traceLevel) {
848         this.traceLevel = traceLevel;
849     }
850
851     public int getTraceLevel() {
852         return this.traceLevel;
853     }
854
855
856     public synchronized void setTraceFile(String JavaDoc traceFile) {
857         this.traceFile = traceFile;
858     }
859
860     public String JavaDoc getTraceFile() {
861         return this.traceFile;
862     }
863
864
865     public synchronized void setTraceDirectory(String JavaDoc traceDirectory) {
866         this.traceDirectory = traceDirectory;
867     }
868
869     public String JavaDoc getTraceDirectory() {
870         return this.traceDirectory;
871     }
872
873     synchronized public void setTraceFileAppend(boolean traceFileAppend) {
874         this.traceFileAppend = traceFileAppend;
875     }
876
877     public boolean getTraceFileAppend() {
878         return this.traceFileAppend;
879     }
880
881
882     // --- private helper methods
883

884
885     /**
886      * The dataSource keeps individual fields for the values that are relevant to the client. These need to be updated
887      * when set connection attributes is called.
888      */

889     void updateDataSourceValues(Properties JavaDoc prop) {
890         if (prop == null) {
891             return;
892         }
893         
894         if (prop.containsKey(Attribute.USERNAME_ATTR)) {
895             setUser(getUser(prop));
896         }
897         if (prop.containsKey(Attribute.CLIENT_SECURITY_MECHANISM)) {
898             setSecurityMechanism(getSecurityMechanism(prop));
899         }
900         if (prop.containsKey(Attribute.CLIENT_TRACE_FILE)) {
901             setTraceFile(getTraceFile(prop));
902         }
903         if (prop.containsKey(Attribute.CLIENT_TRACE_DIRECTORY)) {
904             setTraceDirectory(getTraceDirectory(prop));
905         }
906         if (prop.containsKey(Attribute.CLIENT_TRACE_APPEND)) {
907             setTraceFileAppend(getTraceFileAppend(prop));
908         }
909         if (prop.containsKey(Attribute.CLIENT_RETIEVE_MESSAGE_TEXT)) {
910             setRetrieveMessageText(getRetrieveMessageText(prop));
911         }
912     }
913 }
914
Popular Tags