Loading and connecting to mysql jdbc driver runtime - java

I am currently working in a requirement where I need to load the mysql driver runtime and connect to the database using java.
I am using URLClassLoader to load the jar file
File f = new File("D:/Pallavi/workspace/WarInstallation/mysql-connector-java-5.0.4-bin.jar"); //Jar path
URLClassLoader urlCl = new URLClassLoader(new URL[] { f.toURL()},System.class.getClassLoader());
Class sqldriver = urlCl.loadClass("com.mysql.jdbc.Driver"); // Runtime loading
Driver ds = (Driver) sqldriver.newInstance(); //Compilation failing as "sqldriver" class of type Driver is not found
//I am using now java.sql.Driver to remove the compilation error
sqldriver = Class.forName("com.mysql.jdbc.Driver", true, sqldriver.getClassLoader()).newInstance(); //Runtime fail.. "Driver" Class not Found Exception.
Although the class loads fine I can't establish a Database connection (No suitable driver found for ...) no matter which driver I try.
Please suggest a way to load the jdbc "com.mysql.jdbc.Driver" class runtime.
Let me know, if you need any further information, as this is urgent.
Thanks in advance.

I have three questions before I answer to your issues:
Statement 1:
ya, I have set the classpath of mysql jar in the environment variables, do we need to set it through system properties?
Q1: Why are to relying on custom class loader, when a class is readily available to the System class loader from the class path?
You don't need explicit class path to mysql***.jar to use custom class loader.
Statement 2:
Class sqldriver = urlCl.loadClass("com.mysql.jdbc.Driver"); // Runtime loading
//Compilation failing as "sqldriver" class of type Driver is not found
Driver ds = (Driver) sqldriver.newInstance();
Q2: Claiming Compilation failing ... is very conflicting. Is your compiler looking for such class to generate your class!?
I am sure it is not. May be the error is at run time with a java.lang.ClassNotFoundException: com.mysql.jdbc.Driver. And I also suspect the comment should go with your Statement 3 below.
If it is a CNFE, your file path to mysql***.jar is wrong. Fix it first.
Statement 3:
//I am using now java.sql.Driver to remove the compilation error
//Runtime fail.. "Driver" Class not Found Exception.
sqldriver = Class.forName("com.mysql.jdbc.Driver", true, sqldriver.getClassLoader()).newInstance();
Q3: Claiming ... "Driver" Class not Found Exception is suspectful. Because, this statement won't get compiled. Then how can it be a Runtime fail. ..!?
I also suspect the comment should go with your Statement 2 above.
And here, you need to call newInstance() and then cast to java.sql.Driver before assigning to sqlDriver variable. Because Class.forName( ... only returns a Class object associated with the class or interface with the given string name.
If issue at Statement 2 above is fixed, you can apply this fix to test further.
Let me hope you got these statements clarified.
I have a working sample code below, with a tested output shown for you.
import java.io.File; // and others as required
public class MySQLDriveClassLoader {
public static void main( String [] args ) throws Exception {
//File f = new File( "/home/ravinder/soft-dump/mysql-connector-java-5.1.18-bin.jar" );
File f = new File( "E:\\Soft_Dump\\mysql-connector-java-5.0.4\\mysql-connector-java-5.0.4-bin.jar" );
URLClassLoader urlCl = new URLClassLoader( new URL[] { f.toURI().toURL() }, System.class.getClassLoader() );
Class mySqlDriver = urlCl.loadClass( "com.mysql.jdbc.Driver" );
//*** Start: DEBUG *************************
//mySqlDriver.con // On pressing CTRL+SPACEBAR, after .con, IDE shows "No default proposals"
// meaning it still is not an instance of Driver, and hence can't call a method from Driver class.
//Incompatible conditional operand types Class and Driver
//System.out.println( mySqlDriver instanceof java.sql.Driver ) );
System.out.println( "mySqlDriver: " + mySqlDriver );
System.out.println( "Is this interface? = " + mySqlDriver.isInterface() );
Class interfaces[] = mySqlDriver.getInterfaces();
int i = 1;
for( Class _interface : interfaces ) {
System.out.println( "Implemented Interface Name " + ( i++ ) + " = " + _interface.getName() );
} // for(...)
Constructor constructors[] = mySqlDriver.getConstructors();
for( Constructor constructor : constructors ) {
System.out.println( "Constructor Name = " + constructor.getName() );
System.out.println( "Is Constructor Accessible? = " + constructor.isAccessible() );
} // for(...)
//*** End : DEBUG *************************
Driver sqlDriverInstance = ( Driver ) mySqlDriver.newInstance();
System.out.println( "sqlDriverInstance: " + sqlDriverInstance );
Connection con = null;
try {
/******************************************************************
// You may fail to register the above driver
// hence don't depend on DriverManager to get Connected
//DriverManager.registerDriver( sqlDriverInstance );
//Driver driver = DriverManager.getDriver( "com.mysql.jdbc.Driver" ); // ( "jdbc:mysql" );
Enumeration<Driver> enumDrivers = DriverManager.getDrivers();
while ( enumDrivers.hasMoreElements() ) {
Driver driver = enumDrivers.nextElement();
System.out.println( "driver: " + driver );
} // while drivers
//******************************************************************/
String dbUrl = "jdbc:mysql://:3306/test";
Properties userDbCredentials = new Properties();
userDbCredentials.put( "user", "root" );
userDbCredentials.put( "password", "password" );
// No suitable driver found for ...
//con = DriverManager.getConnection( dbUrl, "root", "password" );
// safely use driver to connect
con = sqlDriverInstance.connect( dbUrl, userDbCredentials );
System.out.println( "con: " + con );
Statement stmt = con.createStatement();
String sql = "select now()";
ResultSet rs = stmt.executeQuery( sql );
if ( rs.next() ) {
System.out.println( rs.getString( 1 ) );
} // if rs
} catch( Exception e ) {
e.printStackTrace(); // only for quick debug
} finally {
try { if ( con != null ) con.close(); } catch ( Exception ignoreThis ) {}
}
} // psvm(...)
} // class MySQLDriveClassLoader
A successful compilation and run, resulted following output:
mySqlDriver: class com.mysql.jdbc.Driver
Is this interface? = false
Implemented Interface Name 1 = java.sql.Driver
Constructor Name = com.mysql.jdbc.Driver
Is Constructor Accessible? = false
sqlDriverInstance: com.mysql.jdbc.Driver#1270b73
con: com.mysql.jdbc.Connection#32fb4f
2012-05-29 03:52:12.0

DriverManager ignores classes loaded at runtime, it will work only for classes loaded by the System class loader.
You can create a Dummy driver class which encapsulates your actual database driver. Source code can be found here.
Off topic:
File.toURL is deprecated, instead get URL from File using toURL on URI
URLClassLoader urlCl = new URLClassLoader(new URL[] { f.toURI().toURL()},System.class.getClassLoader());

Related

Java ClassLoader different under Eclipse than when outside of Eclipse

I have written a simple Plugin system so that I can include extensions from external sources. The Plugin Manager loads plugins from predetermined application and user plugins directories. I use a custom URLClassLoader so that I can sandbox all Plugins. Here's the general approach:
Locate the Plugin's JAR file in one of the predetermined directories.
If the Plugin has already been loaded, return the instance of the Plugin that has already been created.
If an instance of the custom URLClassLoader has not been created for the directory containing the Plugin, create one.
Loop through each class in the Plugin's JAR file looking for Classes that implement the PluginInterface by loading the Class using Class.forName( pluginName, false, PluginClassLoader ) and then testing to see if the PluginInterface isAssignableFrom the loaded Class.
If the Class implements the PluginInterface then a new instance of the Class is created, initialized, and saved for later use.
All of this works great when I run it from within the Eclipse IDE. But, when I run it outside of the IDE, the check to see if the Plugin implements the PluginInterface fails. I believe this is because under Eclipse, both the Plugin and the Interface have a related (parent or child) ClassLoader (namely sun.misc.Launcher$AppClassLoader#73d16e93) and outside of Eclipse the PluginInterface has an unrelated ClassLoader (namely java.net.URLClassLoader#14ae5a5).
Here's the code:
The custom ClassLoader:
public class PROD_PluginClassLoader extends URLClassLoader {
protected PROD_PluginClassLoader( URL pluginFileUrl ) {
super( new URL[] { pluginFileUrl } );
}
protected PROD_PluginClassLoader( String pluginFilePath ) throws MalformedURLException {
super( new URL[] { new File( pluginFilePath ).toURI().toURL() } );
}
protected PROD_PluginClassLoader( URL[] pluginFileUrls ) {
super( pluginFileUrls );
}
}
The PluginLoader:
private static List< String > loadedPlugins = new ArrayList<>();
private static List< PROD_PluginInterface > plugins = new ArrayList<>();
private static Map< String, PROD_PluginClassLoader > pluginClassLoaders = new HashMap<>();
protected static void getPluginInstance( String pluginName, String pluginFilePath ) {
try {
PROD_Utilities.printDebug( "Loading plugin name(" + pluginName + ") from(" + pluginFilePath + ")" );
if ( !pluginClassLoaders.containsKey( pluginFilePath ) ) pluginClassLoaders.put( pluginFilePath, new PROD_PluginClassLoader( pluginFilePath ) );
PROD_PluginClassLoader pLoader = pluginClassLoaders.get( pluginFilePath );
boolean pluginLoaded = false;
for ( String n : PROD_Utilities.getClassNamesFromJarFile( pluginFilePath ) ) {
Class<?> pClass = Class.forName( n, false, pLoader );
String interfaces = "";
for ( Class<?> c : pClass.getInterfaces() ) interfaces += "," + c.getName();
if ( !interfaces.isEmpty() ) interfaces = interfaces.substring( 1 );
PROD_Utilities.printDebug( String.format( "Plugin name(%s) object class(%s) super(%s) interfaces(%s) isPlugin(%b)", pluginName, pClass.getName(), pClass.getSuperclass().getName(), interfaces, PROD_PluginInterface.class.isAssignableFrom( pClass ) ) );
if ( pClass.getInterfaces().length > 0 )
PROD_Utilities.printDebug(
String.format(
"pClass loader(%s) parent(%s) pClass interface loader(%s) parent(%s) PROD_PluginInterface loader(%s) parent(%s)"
,pClass.getClassLoader()
,pClass.getClassLoader().getParent()
,pClass.getInterfaces()[0].getClassLoader()
,pClass.getInterfaces()[0].getClassLoader().getParent()
,PROD_PluginInterface.class.getClassLoader()
,PROD_PluginInterface.class.getClassLoader().getParent()
));
if ( PROD_PluginInterface.class.isAssignableFrom( pClass ) ) {
Class<? extends PROD_Plugin> newClass = pClass.asSubclass( PROD_Plugin.class );
Constructor<?> constructor = newClass.getConstructor();
setPluginSandbox();
plugins.add( ( PROD_PluginInterface ) constructor.newInstance() );
plugins.get( plugins.size()-1 ).pluginInitialization();
unsetPluginSandbox();
pluginLoaded = true;
}
}
if ( pluginLoaded ) loadedPlugins.add( pluginName.toLowerCase() );
else PROD_Utilities.printError( "Plugin (" + pluginName + ") is not a valid PROD plugin." );
} catch ( InstantiationException | IllegalAccessException | IllegalArgumentException
| InvocationTargetException | ClassNotFoundException | NoSuchMethodException
| SecurityException | MalformedURLException e ) {
PROD_Utilities.printError( "Could not load plugin (" + pluginName + ").", e.getMesprod() );
}
}
The debug information when running under Eclipse:
Debug: PROD_PluginManager.getPluginInstance().line(138): Loading plugin name(proddb) from(C:\Users\userid\eclipse-workspace\prod\plugins\proddb.jar)
Debug: PROD_PluginManager.getPluginInstance().line(147): Plugin name(proddb) object class(com.company.prod.proddb.PRODDB) super(com.company.prod.PROD_Plugin) interfaces(com.company.prod.PROD_PluginInterface) isPlugin(true)
Debug: PROD_PluginManager.getPluginInstance().line(149): pClass loader(com.company.prod.PROD_PluginClassLoader#5ec0a365) parent(sun.misc.Launcher$AppClassLoader#73d16e93) pClass interface loader(sun.misc.Launcher$AppClassLoader#73d16e93) parent(sun.misc.Launcher$ExtClassLoader#55f96302) PROD_PluginInterface loader(sun.misc.Launcher$AppClassLoader#73d16e93) parent(sun.misc.Launcher$ExtClassLoader#55f96302)
The debug information when running outside of Eclipse:
Debug: PROD_PluginManager.getPluginInstance().line(138): Loading plugin name(proddb) from(C:\Users\userid\eclipse-workspace\prod\plugins\proddb.jar)
Debug: PROD_PluginManager.getPluginInstance().line(147): Plugin name(proddb) object class(com.company.prod.proddb.PRODDB) super(com.company.prod.PROD_Plugin) interfaces(com.company.prod.PROD_PluginInterface) isPlugin(false)
Debug: PROD_PluginManager.getPluginInstance().line(149): pClass loader(com.company.prod.PROD_PluginClassLoader#12405818) parent(sun.misc.Launcher$AppClassLoader#55f96302) pClass interface loader(sun.misc.Launcher$AppClassLoader#55f96302) parent(sun.misc.Launcher$ExtClassLoader#3d3fcdb0) PROD_PluginInterface loader(java.net.URLClassLoader#14ae5a5) parent(null)
I find it very strange that the PluginInterface ClassLoader has changed to a URLClassLoader.
I believe the problem is that the PluginInterface and the Plugin don't share a related ClassLoader and thus the Plugin's PluginInterface is technically a different Java interface from the Application's PluginInterface. If that assessment is correct then my question is how do I fix this so that the PluginInterface and the Plugin do share a related ClassLoader?
Or, perhaps my assessment is incorrect. In which case, my question is why doesn't the Plugin appear to implement the PluginInterface?
I've been wrestling with this for several days now so thanks in advance for any and all answers.
Edit
How is my code (not the plugin) loaded?
From within Eclipse: using the Eclipse Run -> Run menu option.
From outside of Eclipse: java -jar prod.jar
Well after a VERY long time, I finally figured this out and am posting my findings here in case anyone else runs across a similar issue with isAssignableFrom.
When exporting the program from Eclipse using the Export Wizard for Java->Runable JAR file, I chose Library handling option Package required libraries into generated JAR and was getting the isAssignableFrom failure as described in the original post. After re-exporting using Library handling option Extract required libraries into generated JAR, everything worked as expected.

Why isn't jruby closing db connections?

My calls to Oracle via jruby aren't closing their db connections.
Here is the code from the webpage making the call:
<%
require 'jdbc_ssl_connection'
# Database settings
url = "jdbc:oracle:thin:#(DESCRIPTION=(ADDRESS=(PROTOCOL=TCPS)(HOST=**REMOVED**)(PORT=**REMOVED**))(CONNECT_DATA=(SERVICE_NAME=**REMOVED**)))"
output = ""
select_stmt, rest, select_sql = nil
begin
conn = OracleConnection.create(url)
# Display connection using the to_s method of OracleConnection
select_sql = "select FIELD from SCHEMA.TABLE WHERE FIELD='"+#subject["file-name"].first+"'"
select_stmt = conn.create_statement
rset = select_stmt.execute_query select_sql
while (rset.next)
output = output + rset.getString(1)
end
rescue
error = "Error:", $!, "\n"
ensure
if (!select_stmt.nil?)
select_stmt.close
end
if (!rset.nil?)
rset.close
end
if (!conn.nil?)
conn.close_connection
end
end
%>
Here is the class that interacts with the driver.
# jdbc_ssl_connection.rb
require 'java'
java_import 'oracle.jdbc.OracleDriver'
java_import 'java.sql.DriverManager'
java_import 'java.util.Properties'
class OracleConnection
#conn = nil
def initialize (url)
#url = url
properties = java.util.Properties.new
properties['user'] = 'REMOVED'
properties['password'] = 'REMOVED'
# Load driver class
oradriver = OracleDriver.new
DriverManager.registerDriver oradriver
#conn = DriverManager.get_connection url, properties
#conn.auto_commit = false
end
# Add getters and setters for all attributes we wish to expose
attr_reader :url, :connection
def close_connection()
#conn.close() unless #conn
end
def prepare_call(call)
#conn.prepare_call call
end
def create_statement()
#conn.create_statement
end
def prepare_statement(sql)
#conn.prepare_statement sql
end
def commit()
#conn.commit
end
def self.create(url)
conn = new(url)
end
def to_s
"OracleConnection [url=#{#url}]"
end
alias_method :to_string, :to_s
end
The code works and is pretty simple. I ran a test and I have about 100 open sessions on the db. For some reason the call to close the connection isn't stopping the session. Any ideas what might be wrong?
def close_connection()
#conn.close() unless #conn
end
because of the conditional, you really wanted: #conn.close if #conn

How To Load classes using ClassLoader

I have an interface named Operator the directory of this interface is d:\operators
Interface definition is like so :
package operators;
public interface Operator
{
double calculate(double firstNumber,double secondNumber);
String getSign();
}
In the main program (d:\ProjectFile94.6.7\main) I want load this interface and use it .I load interface like so :
String rootPath = System.getProperty("user.dir")+System.getProperty("file.separator");
String operatorsPath = rootPath.replace("ProjectFile94.6.7" , "").replace("main" , "") + "operators";
System.out.println(operatorsPath);
//Load operators from another file
File operatorFile = new File(operatorsPath);
URL operatorFilePath = operatorFile.toURL();
URL[] operatorFilePaths = new URL[]{operatorFilePath};
ClassLoader operatorsLoader = new URLClassLoader(operatorFilePaths);
Class operatorInterface = operatorsLoader.loadClass("operators.Operator");
The app compiled fine but at runtime I got this exception :
java.lang.ClassNotFoundException : operators.Operator
You must not append the package name in the classpath directory:
String operatorsPath = rootPath.replace("ProjectFile94.6.7" , "").replace("main" , "");
i.e. the directory path should be just D:/. Otherwise, you're just telling the classloader to search for D:/operators/operators/Operator.class.

How to solve lua errors: "attempt to index ? (a nil value)" [duplicate]

This question already has an answer here:
Attempt to index local 'v' (a nil value)
(1 answer)
Closed 5 years ago.
There has been a lot of post about this kind of error and most people say it is related to table and array indexing problems. But I am not using tables at all, I am just trying to call a library function I made and I get this error. Here is the lua script called from java:
String script = new String (
"function event_touch ( )"
+ " pb.open_form ('view_monster');"
+ " print ('I ran the lua script');"
+ "end");
PBLUAengine.run_script(script, "event_touch");
This gives me the following error when trapping the exception:
"function event_touch ( ) pb.open_form ('view_monster'); print ('I ran the lua script');end:1 attempt to index ? (a nil value)"
The run_script() function calls the script like this( I am using luaj):
public static LuaValue run_script ( String script )
{
try
{
LuaValue chunk = s_globals.load( script );
return chunk.call();
}
catch ( Exception e)
{
Gdx.app.error ("PBLUAengine.run_script()", e.getMessage() );
}
return null;
}
The library method goes like this and the same piece of code works when called from java:
static class open_form extends OneArgFunction
{
public LuaValue call (LuaValue formname)
{
String tmpstr = (String ) CoerceLuaToJava.coerce(formname, java.lang.String.class );
try
{
PBscreen_game.hide_subscreen(PBscreen_game.MENU_SUBS);
PBscreen_game.show_subscreen ( PBscreen_game.FORM_SUBS);
PBsubscreen_form.open_form ( new PBform_regular ( tmpstr ) );
}
catch (Exception e)
{
Gdx.app.error("PBLUAlibrary.open_form", e.getMessage());
}
return valueOf ( 0 );
}
}
It basically convert the lua parameter to string, create a new from and pass in parameter the string.
The declaration of the library functions goes like this:
public LuaValue call( LuaValue modname, LuaValue env )
{
LuaValue library = tableOf();
library.set( "open_form", new open_form() );
library.set( "open_system_form", new open_system_form() );
env.set( "pb", library );
return library;
}
Which could be the only "table" I can see in the whole system. This is generally used link the right class with the right function name.
Anybody have an idea?
most people say it is related to table and array indexing problems
It's related to table and array indexing. If you try to index an object and that object is nil, you'll get that error:
I am not using tables at all [..] Here is the lua script:
pb.open_form
pb is being indexed. It's probably nil.
I seems that I solved the problem by adding a require line to include the library. So the new script is:
String script = new String (
"require 'com.lariennalibrary.pixelboard.library.PBLUAlibrary'"
+ "function event_touch ( )"
+ " pb.open_form ('view_monster');"
+ " print ('I ran the next button lua script');"
+ "end");
It ask to include my library class which will add all the "pb.*" functions. I probably deleted the line by error, or managed to make it work somehow without it. Since this library will be required by all script, I might append it by default before each script I try to run.
Thanks Again

can not instantiate driver class in Meteor method

I am trying to use JDBC inside my meteor application but I was not successful in loading the driver class.
the code is simple enough:
console.log("testing jdbc " + process.env.PWD + "/server/ojdbc14-11.2.jar");
var java = Meteor.require('java');
java.classpath.push(process.env.PWD + '/server/ojdbc14-11.2.jar');
console.log("class loaded");
var driver = java.newInstanceSync('oracle.jdbc.driver.OracleDriver');
console.log("driver instantiated");
var result = java.callStaticMethodSync('java.sql.DriverManager','registerDriver', driver);
console.log("driver registered");
result = java.callStaticMethodSync('java.sql.DriverManager','getConnection', 'jdbc:oracle:thin:user/password#local.sertal.ch:7788/KND1');
console.log("connection established");
I am using the Meteor npm package to include java the console never shows the message driver instantiated
I tried the same thing with a naked nodejs script and it worked fine. The code is almost the same:
var java = require('java');
java.classpath.push(__dirname + '/ojdbc14-11.2.jar');
var driver = java.newInstanceSync('oracle.jdbc.driver.OracleDriver');
var result = java.callStaticMethodSync('java.sql.DriverManager','registerDriver', driver);
var connection = java.callStaticMethodSync('java.sql.DriverManager', 'getConnection', 'jdbc:oracle:thin:user/password#local.sertal.ch:7788/KND1');

Categories

Resources