Passing OSGi bundles for Jython Interpreter on-the-fly

648 views Asked by At

we would like to integrate the Jython interpreter into our Eclipse RCP based solution and we need to access the OSGi bundles (e.g. everything from Activator.getContext().getBundles() ) from there.

How could I pass these bundles to a Jython PythonInterpreter object python.path property, so I can import these classes from the Jython code?

(I get similar error messages when I try to import packages e.g.: from org.eclipse.chemclipse.msd.converter.chromatogram import ChromatogramConverterMSD)

ImportError: cannot import name ChromatogramConverterMSD

1

There are 1 answers

0
Janos Binder On

I managed to find a solution after working on this issue for days.

First we need a ClassLoader which can load OSGi bundles if necessary:

public class JythonClassLoader extends ClassLoader {

private final Bundle bundle;

public JythonClassLoader(ClassLoader parent, Bundle bundle) {
    super(parent);
    this.bundle = bundle;
}

@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {

    // System.out.println("findClass " + name);
    try {
        return super.findClass(name);
    } catch(ClassNotFoundException e) {
        Class<?> loadClass = bundle.loadClass(name);
        if(loadClass != null)
            return loadClass;
        throw e;
    }
}}

Then the PythonInterpreter needs to know about this ClassLoader. The best is to set up the environment for the PythonInterpreter before. The following class does the job:

public class JythonEnvironment {

private final Bundle bundle;

public JythonEnvironment(Bundle bundle) {
    this.bundle = bundle;
}

public PySystemState getPySystemState() {

    Properties properties = new Properties();
    String jythonPath = net.openchrom.thirdpartylibraries.jython.Activator.getJythonPath();
    properties.setProperty("python.home", jythonPath);
    properties.setProperty("python.cachedir.skip", "true");
    Properties systemProperties = System.getProperties();
    PySystemState.initialize(systemProperties, properties, new String[]{""});
    PySystemState pySystemState = new PySystemState();
    JythonClassLoader classLoader = new JythonClassLoader(getClass().getClassLoader(), bundle);
    pySystemState.setClassLoader(classLoader);
    return pySystemState;
}

public PythonInterpreter getInterpreter() {

    return new PythonInterpreter(null, getPySystemState());
}

public PythonInterpreter getInterpreter(OutputStream outStream, OutputStream errStream) {

    PythonInterpreter interpreter = new PythonInterpreter(null, getPySystemState());
    interpreter.setErr(outStream);
    interpreter.setOut(errStream);
    return interpreter;
}}

The JythonEnvironment class needs to know about the bundle. The best if that one can be received through the Activator.

JythonEnvironment environment = new JythonEnvironment(Activator.getDefault().getBundle());

Hope this answer will save time, if someone else needs to integrate Jython into an Eclipse RCP based solution.