Hi,
ich hab mal wieder eine Frage. Und zwar muß ich die JDBC-Treiber von h2 mittels eines eigenen ClassLoaders laden. Normalerweise wird das ja so gemacht:
Nun kann ich aber nicht den System-ClassLoader nehmen, da das Prog ein Installationtool ist, welches die h2-JAR in ein Verzeichnis installiert, in dem die spätere Anwendung (die ebenfalls installiert wird) läuft. Das Inst-Prog muß aber noch einige Tabellen in der DB erstellen und Einträge in diesen vornehmen. Somit ist zur Startzeit des Inst-Prog der spätere Installpath nicht bekannt, da dieser vom Benutzer gesetzt wird.
Nun habe ich mir gedacht, ich baue mir einen eigenen ClassLoader, der den Treiber lädt. Aber dies brachte neue Probleme mit sich. Erst wurden Klassen wie z.B. java.sql.Driver nicht mehr gefunden, die innerhalb des h2-jdbc-treibers referenziert werden. Dies konnte ich aber noch lösen, in dem ich bei nicht auffinden der Klasse innerhalb der h2-JAR den System-ClassLoader bemühe. Aber sobald ich den DriverManager bemühe eine Connection aufzubauen, sagt dieser das kein entsprechender Treiber gefunden werden konnte (no suitable driver...). Daraus schließe ich jetzt mal, das mein ClassLoader den Treiber nicht richtig initialisiert, so daß dieser sich beim DriverManager anmeldet.
Hier mal der Code meises ClassLoaders:
Außerdem fand ich noch etwas in den Sourcen des h2-Treibers, was die Initialisierung angeht, von dem ich aber weder wußte, daß es sowas gibt, noch wie sowas von der Funktion her abläuft.
Ich meine dieses einsame
am Anfang der Klasse.
Wann wird sowas ausgeführt und wodurch?
Danke in Vorraus
Lars
ich hab mal wieder eine Frage. Und zwar muß ich die JDBC-Treiber von h2 mittels eines eigenen ClassLoaders laden. Normalerweise wird das ja so gemacht:
Java:
import java.sql.*;
public class Test {
public static void main(String[] a)
throws Exception {
Class.forName("org.h2.Driver");
Connection conn = DriverManager.
getConnection("jdbc:h2:~/test", "sa", "");
// add application code here
conn.close();
}
}
Nun kann ich aber nicht den System-ClassLoader nehmen, da das Prog ein Installationtool ist, welches die h2-JAR in ein Verzeichnis installiert, in dem die spätere Anwendung (die ebenfalls installiert wird) läuft. Das Inst-Prog muß aber noch einige Tabellen in der DB erstellen und Einträge in diesen vornehmen. Somit ist zur Startzeit des Inst-Prog der spätere Installpath nicht bekannt, da dieser vom Benutzer gesetzt wird.
Nun habe ich mir gedacht, ich baue mir einen eigenen ClassLoader, der den Treiber lädt. Aber dies brachte neue Probleme mit sich. Erst wurden Klassen wie z.B. java.sql.Driver nicht mehr gefunden, die innerhalb des h2-jdbc-treibers referenziert werden. Dies konnte ich aber noch lösen, in dem ich bei nicht auffinden der Klasse innerhalb der h2-JAR den System-ClassLoader bemühe. Aber sobald ich den DriverManager bemühe eine Connection aufzubauen, sagt dieser das kein entsprechender Treiber gefunden werden konnte (no suitable driver...). Daraus schließe ich jetzt mal, das mein ClassLoader den Treiber nicht richtig initialisiert, so daß dieser sich beim DriverManager anmeldet.
Hier mal der Code meises ClassLoaders:
Java:
package WebSetup.Setup;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.jar.JarFile;
import java.util.zip.ZipEntry;
public class JarClassLoader extends ClassLoader
{
private JarFile jarFile;
public JarClassLoader(File jarFile) throws IOException
{
this.jarFile = new JarFile(jarFile);
}
protected Class<?> findClass(String className)
{
Class<?> ret = null;
try
{
String classString = className.replace(".", "/") + ".class";
System.out.println("Try to find Class: " + classString);
ZipEntry zipEntry = this.jarFile.getEntry(classString);
if(zipEntry != null)
{
System.out.println("Class found...");
InputStream in = this.jarFile.getInputStream(zipEntry);
int b;
ArrayList<Byte> array = new ArrayList<Byte>();
while((b = in.read()) != -1)
{
array.add(new Byte((byte)b));
}
byte[] buffer = new byte[array.size()];
for(int i = 0; i < buffer.length; i++)
{
buffer[i] = array.get(i).byteValue();
}
System.out.println("Class data length: " + buffer.length);
ret = this.defineClass(className, buffer, 0, buffer.length);
this.resolveClass(ret);
}
else
{
ret = Class.forName(className);
}
}
catch(IOException e)
{
e.printStackTrace();
}
catch (ClassNotFoundException e)
{
e.printStackTrace();
}
return(ret);
}
public Class<?> loadClass(String className)
{
Class<?> ret = this.findClass(className);
return(ret);
}
}
Außerdem fand ich noch etwas in den Sourcen des h2-Treibers, was die Initialisierung angeht, von dem ich aber weder wußte, daß es sowas gibt, noch wie sowas von der Funktion her abläuft.
Java:
/*
* Copyright 2004-2009 H2 Group. Multiple-Licensed under the H2 License,
* Version 1.0, and under the Eclipse Public License, Version 1.0
* ([url=http://h2database.com/html/license.html]License[/url]).
* Initial Developer: H2 Group
*/
package org.h2;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.DriverPropertyInfo;
import java.sql.SQLException;
import java.util.Properties;
import org.h2.engine.Constants;
import org.h2.jdbc.JdbcConnection;
import org.h2.message.Message;
import org.h2.message.TraceSystem;
/**
* The database driver. An application should not use this class directly. The
* only thing the application needs to do is load the driver. This can be done
* using Class.forName. To load the driver and open a database connection, use
* the following code:
*
* <pre>
* Class.forName("org.h2.Driver");
* Connection conn = DriverManager.getConnection(
* "jdbc:h2:˜/test", "sa", "sa");
* </pre>
*/
public class Driver implements java.sql.Driver {
private static final Driver INSTANCE = new Driver();
private static volatile boolean registered;
static {
load();
}
/**
* Open a database connection.
* This method should not be called by an application.
* Instead, the method DriverManager.getConnection should be used.
*
* @param url the database URL
* @param info the connection properties
* @return the new connection
*/
public Connection connect(String url, Properties info) throws SQLException {
try {
if (info == null) {
info = new Properties();
}
if (!acceptsURL(url)) {
return null;
}
return new JdbcConnection(url, info);
} catch (Exception e) {
throw Message.convert(e);
}
}
/**
* Check if the driver understands this URL.
* This method should not be called by an application.
*
* @param url the database URL
* @return if the driver understands the URL
*/
public boolean acceptsURL(String url) {
return url != null && url.startsWith(Constants.START_URL);
}
/**
* Get the major version number of the driver.
* This method should not be called by an application.
*
* @return the major version number
*/
public int getMajorVersion() {
return Constants.VERSION_MAJOR;
}
/**
* Get the minor version number of the driver.
* This method should not be called by an application.
*
* @return the minor version number
*/
public int getMinorVersion() {
return Constants.VERSION_MINOR;
}
/**
* Get the list of supported properties.
* This method should not be called by an application.
*
* @param url the database URL
* @param info the connection properties
* @return a zero length array
*/
public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) {
return new DriverPropertyInfo[0];
}
/**
* Check if this driver is compliant to the JDBC specification.
* This method should not be called by an application.
*
* @return true
*/
public boolean jdbcCompliant() {
return true;
}
/**
* INTERNAL
*/
public static synchronized Driver load() {
try {
if (!registered) {
registered = true;
DriverManager.registerDriver(INSTANCE);
}
} catch (SQLException e) {
TraceSystem.traceThrowable(e);
}
return INSTANCE;
}
/**
* INTERNAL
*/
public static synchronized void unload() {
try {
if (registered) {
registered = false;
DriverManager.deregisterDriver(INSTANCE);
}
} catch (SQLException e) {
TraceSystem.traceThrowable(e);
}
}
}
Java:
static { load(); }
Wann wird sowas ausgeführt und wodurch?
Danke in Vorraus
Lars
Zuletzt bearbeitet von einem Moderator: