EMMA Coverage Report (generated Sun Mar 01 22:06:14 CET 2015)
[all classes][org.h2.util]

COVERAGE SUMMARY FOR SOURCE FILE [JdbcUtils.java]

nameclass, %method, %block, %line, %
JdbcUtils.java100% (2/2)94%  (16/17)74%  (516/695)68%  (94.3/139)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class JdbcUtils$1100% (1/1)100% (2/2)74%  (14/19)50%  (2/4)
resolveClass (ObjectStreamClass): Class 100% (1/1)58%  (7/12)33%  (1/3)
JdbcUtils$1 (InputStream, ClassLoader): void 100% (1/1)100% (7/7)100% (1/1)
     
class JdbcUtils100% (1/1)93%  (14/15)74%  (502/676)69%  (93.3/136)
JdbcUtils (): void 0%   (0/1)0%   (0/3)0%   (0/2)
getConnection (String, String, Properties): Connection 100% (1/1)33%  (21/64)35%  (6/17)
loadUserClass (String): Class 100% (1/1)48%  (86/181)51%  (20.3/40)
getUserClassFactories (): ArrayList 100% (1/1)50%  (4/8)67%  (2/3)
serialize (Object, DataHandler): byte [] 100% (1/1)74%  (34/46)85%  (11/13)
closeSilently (ResultSet): void 100% (1/1)86%  (6/7)80%  (4/5)
closeSilently (Statement): void 100% (1/1)86%  (6/7)80%  (4/5)
deserialize (byte [], DataHandler): Object 100% (1/1)91%  (51/56)94%  (15/16)
<static initializer> 100% (1/1)95%  (212/222)56%  (5/9)
addClassFactory (Utils$ClassFactory): void 100% (1/1)100% (5/5)100% (2/2)
closeSilently (Connection): void 100% (1/1)100% (7/7)100% (5/5)
getConnection (String, String, String, String): Connection 100% (1/1)100% (23/23)100% (6/6)
getDriver (String): String 100% (1/1)100% (33/33)100% (7/7)
load (String): void 100% (1/1)100% (9/9)100% (4/4)
removeClassFactory (Utils$ClassFactory): void 100% (1/1)100% (5/5)100% (2/2)

