Differences between revisions 16 and 17
Revision 16 as of 2007-01-16 03:18:09
Size: 4433
Editor: sglanger
Comment:
Revision 17 as of 2007-01-16 03:27:10
Size: 4649
Editor: sglanger
Comment:
Deletions are marked like this. Additions are marked like this.
Line 73: Line 73:
                parameters = self.jarray.array([self.java.net.URL], self.java.l$                 parameters = self.jarray.array([self.java.net.URL], self.java.lang.Class)
Line 83: Line 83:

'''Conclusions'''




'''References'''

1. Information on IHE, http://www.ihe.net/Resources/index.cfm

2. The original Java classPathHacker, http://forum.java.sun.com/thread.jspa?threadID=300557

Introduction

During Oct-Nov 2006 there was a thread in the jython-users group titled "adding Jars to sys.path". More accurately the objective there was to add Jars to the sys.path at runtime. Several people asked the question, "Why would you want to do that?" Well there are at least 2 good reasons. First, if you want to distribute a jython or Java package that includes non-standard Jars in it, perhaps you want to make life easier for the target user and not demand that they know how to set environment variables. A second even more compelling reason is when there is no normal user account to provide environment variables.

"What?", you ask. Well, in my case I came upon it in the following way. I am authoring an Open Source IHE Image Archive Actor [1] and needed a web interface. I'm using AJAX on the client side to route database calls through CGI to a jython-JDBC enabled API. Testing the jython-JDBC API from the command line worked fine, I had the PostGres driver in my CLASSPATH. But, when called via the web interface I got "zxJDBC error, postGres driver not found" errors. Why? Because APACHE was calling the API and APACHE is not a normal account with environment variables.

What to do?

The jython-users thread had many suggestions but none were found to work. After a while, it occured to me that perhaps someone in the Java world had found a similar problem and had solved it. Then all I would have to do is trasnlate the solution. And that is exactly what happened.

Method

For brevity I will not repeat the original Java code here, but it will be linked to in the References [2]. This is how I call the Jython class (note that one can use either addFile or addURL depending on whether the Jar is on a locally accesable file system or remote server).

from com.ziclix.python.sql import zxJDBC

d,u,p,v = "jdbc:postgresql://localhost/img_arc2","postgres","","org.postgresql.Driver"

try :
    # if called from command line with .login CLASSPATH setup right,this works
    db = zxJDBC.connect(d, u, p, v)
except:
    # if called from Apache or account where the .login has not set CLASSPATH
    # need to use run-time CLASSPATH Hacker
    try :
        jarLoad = classPathHacker()
        a = jarLoad.addFile("/usr/share/java/postgresql-jdbc3.jar")
        db = zxJDBC.connect(d, u, p, v)
    except :
        sys.exit ("still failed \n%s" % (sys.exc_info() ))

And here is the class "classPathHacker" which is what the original author called his solution. In fact, you can simply Google on "classPathHacker" to find the Java solution.

class classPathHacker :
##########################################################
# from http://forum.java.sun.com/thread.jspa?threadID=300557
#
# Author: SG Langer Jan 2007 translated the above Java to this
#       Jython class
# Purpose: Allow runtime additions of new Class/jars either from
#       local files or URL
######################################################
        import java.lang.reflect.Method
        import java.io.File
        import java.net.URL
        import java.net.URLClassLoader
        import jarray

        def addFile (self, s):
        #############################################
        # Purpose: If adding a file/jar call this first
        #       with s = path_to_jar
        #############################################
                module = "utils:classPathHacker: addFile"

                # make a URL out of 's'
                f = self.java.io.File (s)
                u = f.toURL ()
                a = self.addURL (u)
                return a

        def addURL (self, u):
        ##################################
        # Purpose: Call this with u= URL for
        #       the new Class/jar to be loaded
        #################################
                module = "utils:classPathHacker: addURL"

                parameters = self.jarray.array([self.java.net.URL], self.java.lang.Class)
                sysloader =  self.java.lang.ClassLoader.getSystemClassLoader()
                sysclass = self.java.net.URLClassLoader
                method = sysclass.getDeclaredMethod("addURL", parameters)
                a = method.setAccessible(1)
                jar_a = self.jarray.array([u], self.java.lang.Object)
                b = method.invoke(sysloader, jar_a)
                return u

Conclusions

References

1. Information on IHE, http://www.ihe.net/Resources/index.cfm

2. The original Java classPathHacker, http://forum.java.sun.com/thread.jspa?threadID=300557

JythonMonthly/Articles/January2007/3 (last edited 2009-04-10 10:28:36 by AndrewKuchling)