Passing OSGi bundles for Jython Interpreter on-the-fly
Question: 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


Answer: 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.