1/*
2 * Copyright 2004-2014 H2 Group. Multiple-Licensed under the MPL 2.0,
3 * and the EPL 1.0 (http://h2database.com/html/license.html).
4 * Initial Developer: H2 Group
5 */
6package org.h2.util;
7 
8import java.io.ByteArrayInputStream;
9import java.io.ByteArrayOutputStream;
10import java.io.IOException;
11import java.io.ObjectInputStream;
12import java.io.ObjectOutputStream;
13import java.io.ObjectStreamClass;
14import java.sql.Connection;
15import java.sql.DriverManager;
16import java.sql.ResultSet;
17import java.sql.SQLException;
18import java.sql.Statement;
19import java.util.ArrayList;
20import java.util.HashSet;
21import java.util.Properties;
22 
23import javax.naming.Context;
24import javax.sql.DataSource;
25 
26import org.h2.api.ErrorCode;
27import org.h2.api.JavaObjectSerializer;
28import org.h2.engine.SysProperties;
29import org.h2.message.DbException;
30import org.h2.store.DataHandler;
31import org.h2.util.Utils.ClassFactory;
32 
33/**
34 * This is a utility class with JDBC helper functions.
35 */
36public class JdbcUtils {
37 
38    /**
39     * The serializer to use.
40     */
41    public static JavaObjectSerializer serializer;
42 
43    private static final String[] DRIVERS = {
44        "h2:", "org.h2.Driver",
45        "Cache:", "com.intersys.jdbc.CacheDriver",
46        "daffodilDB://", "in.co.daffodil.db.rmi.RmiDaffodilDBDriver",
47        "daffodil", "in.co.daffodil.db.jdbc.DaffodilDBDriver",
48        "db2:", "COM.ibm.db2.jdbc.net.DB2Driver",
49        "derby:net:", "org.apache.derby.jdbc.ClientDriver",
50        "derby://", "org.apache.derby.jdbc.ClientDriver",
51        "derby:", "org.apache.derby.jdbc.EmbeddedDriver",
52        "FrontBase:", "com.frontbase.jdbc.FBJDriver",
53        "firebirdsql:", "org.firebirdsql.jdbc.FBDriver",
54        "hsqldb:", "org.hsqldb.jdbcDriver",
55        "informix-sqli:", "com.informix.jdbc.IfxDriver",
56        "jtds:", "net.sourceforge.jtds.jdbc.Driver",
57        "microsoft:", "com.microsoft.jdbc.sqlserver.SQLServerDriver",
58        "mimer:", "com.mimer.jdbc.Driver",
59        "mysql:", "com.mysql.jdbc.Driver",
60        "odbc:", "sun.jdbc.odbc.JdbcOdbcDriver",
61        "oracle:", "oracle.jdbc.driver.OracleDriver",
62        "pervasive:", "com.pervasive.jdbc.v2.Driver",
63        "pointbase:micro:", "com.pointbase.me.jdbc.jdbcDriver",
64        "pointbase:", "com.pointbase.jdbc.jdbcUniversalDriver",
65        "postgresql:", "org.postgresql.Driver",
66        "sybase:", "com.sybase.jdbc3.jdbc.SybDriver",
67        "sqlserver:", "com.microsoft.sqlserver.jdbc.SQLServerDriver",
68        "teradata:", "com.ncr.teradata.TeraDriver",
69    };
70 
71    private static boolean allowAllClasses;
72    private static HashSet<String> allowedClassNames;
73 
74    /**
75     *  In order to manage more than one class loader
76     */
77    private static ArrayList<ClassFactory> userClassFactories =
78            new ArrayList<ClassFactory>();
79 
80    private static String[] allowedClassNamePrefixes;
81 
82    private JdbcUtils() {
83        // utility class
84    }
85 
86    /**
87     * Add a class factory in order to manage more than one class loader.
88     *
89     * @param classFactory An object that implements ClassFactory
90     */
91    public static void addClassFactory(ClassFactory classFactory) {
92        getUserClassFactories().add(classFactory);
93    }
94 
95    /**
96     * Remove a class factory
97     *
98     * @param classFactory Already inserted class factory instance
99     */
100    public static void removeClassFactory(ClassFactory classFactory) {
101        getUserClassFactories().remove(classFactory);
102    }
103 
104    private static ArrayList<ClassFactory> getUserClassFactories() {
105        if (userClassFactories == null) {
106            // initially, it is empty
107            // but Apache Tomcat may clear the fields as well
108            userClassFactories = new ArrayList<ClassFactory>();
109        }
110        return userClassFactories;
111    }
112 
113    static {
114        String clazz = SysProperties.JAVA_OBJECT_SERIALIZER;
115        if (clazz != null) {
116            try {
117                serializer = (JavaObjectSerializer) loadUserClass(clazz).newInstance();
118            } catch (Exception e) {
119                throw DbException.convert(e);
120            }
121        }
122    }
123 
124    /**
125     * Load a class, but check if it is allowed to load this class first. To
126     * perform access rights checking, the system property h2.allowedClasses
127     * needs to be set to a list of class file name prefixes.
128     *
129     * @param className the name of the class
130     * @return the class object
131     */
132    public static Class<?> loadUserClass(String className) {
133        if (allowedClassNames == null) {
134            // initialize the static fields
135            String s = SysProperties.ALLOWED_CLASSES;
136            ArrayList<String> prefixes = New.arrayList();
137            boolean allowAll = false;
138            HashSet<String> classNames = New.hashSet();
139            for (String p : StringUtils.arraySplit(s, ',', true)) {
140                if (p.equals("*")) {
141                    allowAll = true;
142                } else if (p.endsWith("*")) {
143                    prefixes.add(p.substring(0, p.length() - 1));
144                } else {
145                    classNames.add(p);
146                }
147            }
148            allowedClassNamePrefixes = new String[prefixes.size()];
149            prefixes.toArray(allowedClassNamePrefixes);
150            allowAllClasses = allowAll;
151            allowedClassNames = classNames;
152        }
153        if (!allowAllClasses && !allowedClassNames.contains(className)) {
154            boolean allowed = false;
155            for (String s : allowedClassNamePrefixes) {
156                if (className.startsWith(s)) {
157                    allowed = true;
158                }
159            }
160            if (!allowed) {
161                throw DbException.get(
162                        ErrorCode.ACCESS_DENIED_TO_CLASS_1, className);
163            }
164        }
165        // Use provided class factory first.
166        for (ClassFactory classFactory : getUserClassFactories()) {
167            if (classFactory.match(className)) {
168                try {
169                    Class<?> userClass = classFactory.loadClass(className);
170                    if (!(userClass == null)) {
171                        return userClass;
172                    }
173                } catch (Exception e) {
174                    throw DbException.get(
175                            ErrorCode.CLASS_NOT_FOUND_1, e, className);
176                }
177            }
178        }
179        // Use local ClassLoader
180        try {
181            return Class.forName(className);
182        } catch (ClassNotFoundException e) {
183            try {
184                return Class.forName(
185                        className, true,
186                        Thread.currentThread().getContextClassLoader());
187            } catch (Exception e2) {
188                throw DbException.get(
189                        ErrorCode.CLASS_NOT_FOUND_1, e, className);
190            }
191        } catch (NoClassDefFoundError e) {
192            throw DbException.get(
193                    ErrorCode.CLASS_NOT_FOUND_1, e, className);
194        } catch (Error e) {
195            // UnsupportedClassVersionError
196            throw DbException.get(
197                    ErrorCode.GENERAL_ERROR_1, e, className);
198        }
199    }
200 
201    /**
202     * Close a statement without throwing an exception.
203     *
204     * @param stat the statement or null
205     */
206    public static void closeSilently(Statement stat) {
207        if (stat != null) {
208            try {
209                stat.close();
210            } catch (SQLException e) {
211                // ignore
212            }
213        }
214    }
215 
216    /**
217     * Close a connection without throwing an exception.
218     *
219     * @param conn the connection or null
220     */
221    public static void closeSilently(Connection conn) {
222        if (conn != null) {
223            try {
224                conn.close();
225            } catch (SQLException e) {
226                // ignore
227            }
228        }
229    }
230 
231    /**
232     * Close a result set without throwing an exception.
233     *
234     * @param rs the result set or null
235     */
236    public static void closeSilently(ResultSet rs) {
237        if (rs != null) {
238            try {
239                rs.close();
240            } catch (SQLException e) {
241                // ignore
242            }
243        }
244    }
245 
246    /**
247     * Open a new database connection with the given settings.
248     *
249     * @param driver the driver class name
250     * @param url the database URL
251     * @param user the user name
252     * @param password the password
253     * @return the database connection
254     */
255    public static Connection getConnection(String driver, String url,
256            String user, String password) throws SQLException {
257        Properties prop = new Properties();
258        if (user != null) {
259            prop.setProperty("user", user);
260        }
261        if (password != null) {
262            prop.setProperty("password", password);
263        }
264        return getConnection(driver, url, prop);
265    }
266 
267    /**
268     * Open a new database connection with the given settings.
269     *
270     * @param driver the driver class name
271     * @param url the database URL
272     * @param prop the properties containing at least the user name and password
273     * @return the database connection
274     */
275    public static Connection getConnection(String driver, String url,
276            Properties prop) throws SQLException {
277        if (StringUtils.isNullOrEmpty(driver)) {
278            JdbcUtils.load(url);
279        } else {
280            Class<?> d = loadUserClass(driver);
281            if (java.sql.Driver.class.isAssignableFrom(d)) {
282                return DriverManager.getConnection(url, prop);
283            } else if (javax.naming.Context.class.isAssignableFrom(d)) {
284                // JNDI context
285                try {
286                    Context context = (Context) d.newInstance();
287                    DataSource ds = (DataSource) context.lookup(url);
288                    String user = prop.getProperty("user");
289                    String password = prop.getProperty("password");
290                    if (StringUtils.isNullOrEmpty(user) && StringUtils.isNullOrEmpty(password)) {
291                        return ds.getConnection();
292                    }
293                    return ds.getConnection(user, password);
294                } catch (Exception e) {
295                    throw DbException.toSQLException(e);
296                }
297            } else {
298                // don't know, but maybe it loaded a JDBC Driver
299                return DriverManager.getConnection(url, prop);
300            }
301        }
302        return DriverManager.getConnection(url, prop);
303    }
304 
305    /**
306     * Get the driver class name for the given URL, or null if the URL is
307     * unknown.
308     *
309     * @param url the database URL
310     * @return the driver class name
311     */
312    public static String getDriver(String url) {
313        if (url.startsWith("jdbc:")) {
314            url = url.substring("jdbc:".length());
315            for (int i = 0; i < DRIVERS.length; i += 2) {
316                String prefix = DRIVERS[i];
317                if (url.startsWith(prefix)) {
318                    return DRIVERS[i + 1];
319                }
320            }
321        }
322        return null;
323    }
324 
325    /**
326     * Load the driver class for the given URL, if the database URL is known.
327     *
328     * @param url the database URL
329     */
330    public static void load(String url) {
331        String driver = getDriver(url);
332        if (driver != null) {
333            loadUserClass(driver);
334        }
335    }
336 
337    /**
338     * Serialize the object to a byte array, using the serializer specified by
339     * the connection info if set, or the default serializer.
340     *
341     * @param obj the object to serialize
342     * @param dataHandler provides the object serializer (may be null)
343     * @return the byte array
344     */
345    public static byte[] serialize(Object obj, DataHandler dataHandler) {
346        try {
347            JavaObjectSerializer handlerSerializer = null;
348            if (dataHandler != null) {
349                handlerSerializer = dataHandler.getJavaObjectSerializer();
350            }
351            if (handlerSerializer != null) {
352                return handlerSerializer.serialize(obj);
353            }
354            if (serializer != null) {
355                return serializer.serialize(obj);
356            }
357            ByteArrayOutputStream out = new ByteArrayOutputStream();
358            ObjectOutputStream os = new ObjectOutputStream(out);
359            os.writeObject(obj);
360            return out.toByteArray();
361        } catch (Throwable e) {
362            throw DbException.get(ErrorCode.SERIALIZATION_FAILED_1, e, e.toString());
363        }
364    }
365 
366    /**
367     * De-serialize the byte array to an object, eventually using the serializer
368     * specified by the connection info.
369     *
370     * @param data the byte array
371     * @param dataHandler provides the object serializer (may be null)
372     * @return the object
373     * @throws DbException if serialization fails
374     */
375    public static Object deserialize(byte[] data, DataHandler dataHandler) {
376        try {
377            JavaObjectSerializer dbJavaObjectSerializer = null;
378            if (dataHandler != null) {
379                dbJavaObjectSerializer = dataHandler.getJavaObjectSerializer();
380            }
381            if (dbJavaObjectSerializer != null) {
382                return dbJavaObjectSerializer.deserialize(data);
383            }
384            if (serializer != null) {
385                return serializer.deserialize(data);
386            }
387            ByteArrayInputStream in = new ByteArrayInputStream(data);
388            ObjectInputStream is;
389            if (SysProperties.USE_THREAD_CONTEXT_CLASS_LOADER) {
390                final ClassLoader loader = Thread.currentThread().getContextClassLoader();
391                is = new ObjectInputStream(in) {
392                    @Override
393                    protected Class<?> resolveClass(ObjectStreamClass desc)
394                            throws IOException, ClassNotFoundException {
395                        try {
396                            return Class.forName(desc.getName(), true, loader);
397                        } catch (ClassNotFoundException e) {
398                            return super.resolveClass(desc);
399                        }
400                    }
401                };
402            } else {
403                is = new ObjectInputStream(in);
404            }
405            return is.readObject();
406        } catch (Throwable e) {
407            throw DbException.get(ErrorCode.DESERIALIZATION_FAILED_1, e, e.toString());
408        }
409    }
410 
411}

[all classes][org.h2.util]
EMMA 2.0.5312 (C) Vladimir Roubtsov