1 /*
2 * This file is part of dependency-check-core.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 * Copyright (c) 2014 Jeremy Long. All Rights Reserved.
17 */
18 package org.owasp.dependencycheck.data.nvdcve;
19
20 import org.slf4j.Logger;
21 import org.slf4j.LoggerFactory;
22
23 import java.io.File;
24 import java.net.MalformedURLException;
25 import java.net.URL;
26 import java.net.URLClassLoader;
27 import java.security.AccessController;
28 import java.security.PrivilegedAction;
29 import java.sql.Driver;
30 import java.sql.DriverManager;
31 import java.sql.SQLException;
32 import java.util.ArrayList;
33 import java.util.List;
34
35 /**
36 * DriverLoader is a utility class that is used to load database drivers.
37 *
38 * @author Jeremy Long
39 */
40 public final class DriverLoader {
41
42 /**
43 * The logger.
44 */
45 private static final Logger LOGGER = LoggerFactory.getLogger(DriverLoader.class);
46
47 /**
48 * Private constructor for a utility class.
49 */
50 private DriverLoader() {
51 }
52
53 /**
54 * Loads the specified class using the system class loader and registers the driver with the driver manager.
55 *
56 * @param className the fully qualified name of the desired class
57 * @return the loaded Driver
58 * @throws DriverLoadException thrown if the driver cannot be loaded
59 */
60 public static Driver load(String className) throws DriverLoadException {
61 final ClassLoader loader = DriverLoader.class.getClassLoader(); //ClassLoader.getSystemClassLoader();
62 return load(className, loader);
63 }
64
65 /**
66 * Loads the specified class by registering the supplied paths to the class loader and then registers the driver with the
67 * driver manager. The pathToDriver argument is added to the class loader so that an external driver can be loaded. Note, the
68 * pathToDriver can contain a semi-colon separated list of paths so any dependencies can be added as needed. If a path in the
69 * pathToDriver argument is a directory all files in the directory are added to the class path.
70 *
71 * @param className the fully qualified name of the desired class
72 * @param pathToDriver the path to the JAR file containing the driver; note, this can be a semi-colon separated list of paths
73 * @return the loaded Driver
74 * @throws DriverLoadException thrown if the driver cannot be loaded
75 */
76 public static Driver load(String className, String pathToDriver) throws DriverLoadException {
77 final URLClassLoader parent = (URLClassLoader) ClassLoader.getSystemClassLoader();
78 final List<URL> urls = new ArrayList<URL>();
79 final String[] paths = pathToDriver.split(File.pathSeparator);
80 for (String path : paths) {
81 final File file = new File(path);
82 if (file.isDirectory()) {
83 final File[] files = file.listFiles();
84 if (files != null) {
85 for (File f : files) {
86 try {
87 urls.add(f.toURI().toURL());
88 } catch (MalformedURLException ex) {
89 LOGGER.debug("Unable to load database driver '{}'; invalid path provided '{}'",
90 className, f.getAbsoluteFile(), ex);
91 throw new DriverLoadException("Unable to load database driver. Invalid path provided", ex);
92 }
93 }
94 }
95 } else if (file.exists()) {
96 try {
97 urls.add(file.toURI().toURL());
98 } catch (MalformedURLException ex) {
99 LOGGER.debug("Unable to load database driver '{}'; invalid path provided '{}'",
100 className, file.getAbsoluteFile(), ex);
101 throw new DriverLoadException("Unable to load database driver. Invalid path provided", ex);
102 }
103 }
104 }
105 final URLClassLoader loader = AccessController.doPrivileged(new PrivilegedAction<URLClassLoader>() {
106 @Override
107 public URLClassLoader run() {
108 return new URLClassLoader(urls.toArray(new URL[urls.size()]), parent);
109 }
110 });
111
112 return load(className, loader);
113 }
114
115 /**
116 * Loads the specified class using the supplied class loader and registers the driver with the driver manager.
117 *
118 * @param className the fully qualified name of the desired class
119 * @param loader the class loader to use when loading the driver
120 * @return the loaded Driver
121 * @throws DriverLoadException thrown if the driver cannot be loaded
122 */
123 private static Driver load(String className, ClassLoader loader) throws DriverLoadException {
124 try {
125 final Class c = Class.forName(className, true, loader);
126 //final Class c = loader.loadClass(className);
127 final Driver driver = (Driver) c.newInstance();
128 final Driver shim = new DriverShim(driver);
129 //using the DriverShim to get around the fact that the DriverManager won't register a driver not in the base class path
130 DriverManager.registerDriver(shim);
131 return shim;
132 } catch (ClassNotFoundException ex) {
133 final String msg = String.format("Unable to load database driver '%s'", className);
134 LOGGER.debug(msg, ex);
135 throw new DriverLoadException(msg, ex);
136 } catch (InstantiationException ex) {
137 final String msg = String.format("Unable to load database driver '%s'", className);
138 LOGGER.debug(msg, ex);
139 throw new DriverLoadException(msg, ex);
140 } catch (IllegalAccessException ex) {
141 final String msg = String.format("Unable to load database driver '%s'", className);
142 LOGGER.debug(msg, ex);
143 throw new DriverLoadException(msg, ex);
144 } catch (SQLException ex) {
145 final String msg = String.format("Unable to load database driver '%s'", className);
146 LOGGER.debug(msg, ex);
147 throw new DriverLoadException(msg, ex);
148 }
149 }
150 }