EMMA Coverage Report (generated Wed Jun 28 22:15:27 PDT 2006)
[all classes][org.apache.derby.jdbc]

COVERAGE SUMMARY FOR SOURCE FILE [InternalDriver.java]

nameclass, %method, %block, %line, %
InternalDriver.java100% (1/1)100% (21/21)95%  (406/426)96%  (94.2/98)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class InternalDriver100% (1/1)100% (21/21)95%  (406/426)96%  (94.2/98)
<static initializer> 100% (1/1)100% (5/5)100% (1/1)
InternalDriver (): void 100% (1/1)100% (6/6)100% (3/3)
acceptsURL (String): boolean 100% (1/1)100% (23/23)100% (1/1)
activeDriver (): InternalDriver 100% (1/1)100% (2/2)100% (1/1)
boot (boolean, Properties): void 100% (1/1)72%  (13/18)93%  (4.6/5)
checkBoolean (Properties, String): void 100% (1/1)100% (16/16)100% (3/3)
checkEnumeration (Properties, String, String []): void 100% (1/1)100% (71/71)100% (12/12)
connect (String, Properties): Connection 100% (1/1)92%  (86/93)91%  (21/23)
getAttributes (String, Properties): FormatableProperties 100% (1/1)100% (62/62)100% (15/15)
getAuthenticationService (): AuthenticationService 100% (1/1)95%  (19/20)98%  (3.9/4)
getConnectionContext (): ConnectionContext 100% (1/1)100% (14/14)100% (5/5)
getContextServiceFactory (): ContextService 100% (1/1)100% (3/3)100% (1/1)
getCurrentContextManager (): ContextManager 100% (1/1)100% (4/4)100% (1/1)
getDatabaseName (String, Properties): String 100% (1/1)95%  (38/40)91%  (10/11)
getMajorVersion (): int 100% (1/1)100% (4/4)100% (1/1)
getMinorVersion (): int 100% (1/1)100% (4/4)100% (1/1)
isActive (): boolean 100% (1/1)100% (3/3)100% (1/1)
jdbcCompliant (): boolean 100% (1/1)100% (2/2)100% (1/1)
newEmbedDatabaseMetaData (EmbedConnection, String): DatabaseMetaData 100% (1/1)100% (6/6)100% (1/1)
newEmbedStatement (EmbedConnection, boolean, int, int, int): Statement 100% (1/1)100% (9/9)100% (1/1)
stop (): void 100% (1/1)76%  (16/21)94%  (5.6/6)

