This discussion is archived
3 Replies Latest reply: Jan 28, 2011 6:48 AM by 534035 RSS

Jython in Oracle JVM?

103122 Newbie
Currently Being Moderated
Hello, folks! Welcome to the Python forum!

I wanted to see if anybody's taken a crack at my wildest Oracle/Python ambition... I'd like to get jython.jar loaded into the JVM on Oracle. Then, I'll write Java stored procedures that are really Jython stored procedures... and I'll finally be able to read my own SP code!

I've take a couple halfhearted tries at it, but I really don't know Java very well and was easily turned away by towering Java error stacks. I still intend to find some quality time, fight my way through, and report back... but maybe somebody's already done it?

- Catherine
http://catherinedevlin.blogspot.com
  • 1. Re: Jython in Oracle JVM?
    kmensah Newbie
    Currently Being Moderated
    Hi,

    As described in chapter 5 of my book (http://db360.blogspot.com/2006/08/oracle-database-programming-using-java_01.html), here are the steps for installing the Jython runtime in your Oracle database:

    1. Download the latest jython implementation from:
    http://www.jython.org/download.html
    2. Generate jython.jar by running jython-21:
    java jython-21
    3. Load jython.jar in your schema:
    loadjava -v -u scott/tiger jython.jar


    Then use Jythonc to compile the Python code in Java.

    At this stage, this becomes the usual business of using Java in the database.

    Fwiw, running JACL, Groovy, and Scheme in the database are also described in the book.

    Kuassi http://db360.blogspot.com
  • 2. Re: Jython in Oracle JVM?
    MaximDemenko Pro
    Currently Being Moderated
    I have no java background therefore this sounds as an interesting alternative for getting java stored procedures for me too. After some digging i was able to load jython.jar and compile some very simple examples. The steps are practically the same as Kuassi mentioned, here some more details/culprits.

    The problems may differ for different versions/environments, so , my working setup is:
    Oracle 10.2.0.3 EE on Linux (Fedora Core 6), jython-2.2rc3. First i loaded jline-0.9.91.jar - got separately from sourceforge - in previous attempts a lot of classes were invalid due to dependeny on this package. Then loaded it with
    loadjava -r -f -noverify -v -u scott/tiger jline-0.9.91.jar
    To rum loadjava with -noverify flag i previously granted to scott user following java permission:
    SQL>exec dbms_java.grant_permission( 'SCOTT', 'SYS:oracle.aurora.security.JServerPermission', 'Verifier', '' )
    Next step - load jython itself ( after running jython_installer-2.2rc3.jar of course, for installation i used jdk shipped with oracle - $ORACLE_HOME/jdk/bin/java ).
    loadjava -r -f -noverify -v -u scott/tiger jython.jar
    That gave me about 1100 loaded classes, only 4 of them were invalid, for most purposes i considered that as minor issue.
    Then to load custom java classes compiled with jythonc i took following in consideration ( borrowed from documentation)
    To produce native java classes, there are some constraints for python code
    1) Code should reside within the class with the same name as the modul ( i.e. file Testj.py -> class Testj)
    2) java should be imported
    3) Jython class should subclass a java class/interface - for testing purposes i took simply
    import java
    class Testj(java.lang.Object):
       def ...
    4) By default jythonc compiles classes with private methods, to make public methods - which can be called from outside the class, a hint should be specified in form of comment
    def Testmethod(self,x):
          """@sig public int Testmethod(int x)"""
          # rest of the code
    Here it is meant - after """@sig comes the java specification of the method
    This can be looked up in the Jython FAQ and steps above will be sufficient to produce native java classes with simple call jythonc Testj.py and result in the ./jpywork direcotry containing a .java file with the source code and two compiled .class files - Testj.class and Testj$_PyInner.class, both of them should be loaded later in the database. However, to create a java stored procedure they lack the callable static method - jython don't allow to make methods static. To overcome it, one need a wrapper class ( at least i haven't found nothing similar on the google, so i did this way) - a very basically java class with a public static method, which instantiate a previously created jython class and call an instance method.
    public class TestjWrap {
     public static int fwrap(int n){
       Testj tj = new Testj();
       return tj.Testmethod(n);
     }
    }
    This wrapper can be put in the same jpywork directory and compiled with -classpath . (to find the previously compiled jython classes). Important - the jdk not newer than Oracle JVM should be used ( i had no luck initially - forgotten about jdk 1.5.0.11 installed on my machine and its javac in $PATH) - the simpliest solution is to use the jdk shipped with oracle . Then loadjava all 3 produced classes and create a wrapper pl sql procedure - that's all. Alternatively, jythonc can produce a jar file, which is simplier to redistribute and can be loaded as well. If you like, i could post later a complete example . Maybe i made some mistakes here, (i'm going to order Kuassi's book anyway - so i'll verify these steps) - but it worked finally.

    Best regards

    Maxim
  • 3. Re: Jython in Oracle JVM?
    534035 Newbie
    Currently Being Moderated
    Bringing this thread back from the dead in case anyone has had any further progress with this.

    The approach discussed in this thread and described in Kuassi's book is now outdated, as the latest Jython releases do not come with the Jythonc compiler necessary to turn jython files into callable java classes. http://wiki.python.org/jython/ReplaceJythonc

    Jythonc is planned to be released with a program called clamp: http://wiki.python.org/jython/ReplaceJythonc

    But development on this seems to have stalled, so for the time being, there is no method for compiling jython to java classes. This leaves two approaches:

    1) Write in Jython 2.2.. Not ideal for me as I'm trying to embed code written originally in Python 2.7.

    2) Embed the Jython interpreter inside the database, store the java code in there and interpret this on the fly.

    So - I've had an attempt at approach 2. Firstly, by loading the jython 2.5 jar file to a (11.2) database:

    loadjava -v -r -genmissing -f -u user/pass@//server:1521/service jython.jar

    All goes well, next I create a simple java class for calling the interpreter and call it:

    package jyinterface.factory;

    import org.python.util.PythonInterpreter;

    public class EmployeeFactory {
    public EmployeeFactory(String jythoncommand) {
    PythonInterpreter interpreter = new PythonInterpreter();
    interpreter.exec(jythoncommand);
    }

    public static void main(String[] args){
    System.out.println("Hello");
    EmployeeFactory e = new EmployeeFactory(args[0]);
    }
    }

    CREATE OR REPLACE PROCEDURE main(p1 IN VARCHAR2) AUTHID CURRENT_USER AS LANGUAGE JAVA NAME 'jyinterface.factory.EmployeeFactory.main(java.lang.String[])';

    SQL> exec main('print (range(10))');
    Hello
    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

    So far so good.

    Now the problems start...

    Lets say that in my interpreted code, I want to call another python module. So first up, I want to check the list of places to search in sys.path, and append onto this list the name of a directory on my server where I can place all the jython libraries.

    var c clob;
    begin
    :c := 'import sys
    print (sys.path)'
    end;

    exec main(c);

    Exception in thread "Root Thread" Traceback (most recent call last):
    File "<string>", line 2, in <module>
    java.lang.ClassCastException
    at org.python.core.PyType$MethodCache.lookup_where(PyType.java)
    at org.python.core.PyType.lookup_where(PyType.java)
    at org.python.core.PyType.lookup(PyType.java)
    at org.python.core.PyObject.object___findattr__(PyObject.java)
    at org.python.core.PyObject.__findattr_ex__(PyObject.java:887)
    .... snip

    This is the error I get for any kind of complex script I try to execute. I guess that the lookup_where call is trying to find a module from a folder on the file system, and coming unstuck.

    On other occasions, I run this command and the entire database instance crashes, (so if you're following these steps, make sure you're not on a production db!)

    I'm guessing a solution might go along the lines of overriding the lookup_where method so that is searches in a different way, perhaps through a table of clobs for example, rather than the file system. But at this point, my knowledge and time has run out. Has anyone else had a go at this, any better results? Please let me know.

    Many Thanks,

    James