KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2
3    Derby - Class org.apache.derby.jdbc.EmbeddedDataSource
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 org.apache.derby.iapi.reference.Attribute;
25
26 import java.sql.Connection JavaDoc;
27 import java.sql.DriverManager JavaDoc;
28 import java.sql.SQLException JavaDoc;
29
30 import java.io.PrintWriter JavaDoc;
31 import java.util.Properties JavaDoc;
32
33 /* -- New jdbc 20 extension types --- */
34 import javax.sql.DataSource JavaDoc;
35
36
37 import org.apache.derby.iapi.reference.Attribute;
38 import org.apache.derby.iapi.reference.MessageId;
39 import org.apache.derby.iapi.reference.SQLState;
40 import org.apache.derby.iapi.error.ExceptionSeverity;
41 import org.apache.derby.iapi.services.i18n.MessageService;
42 import org.apache.derby.impl.jdbc.Util;
43
44 /**
45     
46
47     EmbeddedDataSource is Derby's DataSource implementation for JDBC3.0 and JDBC2.0.
48     
49
50     <P>A DataSource is a factory for Connection objects. An object that
51     implements the DataSource interface will typically be registered with a
52     JNDI service provider.
53     <P>
54     EmbeddedDataSource automatically supports the correct JDBC specification version
55     for the Java Virtual Machine's environment.
56     <UL>
57     <LI> JDBC 3.0 - Java 2 - JDK 1.4, J2SE 5.0
58     <LI> JDBC 2.0 - Java 2 - JDK 1.2,1.3
59     </UL>
60
61     <P>The following is a list of properties that can be set on a Derby
62     DataSource object:
63     <P><B>Standard DataSource properties</B> (from JDBC 3.0 specification).
64
65     <UL><LI><B><code>databaseName</code></B> (String): <I>Mandatory</I>
66     <BR>This property must be set and it
67     identifies which database to access. If a database named wombat located at
68     g:/db/wombat is to be accessed, then one should call
69     <code>setDatabaseName("g:/db/wombat")</code> on the data source object.</LI>
70
71     <LI><B><code>dataSourceName</code></B> (String): <I>Optional</I>
72     <BR> Name for DataSource. Not used by the data source object. Used for
73     informational purpose only.</LI>
74
75     <LI><B><code>description</code></B> (String): <I>Optional</I>
76     <BR>Description of the data source. Not
77     used by the data source object. Used for informational purpose only.</LI>
78
79     <LI><B><code>password</code></B> (String): <I>Optional</I>
80     <BR>Database password for the no argument <code>DataSource.getConnection()</code>,
81     <code>ConnectionPoolDataSource.getPooledConnection()</code>
82     and <code>XADataSource.getXAConnection()</code> methods.
83
84     <LI><B><code>user</code></B> (String): <I>Optional</I>
85     <BR>Database user for the no argument <code>DataSource.getConnection()</code>,
86     <code>ConnectionPoolDataSource.getPooledConnection()</code>
87     and <code>XADataSource.getXAConnection()</code> methods.
88     </UL>
89
90     <BR><B>Derby specific DataSource properties.</B>
91
92   <UL>
93
94   <LI><B><code>attributesAsPassword</code></B> (Boolean): <I>Optional</I>
95     <BR>If true, treat the password value in a
96     <code>DataSource.getConnection(String user, String password)</code>,
97     <code>ConnectionPoolDataSource.getPooledConnection(String user, String password)</code>
98     or <code>XADataSource.getXAConnection(String user, String password)</code> as a set
99     of connection attributes. The format of the attributes is the same as the format
100     of the attributes in the property connectionAttributes. If false the password value
101     is treated normally as the password for the given user.
102     Setting this property to true allows a connection request from an application to
103     provide more authentication information that just a password, for example the request
104     can include the user's password and an encrypted database's boot password.</LI>
105
106   <LI><B><code>connectionAttributes</code></B> (String): <I>Optional</I>
107   <BR>Defines a set of Derby connection attributes for use in all connection requests.
108   The format of the String matches the format of the connection attributes in a Derby JDBC URL.
109   That is a list of attributes in the form <code><I>attribute</I>=<I>value</I></code>, each separated by semi-colon (';').
110   E.g. <code>setConnectionAttributes("bootPassword=erd3234dggd3kazkj3000");</code>.
111   <BR>The database name must be set by the DataSource property <code>databaseName</code> and not by setting the <code>databaseName</code>
112   connection attribute in the <code>connectionAttributes</code> property.
113     <BR>
114    Any attributes that can be set using a property of this DataSource implementation
115    (e.g user, password) should not be set in connectionAttributes. Conflicting
116    settings in connectionAttributes and properties of the DataSource will lead to
117    unexpected behaviour.
118   <BR>Please see the Derby documentation for a complete list of connection attributes. </LI>
119
120   <LI><B><code>createDatabase</code></B> (String): <I>Optional</I>
121     <BR>If set to the string "create", this will
122     cause a new database of <code>databaseName</code> if that database does not already
123     exist. The database is created when a connection object is obtained from
124     the data source. </LI>
125
126     <LI><B><code>shutdownDatabase</code></B> (String): <I>Optional</I>
127     <BR>If set to the string "shutdown",
128     this will cause the database to shutdown when a java.sql.Connection object
129     is obtained from the data source. E.g., If the data source is an
130     XADataSource, a getXAConnection().getConnection() is necessary to cause the
131     database to shutdown.
132
133     </UL>
134
135     <P><B>Examples.</B>
136
137     <P>This is an example of setting a property directly using Derby's
138     EmbeddedDataSource object. This code is typically written by a system integrator :
139     <PRE>
140     *
141     * import org.apache.derby.jdbc.*;
142     *
143     * // dbname is the database name
144     * // if create is true, create the database if necessary
145     * javax.sql.DataSource makeDataSource (String dbname, boolean create)
146     * throws Throwable
147     * {
148     * EmbeddedDataSource ds = new EmbeddedDataSource();
149     * ds.setDatabaseName(dbname);
150     *
151     * if (create)
152     * ds.setCreateDatabase("create");
153     *
154     * return ds;
155     * }
156     </PRE>
157
158     <P>Example of setting properties thru reflection. This code is typically
159     generated by tools or written by a system integrator: <PRE>
160     *
161     * javax.sql.DataSource makeDataSource(String dbname)
162     * throws Throwable
163     * {
164     * Class[] parameter = new Class[1];
165     * parameter[0] = dbname.getClass();
166     * DataSource ds = new EmbeddedDataSource();
167     * Class cl = ds.getClass();
168     *
169     * Method setName = cl.getMethod("setDatabaseName", parameter);
170     * Object[] arg = new Object[1];
171     * arg[0] = dbname;
172     * setName.invoke(ds, arg);
173     *
174     * return ds;
175     * }
176     </PRE>
177
178     <P>Example on how to register a data source object with a JNDI naming
179     service.
180     <PRE>
181     * DataSource ds = makeDataSource("mydb");
182     * Context ctx = new InitialContext();
183     * ctx.bind("jdbc/MyDB", ds);
184     </PRE>
185
186     <P>Example on how to retrieve a data source object from a JNDI naming
187     service.
188     <PRE>
189     * Context ctx = new InitialContext();
190     * DataSource ds = (DataSource)ctx.lookup("jdbc/MyDB");
191     </PRE>
192
193 */