1 
2/*
3 
4   Derby - Class org.apache.derby.jdbc.InternalDriver
5 
6   Copyright 1997, 2005 The Apache Software Foundation or its licensors, as applicable.
7 
8   Licensed under the Apache License, Version 2.0 (the "License");
9   you may not use this file except in compliance with the License.
10   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 
22package org.apache.derby.jdbc;
23 
24import org.apache.derby.iapi.reference.Attribute;
25import org.apache.derby.iapi.reference.SQLState;
26import org.apache.derby.iapi.reference.MessageId;
27import org.apache.derby.iapi.services.io.FormatableProperties;
28 
29import org.apache.derby.iapi.jdbc.ConnectionContext;
30 
31import org.apache.derby.iapi.services.monitor.ModuleControl;
32import org.apache.derby.iapi.services.monitor.Monitor;
33import org.apache.derby.iapi.services.context.ContextService;
34import org.apache.derby.iapi.services.context.ContextManager;
35import org.apache.derby.iapi.services.sanity.SanityManager;
36import org.apache.derby.iapi.error.StandardException;
37import org.apache.derby.iapi.services.i18n.MessageService;
38 
39import org.apache.derby.iapi.sql.ResultSet;
40 
41import org.apache.derby.iapi.jdbc.AuthenticationService;
42import org.apache.derby.iapi.sql.ResultColumnDescriptor;
43 
44import org.apache.derby.impl.jdbc.*;
45 
46import java.sql.Connection;
47import java.sql.DatabaseMetaData;
48import java.sql.SQLException;
49 
50import java.util.Properties;
51import java.util.StringTokenizer;
52 
53 
54/**
55        Abstract factory class and api for JDBC objects.
56        @author djd
57*/
58 
59public abstract class InternalDriver implements ModuleControl {
60    
61        private static final Object syncMe = new Object();
62        private static InternalDriver activeDriver;
63 
64        protected boolean active;
65        private ContextService contextServiceFactory;
66        private AuthenticationService        authenticationService;
67 
68        public static final InternalDriver activeDriver()
69        {
70                return activeDriver;
71        }
72 
73        public InternalDriver() {
74                contextServiceFactory = ContextService.getFactory();
75        }
76 
77        /*
78        **        Methods from ModuleControl
79        */
80 
81        public void boot(boolean create, Properties properties) throws StandardException {
82 
83                synchronized (InternalDriver.syncMe)
84                {
85                        InternalDriver.activeDriver = this;
86                }
87 
88                active = true;
89        }
90 
91        public void stop() {
92 
93                synchronized (InternalDriver.syncMe)
94                {
95                        InternalDriver.activeDriver = null;
96                }
97 
98                active = false;
99 
100                contextServiceFactory = null;
101        }
102 
103        /*
104        ** Methods from java.sql.Driver
105        */
106        public boolean acceptsURL(String url) {
107                return active &&
108                //        need to reject network driver's URL's
109                !url.startsWith(Attribute.JCC_PROTOCOL) && !url.startsWith(Attribute.DNC_PROTOCOL) &&
110                (url.startsWith(Attribute.PROTOCOL) || url.equals(Attribute.SQLJ_NESTED));
111                                
112        }
113 
114        public Connection connect(String url, Properties info)
115                 throws SQLException 
116        {
117                if (!acceptsURL(url)) { return null; }
118                
119        /**
120         * If we are below the low memory watermark for obtaining
121         * a connection, then don't even try. Just throw an exception.
122         */
123                if (EmbedConnection.memoryState.isLowMemory())
124                {
125                        throw EmbedConnection.NO_MEM;
126                }
127                                
128                /*
129                ** A url "jdbc:default:connection" means get the current
130                ** connection.  From within a method called from JSQL, the
131                ** "current" connection is the one that is running the
132                ** JSQL statement containing the method call.
133                */
134                boolean current = url.equals(Attribute.SQLJ_NESTED);
135                
136                /* If jdbc:default:connection, see if user already has a
137                 * connection. All connection attributes are ignored.
138                 */
139                if (current) {
140 
141                        ConnectionContext connContext = getConnectionContext();
142 
143                        if (connContext != null) {
144                                                
145                                return connContext.getNestedConnection(false);
146                                
147                        }
148                        // there is no cloudscape connection, so
149                        // return null, as we are not the driver to handle this
150                        return null;
151                }
152 
153                // convert the ;name=value attributes in the URL into
154                // properties.
155                FormatableProperties finfo = null;
156        
157                try {
158            
159            finfo = getAttributes(url, info);
160            info = null; // ensure we don't use this reference directly again.
161 
162                        /*
163                        ** A property "shutdown=true" means shut the system or database down
164                        */
165                        boolean shutdown = Boolean.valueOf(finfo.getProperty(Attribute.SHUTDOWN_ATTR)).booleanValue();
166                        
167                        if (shutdown) {
168                                
169                                // If we are shutting down the system don't attempt to create
170                                // a connection; but we validate users credentials if we have to.
171                                // In case of datbase shutdown, we ask the database authentication
172                                // service to authenticate the user. If it is a system shutdown,
173                                // then we ask the Driver to do the authentication.
174                                //
175                                if (InternalDriver.getDatabaseName(url, finfo).length() == 0) {
176                                        //
177                                        // We need to authenticate the user if authentication is
178                                        // ON. Note that this is a system shutdown.
179                                        // check that we do have a authentication service
180                                        // it is _always_ expected.
181                                        if (this.getAuthenticationService() == null)
182                                                throw Util.generateCsSQLException(
183                        SQLState.LOGIN_FAILED, 
184                                                MessageService.getTextMessage(MessageId.AUTH_NO_SERVICE_FOR_SYSTEM));
185                                        
186                                                
187                                        if (!this.getAuthenticationService().authenticate((String) null, finfo)) {
188 
189                                                // not a valid user
190                                                throw Util.generateCsSQLException(
191                                  SQLState.LOGIN_FAILED, MessageService.getTextMessage(MessageId.AUTH_INVALID));
192                                        }
193 
194                                        Monitor.getMonitor().shutdown();
195                                        throw Util.generateCsSQLException(
196                                         SQLState.CLOUDSCAPE_SYSTEM_SHUTDOWN);
197                                }
198                        }
199                        
200                        EmbedConnection conn = getNewEmbedConnection(url, finfo);
201 
202                        // if this is not the correct driver a EmbedConnection
203                        // object is returned in the closed state.
204                        if (conn.isClosed()) {
205                                return null;
206                        }
207 
208                        return conn;
209                }
210                catch (OutOfMemoryError noMemory)
211                {
212                        EmbedConnection.memoryState.setLowMemory();
213                        throw EmbedConnection.NO_MEM;
214                }
215                finally {
216                        // break any link with the user's Properties set.
217            if (finfo != null)
218                            finfo.clearDefaults();
219                }
220        }
221 
222        public int getMajorVersion() {
223                return Monitor.getMonitor().getEngineVersion().getMajorVersion();
224        }
225        
226        public int getMinorVersion() {
227                return Monitor.getMonitor().getEngineVersion().getMinorVersion();
228        }
229 
230        public boolean jdbcCompliant() {
231                return true;
232        }
233 
234        /*
235        ** URL manipulation
236        */
237 
238        /**
239                Convert all the attributes in the url into properties and
240                combine them with the set provided. 
241                <BR>
242                If the caller passed in a set of attributes (info != null)
243                then we set that up as the default of the returned property
244                set as the user's set. This means we can easily break the link
245                with the user's set, ensuring that we don't hang onto the users object.
246                It also means that we don't add our attributes into the user's
247                own property object.
248 
249                @exception SQLException thrown if URL form bad
250        */
251        protected FormatableProperties getAttributes(String url, Properties info) 
252                throws SQLException {
253 
254                // We use FormatableProperties here to take advantage
255                // of the clearDefaults, method.
256                FormatableProperties finfo = new FormatableProperties(info);
257                info = null; // ensure we don't use this reference directly again.
258 
259 
260                StringTokenizer st = new StringTokenizer(url, ";");
261                st.nextToken(); // skip the first part of the url
262 
263                while (st.hasMoreTokens()) {
264 
265                        String v = st.nextToken();
266 
267                        int eqPos = v.indexOf('=');
268                        if (eqPos == -1)
269                                throw Util.generateCsSQLException(
270                                            SQLState.MALFORMED_URL, url);
271 
272                        //if (eqPos != v.lastIndexOf('='))
273                        //        throw Util.malformedURL(url);
274 
275                        finfo.put((v.substring(0, eqPos)).trim(),
276                                         (v.substring(eqPos + 1)).trim()
277                                        );
278                }
279 
280                // now validate any attributes we can
281                //
282                // Boolean attributes -
283                //  dataEncryption,create,createSource,convertToSource,shutdown,upgrade,current
284 
285 
286                checkBoolean(finfo, Attribute.DATA_ENCRYPTION);
287                checkBoolean(finfo, Attribute.CREATE_ATTR);
288                checkBoolean(finfo, Attribute.SHUTDOWN_ATTR);
289                checkBoolean(finfo, Attribute.UPGRADE_ATTR);
290 
291                return finfo;
292        }
293 
294        private static void checkBoolean(Properties set, String attribute) throws SQLException
295    {
296        final String[] booleanChoices = {"true", "false"};
297        checkEnumeration( set, attribute, booleanChoices);
298        }
299 
300 
301        private static void checkEnumeration(Properties set, String attribute, String[] choices) throws SQLException
302    {
303                String value = set.getProperty(attribute);
304                if (value == null)
305                        return;
306 
307        for( int i = 0; i < choices.length; i++)
308        {
309            if( value.toUpperCase(java.util.Locale.ENGLISH).equals( choices[i].toUpperCase(java.util.Locale.ENGLISH)))
310                return;
311        }
312 
313        // The attribute value is invalid. Construct a string giving the choices for
314        // display in the error message.
315        String choicesStr = "{";
316        for( int i = 0; i < choices.length; i++)
317        {
318            if( i > 0)
319                choicesStr += "|";
320            choicesStr += choices[i];
321        }
322        
323                throw Util.generateCsSQLException(
324                SQLState.INVALID_ATTRIBUTE, attribute, value, choicesStr + "}");
325        }
326 
327 
328        /**
329                Get the database name from the url.
330                Copes with three forms
331 
332                jdbc:derby:dbname
333                jdbc:derby:dbname;...
334                jdbc:derby:;subname=dbname
335 
336                @param url The url being used for the connection
337                @param info The properties set being used for the connection, must include
338                the properties derived from the attributes in the url
339 
340                @return a String containing the database name or an empty string ("") if
341                no database name is present in the URL.
342        */
343        public static String getDatabaseName(String url, Properties info) {
344 
345                if (url.equals(Attribute.SQLJ_NESTED))
346                {
347                        return "";
348                }        
349                
350                // skip the jdbc:derby:
351                int attributeStart = url.indexOf(';');
352                String dbname;
353                if (attributeStart == -1)
354                        dbname = url.substring(Attribute.PROTOCOL.length());
355                else
356                        dbname = url.substring(Attribute.PROTOCOL.length(), attributeStart);
357 
358                // For security reasons we rely on here an non-null string being
359                // taken as the database name, before the databaseName connection
360                // attribute. Specifically, even if dbname is blank we still we
361                // to use it rather than the connection attribute, even though
362                // it will end up, after the trim, as a zero-length string.
363                // See EmbeddedDataSource.update()
364 
365                if (dbname.length() == 0) {
366                    if (info != null)
367                                dbname = info.getProperty(Attribute.DBNAME_ATTR, dbname);
368                }
369                // Beetle 4653 - trim database name to remove blanks that might make a difference on finding the database
370                // on unix platforms
371                dbname = dbname.trim();
372 
373                return dbname;
374        }
375 
376        public final ContextService getContextServiceFactory() {
377                return contextServiceFactory;
378        }
379 
380        // returns the authenticationService handle
381        public AuthenticationService getAuthenticationService() {
382                //
383                // If authenticationService handle not cached in yet, then
384                // ask the monitor to find it for us and set it here in its
385                // attribute.
386                //
387                if (this.authenticationService == null) {
388                        this.authenticationService = (AuthenticationService)
389                                Monitor.findService(AuthenticationService.MODULE,
390                                                                        "authentication"
391                                                                   );
392                }
393 
394                // We should have a Authentication Service (always)
395                //
396                if (SanityManager.DEBUG)
397                {
398                        SanityManager.ASSERT(this.authenticationService != null, 
399                                "Unexpected - There is no valid authentication service!");
400                }
401                return this.authenticationService;
402        }
403 
404        /*
405                Methods to be overloaded in sub-implementations such as
406                a tracing driver.
407         */
408        protected abstract EmbedConnection getNewEmbedConnection(String url, Properties info) 
409                 throws SQLException ;
410 
411 
412        private ConnectionContext getConnectionContext() {
413 
414                /*
415                ** The current connection is the one in the current
416                ** connection context, so get the context.
417                */
418                ContextManager        cm = getCurrentContextManager();
419 
420                ConnectionContext localCC = null;
421 
422                /*
423                        cm is null the very first time, and whenever
424                        we aren't actually nested.
425                 */
426                if (cm != null) {
427                        localCC = (ConnectionContext)
428                                (cm.getContext(ConnectionContext.CONTEXT_ID));
429                }
430 
431                return localCC;
432        }
433 
434        private ContextManager getCurrentContextManager() {
435                return getContextServiceFactory().getCurrentContextManager();
436        }
437 
438 
439        /**
440                Return true if this driver is active. Package private method.
441        */
442        public boolean isActive() {
443                return active;
444        }
445 
446        /**
447          * Get a new nested connection.
448         *
449         * @param conn        The EmbedConnection.
450         *
451         * @return A nested connection object.
452         *
453         */
454        public abstract Connection getNewNestedConnection(EmbedConnection conn);
455 
456        /*
457        ** methods to be overridden by subimplementations wishing to insert
458        ** their classes into the mix.
459        */
460 
461        public java.sql.Statement newEmbedStatement(
462                                EmbedConnection conn,
463                                boolean forMetaData,
464                                int resultSetType,
465                                int resultSetConcurrency,
466                                int resultSetHoldability)
467        {
468                return new EmbedStatement(conn, forMetaData, resultSetType, resultSetConcurrency,
469                resultSetHoldability);
470        }
471        /**
472                 @exception SQLException if fails to create statement
473         */
474        public abstract java.sql.PreparedStatement newEmbedPreparedStatement(
475                                EmbedConnection conn,
476                                String stmt, 
477                                boolean forMetaData, 
478                                int resultSetType,
479                                int resultSetConcurrency,
480                                int resultSetHoldability,
481                                int autoGeneratedKeys,
482                                int[] columnIndexes,
483                                String[] columnNames)
484                throws SQLException;
485 
486        /**
487                 @exception SQLException if fails to create statement
488         */
489        public abstract java.sql.CallableStatement newEmbedCallableStatement(
490                                EmbedConnection conn,
491                                String stmt, 
492                                int resultSetType,
493                                int resultSetConcurrency,
494                                int resultSetHoldability)
495                throws SQLException;
496 
497        /**
498         * Return a new java.sql.DatabaseMetaData instance for this implementation.
499                 @exception SQLException on failure to create.
500         */
501        public DatabaseMetaData newEmbedDatabaseMetaData(EmbedConnection conn,
502                String dbname) throws SQLException {
503                return new EmbedDatabaseMetaData(conn,dbname);
504        }
505 
506        /**
507         * Return a new java.sql.ResultSet instance for this implementation.
508         * @param conn Owning connection
509         * @param results Top level of language result set tree
510         * @param forMetaData Is this for meta-data
511         * @param statement The statement that is creating the SQL ResultSet
512         * @param isAtomic 
513         * @return a new java.sql.ResultSet
514         * @throws SQLException
515         */
516        public abstract EmbedResultSet
517                newEmbedResultSet(EmbedConnection conn, ResultSet results, boolean forMetaData, EmbedStatement statement, boolean isAtomic) throws SQLException;
518        
519        /**
520         * Returns a new java.sql.ResultSetMetaData for this implementation
521         *
522         * @param columnInfo a ResultColumnDescriptor that stores information 
523         *        about the columns in a ResultSet
524         */
525        public EmbedResultSetMetaData newEmbedResultSetMetaData
526                           (ResultColumnDescriptor[] columnInfo) {
527            return new EmbedResultSetMetaData(columnInfo);
528        }
529}
530 
531 
532 

[all classes][org.apache.derby.jdbc]
EMMA 2.0.5312 (C) Vladimir Roubtsov