Java classLoader dilemma with locked jars - java

I was playing around with classLoaders in Java and noticed a strange thing. If a classLoader loads a class from a jar, this jar is locked indefinitely even if you unreference your classLoader.
In the below example, the jar contains a class called HelloWorld. What I do is try to load the class contained in the jar via a classLoader which adds the jar dynamically. If you set skip to true and do not call Class.forName, you can delete the jar but if you do not skip and even if you unreference the classLoader (classLoader = null), the jar cannot be deleted until the JVM exits.
Why is that?
PS: I am using java 6 and the code is very verbose for testing purposes
package loader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
public class TestClassLoader {
private URLClassLoader classLoader;
public TestClassLoader() throws MalformedURLException, IOException {
System.out.println("Copying jar");
if (copyJar()) {
System.out.println("Copying SUCCESS");
performFirstCheck();
} else {
System.out.println("Copying FAILED");
}
}
public static void main(String[] args) throws IOException {
System.out.println("Test started");
TestClassLoader testClassLoader = new TestClassLoader();
System.out.println("Bye!");
}
public void performFirstCheck() throws IOException {
System.out.println("Checking class HelloWorld does not exist");
if (!checkClassFound(TestClassLoader.class.getClassLoader(), false)) {
System.out.println("Deleting jar");
deleteJar();
System.out.println("First Check SUCCESS");
performSecondCheck();
} else {
System.out.println("First Check FAILED");
}
}
private void performSecondCheck() throws IOException {
System.out.println("Copying jar");
if (copyJar()) {
System.out.println("Copying SUCCESS");
createClassLoaderAndCheck();
} else {
System.out.println("Copying FAILED");
}
}
private void createClassLoaderAndCheck() throws MalformedURLException {
System.out.println("Creating classLoader");
createClassLoader();
System.out.println("Checking class HelloWorld exist");
if (checkClassFound(classLoader, true)) {
System.out.println("Second Check SUCCESS");
classLoader = null;
System.out.println("Deleting jar");
if (deleteJar()) {
System.out.println("Deleting SUCCESS");
} else {
System.out.println("Deleting FAILED");
}
} else {
System.out.println("Second Check FAILED");
}
}
public void createClassLoader() throws MalformedURLException {
URL[] urls = new URL[1];
File classFile = new File("C:\\Users\\Adel\\Desktop\\classes.jar");
urls[0] = classFile.toURI().toURL();
classLoader = new URLClassLoader(urls);
}
public boolean checkClassFound(ClassLoader classLoader, boolean skip) {
if (skip) {
System.out.println("Skiping class loading");
return true;
} else {
try {
Class.forName("HelloWorld", true, classLoader);
return true;
} catch (ClassNotFoundException e) {
return false;
}
}
}
public URLClassLoader getClassLoader() {
return classLoader;
}
public boolean copyJar() throws IOException {
File sourceJar = new File("C:\\Users\\Adel\\Desktop\\Folder\\classes.jar");
File destJar = new File("C:\\Users\\Adel\\Desktop\\classes.jar");
if (destJar.exists()) {
return false;
} else {
FileInputStream finput = new FileInputStream(sourceJar);
FileOutputStream foutput = new FileOutputStream(destJar);
byte[] buf = new byte[1024];
int len;
while ((len = finput.read(buf)) > 0) {
foutput.write(buf, 0, len);
}
finput.close();
foutput.close();
return true;
}
}
public boolean deleteJar() {
File destJar = new File("C:\\Users\\Adel\\Desktop\\classes.jar");
return destJar.delete();
}
}

I have found an answer and a workaround.
Based on this article and this amazing related article, it is a bad habit to use Class.forName(className, true, classLoader) because it keeps the class cached in the memory indefinitely.
The solution was to use classLoader.loadClass(clasName) instead, then once finished, unreference the classLoader and call the garbage collector using:
classLoader = null;
System.gc();
Hope this helps others! :)
Background Info:
My project was a complexe one: we had a GWT server acting as a RMI client to another server. So to create instances, GWT needed to download the classes from the server and load them. Later, GWT would resend instance to the server to persist them in database using Hibernate. In order to support hot deployment, we opted for dynamically class loading where a user would upload a jar and notifies the server who would load the classes from it and present them as available to GWT server