194 public class EmbeddedDataSource extends ReferenceableDataSource implements
195                 javax.sql.DataSource JavaDoc
196 {
197
198     private static final long serialVersionUID = -4945135214995641181L;
199
200     /** instance variables that will be serialized */
201
202     /**
203      * The database name.
204      * @serial
205      */

206     private String JavaDoc databaseName;
207
208     /**
209      * The data source name.
210      * @serial
211      */

212     private String JavaDoc dataSourceName;
213
214     /**
215      * Description of the database.
216      * @serial
217      */

218     private String JavaDoc description;
219
220     /**
221      * Set to "create" if the database should be created.
222      * @serial
223      */

224     private String JavaDoc createDatabase;
225
226     /**
227      * Set to "shutdown" if the database should be shutdown.
228      * @serial
229      */

230     private String JavaDoc shutdownDatabase;
231
232     /**
233      * Derby specific connection attributes.
234      * @serial
235      */

236     private String JavaDoc connectionAttributes;
237
238     /**
239         Set password to be a set of connection attributes.
240     */

241     private boolean attributesAsPassword;
242
243     /** instance variables that will not be serialized */
244     transient private PrintWriter JavaDoc printer;
245     transient private int loginTimeout;
246
247     // Unlike a DataSource, LocalDriver is shared by all
248
// Derby databases in the same jvm.
249
transient InternalDriver driver;
250
251     transient private String JavaDoc jdbcurl;
252
253     /**
254         No-arg constructor.
255      */

256     public EmbeddedDataSource() {
257         // needed by Object Factory
258

259         // don't put anything in here or in any of the set method because this
260
// object may be materialized in a remote machine and then sent thru
261
// the net to the machine where it will be used.
262
}
263
264
265   //Most of our customers would be using jndi to get the data
266
//sources. Since we don't have a jndi to test this, we are
267
//adding this method to fake it. This is getting used in
268
//xaJNDI test so we can compare the 2 data sources.
269
public boolean equals(Object JavaDoc p0) {
270     if (p0 instanceof EmbeddedDataSource) {
271       EmbeddedDataSource ds = (EmbeddedDataSource)p0;
272
273       boolean match = true;
274       
275             if (databaseName != null) {
276         if (!(databaseName.equals(ds.databaseName)))
277                     match = false;
278             } else if (ds.databaseName != null)
279         match = false;
280
281             if (dataSourceName != null) {
282         if (!(dataSourceName.equals(ds.dataSourceName)))
283                     match = false;
284             } else if (ds.dataSourceName != null)
285         match = false;
286
287             if (description != null) {
288         if (!(description.equals(ds.description)))
289                     match = false;
290             } else if (ds.description != null)
291         match = false;
292
293             if (createDatabase != null) {
294         if (!(createDatabase.equals(ds.createDatabase)))
295                     match = false;
296             } else if (ds.createDatabase != null)
297         match = false;
298
299             if (shutdownDatabase != null) {
300         if (!(shutdownDatabase.equals(ds.shutdownDatabase)))
301                     match = false;
302             } else if (ds.shutdownDatabase != null)
303         match = false;
304
305             if (connectionAttributes != null) {
306         if (!(connectionAttributes.equals(ds.connectionAttributes)))
307                     match = false;
308             } else if (ds.connectionAttributes != null)
309         match = false;
310
311       if (loginTimeout != ds.loginTimeout)
312         match = false;
313
314       return match;
315
316     }
317
318     return false;
319     }
320
321     /*
322      * Properties to be seen by Bean - access thru reflection.
323      */

324
325     /**
326         Set this property to create a new database. If this
327         property is not set, the database (identified by databaseName) is
328         assumed to be already existing.
329
330         @param create if set to the string "create", this data source will try
331         to create a new database of databaseName, or boot the database if one
332         by that name already exists.
333      */

334     public final void setCreateDatabase(String JavaDoc create) {
335         if (create != null && create.toLowerCase(java.util.Locale.ENGLISH).equals("create"))
336             createDatabase = create;
337         else
338             createDatabase = null;
339     }
340     /** @return "create" if create is set, or null if not */
341     public final String JavaDoc getCreateDatabase() {
342         return createDatabase;
343     }
344
345
346     /**
347         Set this property if one wishes to shutdown the database identified by
348         databaseName.
349
350         @param shutdown if set to the string "shutdown", this data source will
351         shutdown the database if it is running.
352      */

353     public final void setShutdownDatabase(String JavaDoc shutdown) {
354         if (shutdown != null && shutdown.equalsIgnoreCase("shutdown"))
355             shutdownDatabase = shutdown;
356         else
357             shutdownDatabase = null;
358     }
359     /** @return "shutdown" if shutdown is set, or null if not */
360     public final String JavaDoc getShutdownDatabase() {
361         return shutdownDatabase;
362     }
363
364     /**
365         Set this property to pass in more Derby specific
366         connection URL attributes.
367         <BR>
368        Any attributes that can be set using a property of this DataSource implementation
369        (e.g user, password) should not be set in connectionAttributes. Conflicting
370        settings in connectionAttributes and properties of the DataSource will lead to
371        unexpected behaviour.
372
373         @param prop set to the list of Derby connection
374         attributes separated by semi-colons. E.g., to specify an encryption
375         bootPassword of "x8hhk2adf", and set upgrade to true, do the following:
376         <PRE>
377             ds.setConnectionAttributes("bootPassword=x8hhk2adf;upgrade=true");
378         </PRE>
379         See the Derby documentation for complete list.
380      */

381     public final void setConnectionAttributes(String JavaDoc prop) {
382          connectionAttributes = prop;
383          update();
384     }
385     /** @return Derby specific connection URL attributes */
386     public final String JavaDoc getConnectionAttributes() {
387         return connectionAttributes;
388     }
389
390
391     /**
392         Set attributeAsPassword property to enable passing connection request attributes in the password argument of getConnection.
393         If the property is set to true then the password argument of the DataSource.getConnection(String user, String password)
394         method call is taken to be a list of connection attributes with the same format as the connectionAttributes property.
395
396         @param attributesAsPassword true to encode password argument as a set of connection attributes in a connection request.
397     */

398     public final void setAttributesAsPassword(boolean attributesAsPassword) {
399         this.attributesAsPassword = attributesAsPassword;
400          update();
401     }
402
403     /**
404         Return the value of the attributesAsPassword property.
405     */

406     public final boolean getAttributesAsPassword() {
407         return attributesAsPassword;
408     }
409
410     /*
411      * DataSource methods
412      */

413
414
415     /**
416      * Attempt to establish a database connection.
417      *
418      * @return a Connection to the database
419      * @exception SQLException if a database-access error occurs.
420      */

421     public final Connection JavaDoc getConnection() throws SQLException JavaDoc
422     {
423         return this.getConnection(getUser(), getPassword(), false);
424     }
425
426     /**
427      * Attempt to establish a database connection with the given username and password.
428        If the attributeAsPassword property is set to true then the password argument is taken to be a list of
429        connection attributes with the same format as the connectionAttributes property.
430
431      *
432      * @param username the database user on whose behalf the Connection is
433      * being made
434      * @param password the user's password
435      * @return a Connection to the database
436      * @exception SQLException if a database-access error occurs.
437      */

438     public final Connection JavaDoc getConnection(String JavaDoc username, String JavaDoc password)
439          throws SQLException JavaDoc
440     {
441         return this.getConnection(username, password, true);
442     }
443
444     /**
445         @param requestPassword true if the password came from the getConnection() call.
446     */

447     final Connection JavaDoc getConnection(String JavaDoc username, String JavaDoc password, boolean requestPassword)
448         throws SQLException JavaDoc {
449
450         Properties JavaDoc info = new Properties JavaDoc();
451         if (username != null)
452             info.put(Attribute.USERNAME_ATTR, username);
453
454         if (!requestPassword || !attributesAsPassword)
455         {
456             if (password != null)
457                 info.put(Attribute.PASSWORD_ATTR, password);
458         }
459
460         if (createDatabase != null)
461             info.put(Attribute.CREATE_ATTR, "true");
462         if (shutdownDatabase != null)
463             info.put(Attribute.SHUTDOWN_ATTR, "true");
464
465         String JavaDoc url = jdbcurl;
466
467         if (attributesAsPassword && requestPassword && password != null) {
468
469
470             StringBuffer JavaDoc sb = new StringBuffer JavaDoc(url.length() + password.length() + 1);
471
472             sb.append(url);
473             sb.append(';');
474             sb.append(password); // these are now request attributes on the URL
475

476             url = sb.toString();
477
478         }
479         Connection JavaDoc conn = findDriver().connect(url, info);
480
481     // JDBC driver's getConnection method returns null if
482
// the driver does not handle the request's URL.
483
if (conn == null)
484            throw Util.generateCsSQLException(SQLState.PROPERTY_INVALID_VALUE,Attribute.DBNAME_ATTR,getDatabaseName());
485
486         return conn;
487     }
488    
489     InternalDriver findDriver() throws SQLException JavaDoc
490     {
491         String JavaDoc url = jdbcurl;
492
493         if (driver == null || !driver.acceptsURL(url))
494         {
495             synchronized(this)
496             {
497                 // The driver has either never been booted, or it has been
498
// shutdown by a 'jdbc:derby:;shutdown=true'
499
if (driver == null || !driver.acceptsURL(url))
500                 {
501
502                     new org.apache.derby.jdbc.EmbeddedDriver();
503
504                     // If we know the driver, we loaded it. Otherwise only
505
// work if DriverManager has already loaded it.
506

507                     AutoloadedDriver autoloadedDriver =
508                         (AutoloadedDriver) DriverManager.getDriver(url);
509                     driver = (InternalDriver) autoloadedDriver.getDriverModule();
510                     // DriverManager will throw an exception if it cannot find the driver
511
}
512             }
513         }
514         return driver;
515         // else driver != null and driver can accept url
516
}
517
518     void update()
519     {
520         StringBuffer JavaDoc sb = new StringBuffer JavaDoc(64);
521
522         sb.append(Attribute.PROTOCOL);
523
524
525         // Set the database name from the databaseName property
526
String JavaDoc dbName = getDatabaseName();
527
528         if (dbName != null) {
529             dbName = dbName.trim();
530         }
531
532         if (dbName == null || dbName.length() == 0) {
533             // need to put something in so that we do not allow the
534
// database name to be set from the request or from the
535
// connection attributes.
536

537             // this space will selected as the database name (and trimmed to an empty string)
538
// See the getDatabaseName() code in InternalDriver. Since this is a non-null
539
// value, it will be selected over any databaseName connection attribute.
540
dbName = " ";
541         }
542
543         sb.append(dbName);
544
545
546         String JavaDoc connAttrs = getConnectionAttributes();
547         if (connAttrs != null) {
548             connAttrs = connAttrs.trim();
549             if (connAttrs.length() != 0) {
550                 sb.append(';');
551                 sb.append(connectionAttributes);
552             }
553         }
554
555         jdbcurl = sb.toString();
556     }
557 }
558
Popular Tags