Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/java/sql/DriverManager.java
38829 views
1
/*
2
* Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
26
package java.sql;
27
28
import java.util.Iterator;
29
import java.util.ServiceLoader;
30
import java.security.AccessController;
31
import java.security.PrivilegedAction;
32
import java.util.concurrent.CopyOnWriteArrayList;
33
import sun.reflect.CallerSensitive;
34
import sun.reflect.Reflection;
35
36
37
/**
38
* <P>The basic service for managing a set of JDBC drivers.<br>
39
* <B>NOTE:</B> The {@link javax.sql.DataSource} interface, new in the
40
* JDBC 2.0 API, provides another way to connect to a data source.
41
* The use of a <code>DataSource</code> object is the preferred means of
42
* connecting to a data source.
43
*
44
* <P>As part of its initialization, the <code>DriverManager</code> class will
45
* attempt to load the driver classes referenced in the "jdbc.drivers"
46
* system property. This allows a user to customize the JDBC Drivers
47
* used by their applications. For example in your
48
* ~/.hotjava/properties file you might specify:
49
* <pre>
50
* <CODE>jdbc.drivers=foo.bah.Driver:wombat.sql.Driver:bad.taste.ourDriver</CODE>
51
* </pre>
52
*<P> The <code>DriverManager</code> methods <code>getConnection</code> and
53
* <code>getDrivers</code> have been enhanced to support the Java Standard Edition
54
* <a href="../../../technotes/guides/jar/jar.html#Service%20Provider">Service Provider</a> mechanism. JDBC 4.0 Drivers must
55
* include the file <code>META-INF/services/java.sql.Driver</code>. This file contains the name of the JDBC drivers
56
* implementation of <code>java.sql.Driver</code>. For example, to load the <code>my.sql.Driver</code> class,
57
* the <code>META-INF/services/java.sql.Driver</code> file would contain the entry:
58
* <pre>
59
* <code>my.sql.Driver</code>
60
* </pre>
61
*
62
* <P>Applications no longer need to explicitly load JDBC drivers using <code>Class.forName()</code>. Existing programs
63
* which currently load JDBC drivers using <code>Class.forName()</code> will continue to work without
64
* modification.
65
*
66
* <P>When the method <code>getConnection</code> is called,
67
* the <code>DriverManager</code> will attempt to
68
* locate a suitable driver from amongst those loaded at
69
* initialization and those loaded explicitly using the same classloader
70
* as the current applet or application.
71
*
72
* <P>
73
* Starting with the Java 2 SDK, Standard Edition, version 1.3, a
74
* logging stream can be set only if the proper
75
* permission has been granted. Normally this will be done with
76
* the tool PolicyTool, which can be used to grant <code>permission
77
* java.sql.SQLPermission "setLog"</code>.
78
* @see Driver
79
* @see Connection
80
*/
81
public class DriverManager {
82
83
84
// List of registered JDBC drivers
85
private final static CopyOnWriteArrayList<DriverInfo> registeredDrivers = new CopyOnWriteArrayList<>();
86
private static volatile int loginTimeout = 0;
87
private static volatile java.io.PrintWriter logWriter = null;
88
private static volatile java.io.PrintStream logStream = null;
89
// Used in println() to synchronize logWriter
90
private final static Object logSync = new Object();
91
92
/* Prevent the DriverManager class from being instantiated. */
93
private DriverManager(){}
94
95
96
/**
97
* Load the initial JDBC drivers by checking the System property
98
* jdbc.properties and then use the {@code ServiceLoader} mechanism
99
*/
100
static {
101
loadInitialDrivers();
102
println("JDBC DriverManager initialized");
103
}
104
105
/**
106
* The <code>SQLPermission</code> constant that allows the
107
* setting of the logging stream.
108
* @since 1.3
109
*/
110
final static SQLPermission SET_LOG_PERMISSION =
111
new SQLPermission("setLog");
112
113
/**
114
* The {@code SQLPermission} constant that allows the
115
* un-register a registered JDBC driver.
116
* @since 1.8
117
*/
118
final static SQLPermission DEREGISTER_DRIVER_PERMISSION =
119
new SQLPermission("deregisterDriver");
120
121
//--------------------------JDBC 2.0-----------------------------
122
123
/**
124
* Retrieves the log writer.
125
*
126
* The <code>getLogWriter</code> and <code>setLogWriter</code>
127
* methods should be used instead
128
* of the <code>get/setlogStream</code> methods, which are deprecated.
129
* @return a <code>java.io.PrintWriter</code> object
130
* @see #setLogWriter
131
* @since 1.2
132
*/
133
public static java.io.PrintWriter getLogWriter() {
134
return logWriter;
135
}
136
137
/**
138
* Sets the logging/tracing <code>PrintWriter</code> object
139
* that is used by the <code>DriverManager</code> and all drivers.
140
* <P>
141
* There is a minor versioning problem created by the introduction
142
* of the method <code>setLogWriter</code>. The
143
* method <code>setLogWriter</code> cannot create a <code>PrintStream</code> object
144
* that will be returned by <code>getLogStream</code>---the Java platform does
145
* not provide a backward conversion. As a result, a new application
146
* that uses <code>setLogWriter</code> and also uses a JDBC 1.0 driver that uses
147
* <code>getLogStream</code> will likely not see debugging information written
148
* by that driver.
149
*<P>
150
* Starting with the Java 2 SDK, Standard Edition, version 1.3 release, this method checks
151
* to see that there is an <code>SQLPermission</code> object before setting
152
* the logging stream. If a <code>SecurityManager</code> exists and its
153
* <code>checkPermission</code> method denies setting the log writer, this
154
* method throws a <code>java.lang.SecurityException</code>.
155
*
156
* @param out the new logging/tracing <code>PrintStream</code> object;
157
* <code>null</code> to disable logging and tracing
158
* @throws SecurityException
159
* if a security manager exists and its
160
* <code>checkPermission</code> method denies
161
* setting the log writer
162
*
163
* @see SecurityManager#checkPermission
164
* @see #getLogWriter
165
* @since 1.2
166
*/
167
public static void setLogWriter(java.io.PrintWriter out) {
168
169
SecurityManager sec = System.getSecurityManager();
170
if (sec != null) {
171
sec.checkPermission(SET_LOG_PERMISSION);
172
}
173
logStream = null;
174
logWriter = out;
175
}
176
177
178
//---------------------------------------------------------------
179
180
/**
181
* Attempts to establish a connection to the given database URL.
182
* The <code>DriverManager</code> attempts to select an appropriate driver from
183
* the set of registered JDBC drivers.
184
*<p>
185
* <B>Note:</B> If a property is specified as part of the {@code url} and
186
* is also specified in the {@code Properties} object, it is
187
* implementation-defined as to which value will take precedence.
188
* For maximum portability, an application should only specify a
189
* property once.
190
*
191
* @param url a database url of the form
192
* <code> jdbc:<em>subprotocol</em>:<em>subname</em></code>
193
* @param info a list of arbitrary string tag/value pairs as
194
* connection arguments; normally at least a "user" and
195
* "password" property should be included
196
* @return a Connection to the URL
197
* @exception SQLException if a database access error occurs or the url is
198
* {@code null}
199
* @throws SQLTimeoutException when the driver has determined that the
200
* timeout value specified by the {@code setLoginTimeout} method
201
* has been exceeded and has at least tried to cancel the
202
* current database connection attempt
203
*/
204
@CallerSensitive
205
public static Connection getConnection(String url,
206
java.util.Properties info) throws SQLException {
207
208
return (getConnection(url, info, Reflection.getCallerClass()));
209
}
210
211
/**
212
* Attempts to establish a connection to the given database URL.
213
* The <code>DriverManager</code> attempts to select an appropriate driver from
214
* the set of registered JDBC drivers.
215
*<p>
216
* <B>Note:</B> If the {@code user} or {@code password} property are
217
* also specified as part of the {@code url}, it is
218
* implementation-defined as to which value will take precedence.
219
* For maximum portability, an application should only specify a
220
* property once.
221
*
222
* @param url a database url of the form
223
* <code>jdbc:<em>subprotocol</em>:<em>subname</em></code>
224
* @param user the database user on whose behalf the connection is being
225
* made
226
* @param password the user's password
227
* @return a connection to the URL
228
* @exception SQLException if a database access error occurs or the url is
229
* {@code null}
230
* @throws SQLTimeoutException when the driver has determined that the
231
* timeout value specified by the {@code setLoginTimeout} method
232
* has been exceeded and has at least tried to cancel the
233
* current database connection attempt
234
*/
235
@CallerSensitive
236
public static Connection getConnection(String url,
237
String user, String password) throws SQLException {
238
java.util.Properties info = new java.util.Properties();
239
240
if (user != null) {
241
info.put("user", user);
242
}
243
if (password != null) {
244
info.put("password", password);
245
}
246
247
return (getConnection(url, info, Reflection.getCallerClass()));
248
}
249
250
/**
251
* Attempts to establish a connection to the given database URL.
252
* The <code>DriverManager</code> attempts to select an appropriate driver from
253
* the set of registered JDBC drivers.
254
*
255
* @param url a database url of the form
256
* <code> jdbc:<em>subprotocol</em>:<em>subname</em></code>
257
* @return a connection to the URL
258
* @exception SQLException if a database access error occurs or the url is
259
* {@code null}
260
* @throws SQLTimeoutException when the driver has determined that the
261
* timeout value specified by the {@code setLoginTimeout} method
262
* has been exceeded and has at least tried to cancel the
263
* current database connection attempt
264
*/
265
@CallerSensitive
266
public static Connection getConnection(String url)
267
throws SQLException {
268
269
java.util.Properties info = new java.util.Properties();
270
return (getConnection(url, info, Reflection.getCallerClass()));
271
}
272
273
/**
274
* Attempts to locate a driver that understands the given URL.
275
* The <code>DriverManager</code> attempts to select an appropriate driver from
276
* the set of registered JDBC drivers.
277
*
278
* @param url a database URL of the form
279
* <code>jdbc:<em>subprotocol</em>:<em>subname</em></code>
280
* @return a <code>Driver</code> object representing a driver
281
* that can connect to the given URL
282
* @exception SQLException if a database access error occurs
283
*/
284
@CallerSensitive
285
public static Driver getDriver(String url)
286
throws SQLException {
287
288
println("DriverManager.getDriver(\"" + url + "\")");
289
290
Class<?> callerClass = Reflection.getCallerClass();
291
292
// Walk through the loaded registeredDrivers attempting to locate someone
293
// who understands the given URL.
294
for (DriverInfo aDriver : registeredDrivers) {
295
// If the caller does not have permission to load the driver then
296
// skip it.
297
if(isDriverAllowed(aDriver.driver, callerClass)) {
298
try {
299
if(aDriver.driver.acceptsURL(url)) {
300
// Success!
301
println("getDriver returning " + aDriver.driver.getClass().getName());
302
return (aDriver.driver);
303
}
304
305
} catch(SQLException sqe) {
306
// Drop through and try the next driver.
307
}
308
} else {
309
println(" skipping: " + aDriver.driver.getClass().getName());
310
}
311
312
}
313
314
println("getDriver: no suitable driver");
315
throw new SQLException("No suitable driver", "08001");
316
}
317
318
319
/**
320
* Registers the given driver with the {@code DriverManager}.
321
* A newly-loaded driver class should call
322
* the method {@code registerDriver} to make itself
323
* known to the {@code DriverManager}. If the driver is currently
324
* registered, no action is taken.
325
*
326
* @param driver the new JDBC Driver that is to be registered with the
327
* {@code DriverManager}
328
* @exception SQLException if a database access error occurs
329
* @exception NullPointerException if {@code driver} is null
330
*/
331
public static synchronized void registerDriver(java.sql.Driver driver)
332
throws SQLException {
333
334
registerDriver(driver, null);
335
}
336
337
/**
338
* Registers the given driver with the {@code DriverManager}.
339
* A newly-loaded driver class should call
340
* the method {@code registerDriver} to make itself
341
* known to the {@code DriverManager}. If the driver is currently
342
* registered, no action is taken.
343
*
344
* @param driver the new JDBC Driver that is to be registered with the
345
* {@code DriverManager}
346
* @param da the {@code DriverAction} implementation to be used when
347
* {@code DriverManager#deregisterDriver} is called
348
* @exception SQLException if a database access error occurs
349
* @exception NullPointerException if {@code driver} is null
350
* @since 1.8
351
*/
352
public static synchronized void registerDriver(java.sql.Driver driver,
353
DriverAction da)
354
throws SQLException {
355
356
/* Register the driver if it has not already been added to our list */
357
if(driver != null) {
358
registeredDrivers.addIfAbsent(new DriverInfo(driver, da));
359
} else {
360
// This is for compatibility with the original DriverManager
361
throw new NullPointerException();
362
}
363
364
println("registerDriver: " + driver);
365
366
}
367
368
/**
369
* Removes the specified driver from the {@code DriverManager}'s list of
370
* registered drivers.
371
* <p>
372
* If a {@code null} value is specified for the driver to be removed, then no
373
* action is taken.
374
* <p>
375
* If a security manager exists and its {@code checkPermission} denies
376
* permission, then a {@code SecurityException} will be thrown.
377
* <p>
378
* If the specified driver is not found in the list of registered drivers,
379
* then no action is taken. If the driver was found, it will be removed
380
* from the list of registered drivers.
381
* <p>
382
* If a {@code DriverAction} instance was specified when the JDBC driver was
383
* registered, its deregister method will be called
384
* prior to the driver being removed from the list of registered drivers.
385
*
386
* @param driver the JDBC Driver to remove
387
* @exception SQLException if a database access error occurs
388
* @throws SecurityException if a security manager exists and its
389
* {@code checkPermission} method denies permission to deregister a driver.
390
*
391
* @see SecurityManager#checkPermission
392
*/
393
@CallerSensitive
394
public static synchronized void deregisterDriver(Driver driver)
395
throws SQLException {
396
if (driver == null) {
397
return;
398
}
399
400
SecurityManager sec = System.getSecurityManager();
401
if (sec != null) {
402
sec.checkPermission(DEREGISTER_DRIVER_PERMISSION);
403
}
404
405
println("DriverManager.deregisterDriver: " + driver);
406
407
DriverInfo aDriver = new DriverInfo(driver, null);
408
if(registeredDrivers.contains(aDriver)) {
409
if (isDriverAllowed(driver, Reflection.getCallerClass())) {
410
DriverInfo di = registeredDrivers.get(registeredDrivers.indexOf(aDriver));
411
// If a DriverAction was specified, Call it to notify the
412
// driver that it has been deregistered
413
if(di.action() != null) {
414
di.action().deregister();
415
}
416
registeredDrivers.remove(aDriver);
417
} else {
418
// If the caller does not have permission to load the driver then
419
// throw a SecurityException.
420
throw new SecurityException();
421
}
422
} else {
423
println(" couldn't find driver to unload");
424
}
425
}
426
427
/**
428
* Retrieves an Enumeration with all of the currently loaded JDBC drivers
429
* to which the current caller has access.
430
*
431
* <P><B>Note:</B> The classname of a driver can be found using
432
* <CODE>d.getClass().getName()</CODE>
433
*
434
* @return the list of JDBC Drivers loaded by the caller's class loader
435
*/
436
@CallerSensitive
437
public static java.util.Enumeration<Driver> getDrivers() {
438
java.util.Vector<Driver> result = new java.util.Vector<>();
439
440
Class<?> callerClass = Reflection.getCallerClass();
441
442
// Walk through the loaded registeredDrivers.
443
for(DriverInfo aDriver : registeredDrivers) {
444
// If the caller does not have permission to load the driver then
445
// skip it.
446
if(isDriverAllowed(aDriver.driver, callerClass)) {
447
result.addElement(aDriver.driver);
448
} else {
449
println(" skipping: " + aDriver.getClass().getName());
450
}
451
}
452
return (result.elements());
453
}
454
455
456
/**
457
* Sets the maximum time in seconds that a driver will wait
458
* while attempting to connect to a database once the driver has
459
* been identified.
460
*
461
* @param seconds the login time limit in seconds; zero means there is no limit
462
* @see #getLoginTimeout
463
*/
464
public static void setLoginTimeout(int seconds) {
465
loginTimeout = seconds;
466
}
467
468
/**
469
* Gets the maximum time in seconds that a driver can wait
470
* when attempting to log in to a database.
471
*
472
* @return the driver login time limit in seconds
473
* @see #setLoginTimeout
474
*/
475
public static int getLoginTimeout() {
476
return (loginTimeout);
477
}
478
479
/**
480
* Sets the logging/tracing PrintStream that is used
481
* by the <code>DriverManager</code>
482
* and all drivers.
483
*<P>
484
* In the Java 2 SDK, Standard Edition, version 1.3 release, this method checks
485
* to see that there is an <code>SQLPermission</code> object before setting
486
* the logging stream. If a <code>SecurityManager</code> exists and its
487
* <code>checkPermission</code> method denies setting the log writer, this
488
* method throws a <code>java.lang.SecurityException</code>.
489
*
490
* @param out the new logging/tracing PrintStream; to disable, set to <code>null</code>
491
* @deprecated Use {@code setLogWriter}
492
* @throws SecurityException if a security manager exists and its
493
* <code>checkPermission</code> method denies setting the log stream
494
*
495
* @see SecurityManager#checkPermission
496
* @see #getLogStream
497
*/
498
@Deprecated
499
public static void setLogStream(java.io.PrintStream out) {
500
501
SecurityManager sec = System.getSecurityManager();
502
if (sec != null) {
503
sec.checkPermission(SET_LOG_PERMISSION);
504
}
505
506
logStream = out;
507
if ( out != null )
508
logWriter = new java.io.PrintWriter(out);
509
else
510
logWriter = null;
511
}
512
513
/**
514
* Retrieves the logging/tracing PrintStream that is used by the <code>DriverManager</code>
515
* and all drivers.
516
*
517
* @return the logging/tracing PrintStream; if disabled, is <code>null</code>
518
* @deprecated Use {@code getLogWriter}
519
* @see #setLogStream
520
*/
521
@Deprecated
522
public static java.io.PrintStream getLogStream() {
523
return logStream;
524
}
525
526
/**
527
* Prints a message to the current JDBC log stream.
528
*
529
* @param message a log or tracing message
530
*/
531
public static void println(String message) {
532
synchronized (logSync) {
533
if (logWriter != null) {
534
logWriter.println(message);
535
536
// automatic flushing is never enabled, so we must do it ourselves
537
logWriter.flush();
538
}
539
}
540
}
541
542
//------------------------------------------------------------------------
543
544
// Indicates whether the class object that would be created if the code calling
545
// DriverManager is accessible.
546
private static boolean isDriverAllowed(Driver driver, Class<?> caller) {
547
ClassLoader callerCL = caller != null ? caller.getClassLoader() : null;
548
return isDriverAllowed(driver, callerCL);
549
}
550
551
private static boolean isDriverAllowed(Driver driver, ClassLoader classLoader) {
552
boolean result = false;
553
if(driver != null) {
554
Class<?> aClass = null;
555
try {
556
aClass = Class.forName(driver.getClass().getName(), true, classLoader);
557
} catch (Exception ex) {
558
result = false;
559
}
560
561
result = ( aClass == driver.getClass() ) ? true : false;
562
}
563
564
return result;
565
}
566
567
private static void loadInitialDrivers() {
568
String drivers;
569
try {
570
drivers = AccessController.doPrivileged(new PrivilegedAction<String>() {
571
public String run() {
572
return System.getProperty("jdbc.drivers");
573
}
574
});
575
} catch (Exception ex) {
576
drivers = null;
577
}
578
// If the driver is packaged as a Service Provider, load it.
579
// Get all the drivers through the classloader
580
// exposed as a java.sql.Driver.class service.
581
// ServiceLoader.load() replaces the sun.misc.Providers()
582
583
AccessController.doPrivileged(new PrivilegedAction<Void>() {
584
public Void run() {
585
586
ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);
587
Iterator<Driver> driversIterator = loadedDrivers.iterator();
588
589
/* Load these drivers, so that they can be instantiated.
590
* It may be the case that the driver class may not be there
591
* i.e. there may be a packaged driver with the service class
592
* as implementation of java.sql.Driver but the actual class
593
* may be missing. In that case a java.util.ServiceConfigurationError
594
* will be thrown at runtime by the VM trying to locate
595
* and load the service.
596
*
597
* Adding a try catch block to catch those runtime errors
598
* if driver not available in classpath but it's
599
* packaged as service and that service is there in classpath.
600
*/
601
try{
602
while(driversIterator.hasNext()) {
603
driversIterator.next();
604
}
605
} catch(Throwable t) {
606
// Do nothing
607
}
608
return null;
609
}
610
});
611
612
println("DriverManager.initialize: jdbc.drivers = " + drivers);
613
614
if (drivers == null || drivers.equals("")) {
615
return;
616
}
617
String[] driversList = drivers.split(":");
618
println("number of Drivers:" + driversList.length);
619
for (String aDriver : driversList) {
620
try {
621
println("DriverManager.Initialize: loading " + aDriver);
622
Class.forName(aDriver, true,
623
ClassLoader.getSystemClassLoader());
624
} catch (Exception ex) {
625
println("DriverManager.Initialize: load failed: " + ex);
626
}
627
}
628
}
629
630
631
// Worker method called by the public getConnection() methods.
632
private static Connection getConnection(
633
String url, java.util.Properties info, Class<?> caller) throws SQLException {
634
/*
635
* When callerCl is null, we should check the application's
636
* (which is invoking this class indirectly)
637
* classloader, so that the JDBC driver class outside rt.jar
638
* can be loaded from here.
639
*/
640
ClassLoader callerCL = caller != null ? caller.getClassLoader() : null;
641
synchronized(DriverManager.class) {
642
// synchronize loading of the correct classloader.
643
if (callerCL == null) {
644
callerCL = Thread.currentThread().getContextClassLoader();
645
}
646
}
647
648
if(url == null) {
649
throw new SQLException("The url cannot be null", "08001");
650
}
651
652
println("DriverManager.getConnection(\"" + url + "\")");
653
654
// Walk through the loaded registeredDrivers attempting to make a connection.
655
// Remember the first exception that gets raised so we can reraise it.
656
SQLException reason = null;
657
658
for(DriverInfo aDriver : registeredDrivers) {
659
// If the caller does not have permission to load the driver then
660
// skip it.
661
if(isDriverAllowed(aDriver.driver, callerCL)) {
662
try {
663
println(" trying " + aDriver.driver.getClass().getName());
664
Connection con = aDriver.driver.connect(url, info);
665
if (con != null) {
666
// Success!
667
println("getConnection returning " + aDriver.driver.getClass().getName());
668
return (con);
669
}
670
} catch (SQLException ex) {
671
if (reason == null) {
672
reason = ex;
673
}
674
}
675
676
} else {
677
println(" skipping: " + aDriver.getClass().getName());
678
}
679
680
}
681
682
// if we got here nobody could connect.
683
if (reason != null) {
684
println("getConnection failed: " + reason);
685
throw reason;
686
}
687
688
println("getConnection: no suitable driver found for "+ url);
689
throw new SQLException("No suitable driver found for "+ url, "08001");
690
}
691
692
693
}
694
695
/*
696
* Wrapper class for registered Drivers in order to not expose Driver.equals()
697
* to avoid the capture of the Driver it being compared to as it might not
698
* normally have access.
699
*/
700
class DriverInfo {
701
702
final Driver driver;
703
DriverAction da;
704
DriverInfo(Driver driver, DriverAction action) {
705
this.driver = driver;
706
da = action;
707
}
708
709
@Override
710
public boolean equals(Object other) {
711
return (other instanceof DriverInfo)
712
&& this.driver == ((DriverInfo) other).driver;
713
}
714
715
@Override
716
public int hashCode() {
717
return driver.hashCode();
718
}
719
720
@Override
721
public String toString() {
722
return ("driver[className=" + driver + "]");
723
}
724
725
DriverAction action() {
726
return da;
727
}
728
}
729
730