In Java 7 URLClassLoader has a #close() method that fixes this.

Related

tTorrent Java: Tracking new torrent files in the directory

I'm using tTorrent Java implementation of the BitTorrent protocol. I'm at the point where I have to deal with a Tracker. The example code from the official repository loads torrent files from a given directory and announce them to the tracker. Then, starts it. I was hoping that the tracker would look for new torrent files in the directory automatically but, it doesn't seem to do so.
I pulled in a DirectoryWatcher and listened to create event; filtering torrent files. Passing the reference of Tracker object, I can announce the new file but, it doesn't seem to do anything.
How can I make the tracker aware of possible new torrent files in the directory while it's running?
DirectoryAwareTracker.java
import com.turn.ttorrent.tracker.TrackedTorrent;
import com.turn.ttorrent.tracker.Tracker;
import io.methvin.watcher.DirectoryChangeEvent;
import io.methvin.watcher.DirectoryChangeListener;
import io.methvin.watcher.DirectoryWatcher;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.file.Path;
public class DirectoryAwareTracker extends Tracker {
private DirectoryWatcher watcher;
private static final FilenameFilter torrentFilenameFilter = new FilenameFilter() {
#Override
public boolean accept(File dir, String name) {
return name.endsWith(".torrent");
}
};
DirectoryAwareTracker(InetSocketAddress address, Path directoryToWatch) throws IOException {
super(address);
File parent = new File(".");
for (File f : parent.listFiles(torrentFilenameFilter)) {
System.out.println("Loading torrent from " + f.getName());
try {
announce(TrackedTorrent.load(f));
} catch (Exception e) {
}
}
System.out.println("Starting tracker with {} announced torrents..." + getTrackedTorrents().size());
start();
watcher = DirectoryWatcher.create(directoryToWatch, new DirectoryChangeListener() {
#Override
public void onEvent(DirectoryChangeEvent directoryChangeEvent) throws IOException {
switch (directoryChangeEvent.eventType()) {
case CREATE:
File newFile = new File(directoryChangeEvent.path().toString());
System.out.println(directoryChangeEvent.path().toString());
System.out.println(newFile.isFile());
System.out.println(newFile.getName().endsWith(".torrent"));
if (newFile.isFile() && newFile.getName().endsWith(".torrent")) {
try {
announce(TrackedTorrent.load(newFile));
} catch (Exception e) {
}
}
break;
}
}
});
}
public void stopWatching() {
try {
watcher.close();
}
catch(Exception e) { }
}
public void watch() {
watcher.watch();
}
}

Dynamic Class Loading : Exception in thread "main" java.lang.ClassFormatError

I was trying to perform dynamic class loading from a jar file, unfortunately there was an error:
Exception in thread "main" java.lang.ClassFormatError: Incompatible magic value 1347093252 in class file com/life/Life
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClassCond(ClassLoader.java:631)
at java.lang.ClassLoader.defineClass(ClassLoader.java:615)
at java.lang.ClassLoader.defineClass(ClassLoader.java:465)
at gloria.MyClassLoader.loadClass(MyClassLoader.java:38)
at gloria.Gloria.main(Gloria.java:9)
Java Result: 1
Here's my code:
MainClass.java
public class MainClass {
public static void main(String[] args) {
try{
ClassLoader parentClassLoader = MyClassLoader.class.getClassLoader();
MyClassLoader classLoader = new MyClassLoader(parentClassLoader);
Class myObjectClass = classLoader.loadClass("com.life.Life");
//create new class loader so classes can be reloaded.
classLoader = new MyClassLoader(parentClassLoader);
myObjectClass = classLoader.loadClass("com.life.Life");
Life life = (Life) myObjectClass.newInstance();
System.out.println("Message: " + life.getMessage());
}catch(Exception e){
e.printStackTrace();
}
}
}
MyClassLoader.java
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
public class MyClassLoader extends ClassLoader{
public MyClassLoader(ClassLoader parent) {
super(parent);
}
#Override
public Class loadClass(String name) throws ClassNotFoundException {
if(!"com.life.Life".equals(name))
return super.loadClass(name);
try {
String url = "http://192.168.1.229:8081/downloads/Life.jar";
URL myUrl = new URL(url);
URLConnection connection = myUrl.openConnection();
InputStream input = connection.getInputStream();
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
int data = input.read();
while(data != -1){
buffer.write(data);
data = input.read();
}
input.close();
byte[] classData = buffer.toByteArray();
return defineClass("com.life.Life", classData, 0, classData.length);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
Life.java
public interface Life {
public String getMessage();
}
What Im doing right here is to instantiate an object that from a jar file and load it in runtime. What's wrong with my code? Any idea?
0xCAFEBABE is the usual first 4 bytes of a Java file.
Your value 1347093252 is 0x504B0304 in hex, which is the magic value for a ZIP file.
As jar is also a zip file. This means that your jar can be corrupt. Try re-building the jar.
You are trying to use a JAR/ZIP file as a CLASS file; a JAR file contains JAR files, but isn't one.
BTW, why won't something like new UrlClassLoader("jar:http://http://192.168.1.229:8081/downloads/!/") work? This will also transparently handle loading classes that Life needs and are located in that JAR.

Is it possible to run a loop when a new file is created in a folder?

So I have to make a program in java that automatically runs in the background and looks for a new .dat file and when it sees the new .dat file it then runs a .bat file to load data into a database. So far I have a program that watches for new file creation, modification, and deletion. I also have a script that runs the .bat file and loads the data into the database now i just need to connect the two but I am not sure how to go about this, If someone could point me in the right direction I would greatly appreciate it.
Below is the code I have so far.
import static java.nio.file.LinkOption.NOFOLLOW_LINKS;
import static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE;
import static java.nio.file.StandardWatchEventKinds.OVERFLOW;
import static java.nio.file.StandardWatchEventKinds.ENTRY_DELETE;
import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY;
import java.io.*;
import java.util.*;
import java.io.File;
import java.io.IOException;
import java.nio.file.FileSystem;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.WatchEvent;
import java.nio.file.WatchEvent.Kind;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;
public class Order_Processing {
public static void watchDirectoryPath(Path path)
{
try {
Boolean isFolder = (Boolean) Files.getAttribute(path,
"basic:isDirectory", NOFOLLOW_LINKS);
if (!isFolder)
{
throw new IllegalArgumentException("Path: " + path
+ " is not a folder");
}
}
catch (IOException ioe)
{
ioe.printStackTrace();
}
System.out.println("Watching path: "+ path);
FileSystem fs = path.getFileSystem();
try (WatchService service = fs.newWatchService())
{
path.register(service, ENTRY_CREATE, ENTRY_MODIFY, ENTRY_DELETE);
WatchKey key = null;
while (true)
{
key = service.take();
Kind<?> kind = null;
for (WatchEvent<?> watchEvent : key.pollEvents())
{
kind = watchEvent.kind();
if (OVERFLOW == kind)
{
continue;
}
else if (ENTRY_CREATE == kind)
{
Path newPath = ((WatchEvent<Path>) watchEvent)
.context();
System.out.println("New Path Created: " + newPath);
}
else if (ENTRY_MODIFY == kind)
{
Path newPath = ((WatchEvent<Path>) watchEvent)
.context();
System.out.println("New path modified: "+ newPath);
}
else if (ENTRY_DELETE == kind)
{
Path newPath = ((WatchEvent<Path>) watchEvent)
.context();
System.out.println("New path deleted: "+ newPath);
}
}
if (!key.reset())
{
break;
}
}
}
catch (IOException ioe)
{
ioe.printStackTrace();
}
catch (InterruptedException ie)
{
ie.printStackTrace();
}
}
public static void main(String[] args)
throws FileNotFoundException
{
File dir = new File("C:\\Paradigm");
watchDirectoryPath(dir.toPath());
//below is the script that runs the .bat file and it works if by itself
//with out all the other watch code.
try {
String[] command = {"cmd.exe", "/C", "Start", "C:\\Try.bat"};
Process p = Runtime.getRuntime().exec(command);
}
catch (IOException ex) {
}
}
}
This doesn't work because you have a while (true). This makes sense because you are listening and want the to happen continuously; however, the bat call will never be executed because watchDirectory(...) will never terminate. To solve this, pull the rest of the main out into its own function like so
public static void executeBat() {
try {
String[] command = {"cmd.exe", "/C", "Start", "C:\\Try.bat"};
Process p = Runtime.getRuntime().exec(command);
}
catch (IOException ex) {
// You should do something with this.
// DON'T JUST IGNORE FAILURES
}
so that upon file creation, you can call that bat script
...
else if (ENTRY_CREATE == kind)
{
Path newPath = ((WatchEvent<Path>) watchEvent).context();
executeBat();
}
...

Java ProtectionDomain seems not to work

I have some problem with granting permissions in Java. I would like to implement app (e.g. myapp), which runs normaly, with all permissions, but when it loads code (from .jar or .class)(e.g. foo.jar and bar.class) from specific location (e.g http://example.net/libs), this code should run with specific permissions.
I thought the only one which I have to do is grant all permissions to myapp (via policy file) and then just simply create ProtectionDomain (on location http://example.net/libs/* and with specified permissions) and run libs via AccessController.
But when I grant permissions (only)(via policy file, see bottom) to myapp, they are granted to all code (including libraries foo.jar and bar.class) - which musn't.
So I stopped exploring how to grant permissions to libs and I have to solve this problem first.
(see EDIT at bottom)
Structure
I have myapp which contains main class (myapp.Main) and it's located in /home/java/:
/home/java/src/myapp/Main.java
/home/java/bin/myapp/Main.class
and libraries
http://example.net/libs/foo.jar
http://example.net/libs/bar.class
Implementation
I wrote myapp.Main.java like this:
package myapp;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
public class Main {
public static void main(String[] args) throws IOException {
//myapp should access
System.out.println("myapp.Main: " + System.getProperty("user.home"));
//find Foo class
Class<?> fooClass = findFooClass();
//invoke some its method
// this should fail
try {
System.out.println(fooClass.newInstance().toString());
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace();
return;
}
}
private static Class<?> findFooClass() throws IOException {
URL fooClassURL;
try {
fooClassURL = new URL("http://example.net/libs/foo.jar");
} catch (MalformedURLException e) {
e.printStackTrace();
return null;
}
URLClassLoader ucl = new URLClassLoader(new URL[]{fooClassURL});
Class<?> fooClass;
try {
fooClass = ucl.loadClass("foopackage.Foo");
} catch (ClassNotFoundException e) {
e.printStackTrace();
return null;
} finally {
ucl.close();
}
return fooClass;
}
}
and class foopackage.Foo like
package foopackage;
public class Foo {
public Foo() {
}
private void tryProperty() {
System.out.println("foopackage.Foo: " + System.getProperty("user.home"));
}
#Override
public String toString() {
tryProperty();
return super.toString();
}
}
Running
When I run myapp via this command
java -Djava.security.manager -Djava.security.policy=/home/java/myapp.policy myapp.Main
where file myapp.policy looks like
grant codeBase "file:/home/java/*" {
permission java.security.AllPermission;
};
it outputs twice home directory and then original value of Foo.toString.
(see EDIT at bottom)
I am asking - what am I doing wrong? What did I disunderstand?
EDIT:
The reason why permissions were granted to whole code was simply - while I was exploring security, I've got litle bit tangled and I granted all permissions via file ~/java.policy.
So, now I can grant permissions via policy file as expected. But still not works granting permissions via AccessController. myapp.Main has permissions granted via policy file and works fine (so it prints once home directory), but when it (via AccessController.doPrivileged) calls FooClassToStringAction's action, the foopackage.Foo has no permission to access property (which I IMHO grant by ProtectionDomain). Updated myapp.Main class' code:
package myapp;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.AllPermission;
import java.security.CodeSource;
import java.security.PermissionCollection;
import java.security.Permissions;
import java.security.PrivilegedAction;
import java.security.ProtectionDomain;
import java.security.cert.Certificate;
public class Main {
public static class FooClassToStringAction implements PrivilegedAction<Void> {
private Class<?> fooClass;
public FooClassToStringAction(Class<?> fooClass) {
this.fooClass = fooClass;
}
#Override
public Void run() {
try {
System.out.println(fooClass.newInstance().toString());
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace();
return null;
}
return null;
}
}
public static void main(String[] args) throws IOException {
//myapp should access
System.out.println("myapp.Main: " + System.getProperty("user.home"));
//find Foo class
Class<?> fooClass = findFooClass();
ProtectionDomain domain = createProtectionDomain();
PrivilegedAction<Void> action = new FooClassToStringAction(fooClass);
AccessControlContext context = new AccessControlContext(new ProtectionDomain[] {domain});
AccessController.doPrivileged(action, context);
}
private static Class<?> findFooClass() throws IOException {
URL fooClassURL;
try {
fooClassURL = new URL("http://example.net/libs/*");
} catch (MalformedURLException e) {
e.printStackTrace();
return null;
}
URLClassLoader ucl = URLClassLoader.newInstance(new URL[] {fooClassURL});//new URLClassLoader(new URL[]{fooClassURL});
Class<?> fooClass;
try {
fooClass = ucl.loadClass("foopackage.Foo");
} catch (ClassNotFoundException e) {
e.printStackTrace();
return null;
} finally {
ucl.close();
}
return fooClass;
}
private static ProtectionDomain createProtectionDomain() {
URL url;
try {
url = new URL("http://example.net/libs/*");
} catch (MalformedURLException e) {
e.printStackTrace();
return null;
}
//I tried url=null or url=file:/- but no change
CodeSource codesource = new CodeSource(url, (Certificate[]) null);
PermissionCollection permissions = new Permissions();
//add various permissions to libraries here
permissions.add(new AllPermission());
return new ProtectionDomain(codesource, permissions);
}
}

URLClassLoader does not read external JAR library of a plugin

I have implemented a simple plugin based application with Java. Main plugin class is derived from and abstract class called "Plugin". The application reads that class from JAR file and runs the plugin by creating an instance of the class. Standard procedure I guess :)
Everything forks fine until now. But the problem occurs when I include a library to my plugin, like MySQL Connector. The exception NoClassDefFoundError and ClassNotFoundException are thrown after execution. I am overcoming the problem by adding MySQL connector library to the main application but what is the point then? :)
I am not a Java expert so I am not sure of any alternative solutions like defining a classpath for libraries etc.
Here is my plugin loader:
http://pastebin.com/90rQ9NfJ
And here is my plugin base class:
http://pastebin.com/Juuicwkm
I am executing from a GUI:
private void jButtonAddActionPerformed(java.awt.event.ActionEvent evt) {
JFileChooser fileChooser = new JFileChooser();
fileChooser.setFileFilter(new FileNameExtensionFilter("JTask Plugin (*.JAR)", "JAR"));
if (fileChooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION)
{
File pluginFile = fileChooser.getSelectedFile();
PluginLoader pluginLoader = new PluginLoader();
Plugin plugin = pluginLoader.loadPlugin(pluginFile);
if (plugin != null)
jPanelPlugins.add(new PluginControl(jPanelPlugins, plugin));
}
}
You should really include your source code as well.
How are you executing the class i.e. via command line or from a GUI? If from the command line, then the MySQLConnector libraries, along with any other dependent library must be included in the classpath (java -classpath). The top answer to this question should help you- Java: how to import a jar file from command line
if the case, your class is a Mysql Driver you have to exclude (at the time the class is calling) classes that are not available. In the Folder of your .jar file there is one with the name "integration" it contains "jboss" and "c3p0" which are not present at this time.
while (en.hasMoreElements()) {
JarEntry entry = new JarEntry(en.nextElement());
String name = entry.getName();
if (name.contains("/integration/")) {
continue;
} else {
if (!entry.isDirectory() && name.toLowerCase().endsWith(".class"))
{
classList.add(name.replace(".class", ""));
}
}
}
This should load a mysql.xxx.jar file.
Try This
dynamicload.java
package dynamicloading;
import java.io.File;
import java.net.URL;
import java.net.URLClassLoader;
import java.sql.Connection;
import java.sql.Statement;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.DriverPropertyInfo;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Enumeration;
import java.util.Properties;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
/**
*
* #author Administrator
*/
class com_mysql_jdbc_Driver implements Driver {
private Driver driver;
com_mysql_jdbc_Driver(Driver cmjd) {
this.driver = cmjd;
}
#Override
public boolean acceptsURL(String aurlS) throws SQLException {
return this.driver.acceptsURL(aurlS);
}
#Override
public Connection connect(String aurlS, Properties pP) throws SQLException {
return this.driver.connect(aurlS, pP);
}
#Override
public int getMajorVersion() {
return this.driver.getMajorVersion();
}
#Override
public int getMinorVersion() {
return this.driver.getMinorVersion();
}
#Override
public DriverPropertyInfo[] getPropertyInfo(String aurlS, Properties pP) throws SQLException {
return this.driver.getPropertyInfo(aurlS, pP);
}
#Override
public boolean jdbcCompliant() {
return this.driver.jdbcCompliant();
}
}
public class DynMain {
/**
* #param args the command line arguments
*/
public static void main(String[] args) throws Exception {
/* please set to your path*/
File file = new File("U:/mozsamples/mysql-connector-java-5.1.19-bin.jar");
Driver cmjdD;
String aktCS;
String urlS = "jdbc:mysql://localhost/db";
String userS = "must-be-set";
String passS = "must-be-set";
Connection con;
Statement stmt;
URLClassLoader clazzLoader = URLClassLoader.newInstance(new URL[]{file.toURI().toURL()});
JarFile jarFile = new JarFile(file);
Enumeration<JarEntry> entries = jarFile.entries();
while (entries.hasMoreElements()) {
JarEntry element = entries.nextElement();
if (element.getName().endsWith(".class")) {
String name = element.getName();
if (name.contains("/integration/")) {
System.out.println( "ignored: " + name );
continue;
} else
{
try {
aktCS = element.getName().replaceAll(".class", "").replaceAll("/", ".");
clazzLoader.loadClass(aktCS);
if (name.contains("com/mysql/jdbc/Driver")) {
cmjdD = (Driver)Class.forName(aktCS, true, clazzLoader).newInstance();
try {
DriverManager.registerDriver(new com_mysql_jdbc_Driver(cmjdD));
System.out.println( "register Class: " + aktCS );
} catch (SQLException e) {
e.printStackTrace();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
try {
con = DriverManager.getConnection(urlS,userS,passS);
stmt = con.createStatement();
/*ResultSet rs = stmt.executeQuery("select * from idcart where ID=255"); */
stmt.close();
} catch (SQLException esql) {
esql.printStackTrace();
}
int j=0 ;
System.out.println("loaded Driver----------------------------------");
for( Enumeration en = DriverManager.getDrivers() ; en.hasMoreElements() ; j++)
System.out.println( en.nextElement().getClass().getName() );
if (j==0) { System.out.println("Driverlist empty"); }
System.out.println("-----------------------------------------------");
}
}
Output:
register Class: com.mysql.jdbc.Driver
ignored: com/mysql/jdbc/integration/c3p0/MysqlConnectionTester.class
ignored: com/mysql/jdbc/integration/jboss/ExtendedMysqlExceptionSorter.class
ignored: com/mysql/jdbc/integration/jboss/MysqlValidConnectionChecker.class
loaded Driver----------------------------------
sun.jdbc.odbc.JdbcOdbcDriver
dynamicloading.com_mysql_jdbc_Driver
-----------------------------------------------
OK ???

Categories

Resources