Skip to content

How to consume Python code from within OSGi

Ahmad Shahwan edited this page Sep 30, 2015 · 9 revisions

This tutorial shows how to consuming Python code from within OSGi in Cohorte.

Consuming Python code from within OSGi in Cohorte

This goes through 5 steps, that are detailed in the following sections.

  • Prepare an OSGi bundle;
  • Add the JAR file to the classpath of the JVM;
  • Add the package to OSGi's Extra-Packages;
  • Implementation;
  • Register Python implementation as an OSGi service.

Prepare an OSGi bundle

This is necessary for compilation, and not for run time.

It also makes the programmer's life easier than compiling a simple JAR, as a bundle's JAR file can be found by the bundles symbolic name from within Python, thanks to the method PythonModuleRepository.get_artifact() in cohorte.repositories.python.modules.

Compile time vs. Run time

Add the JAR file to the classpath of the JVM

        # Find the Herald API JAR file
        herald_jar = self._repository.get_artifact(HERALD_EVENT_API)
        classpath.append(herald_jar.file)
        # Start the JVM
        self._start_jvm(configuration.get('vm_args'), classpath,
                        configuration.get('vm_properties'))

Add the package to OSGi's Extra-Packages

This is necessary because bundles within OSGi are not accessible through JPype. Thus, during runtime, the API bundle is made accessible to bundles with OSGi through the Extra-Packages property.

# Prepare the "extra system package" framework property
osgi_properties.put(
    FRAMEWORK_SYSTEMPACKAGES_EXTRA,
    "{0}; version=1.0.0, {1}; version=1.0.0"
    .format(PYTHON_BRIDGE_BUNDLE_API, HERALD_EVENT_BUNDLE_API))

Implementation

To implement the following Java interface:

public interface IEventFactory {
    IEvent createEvent();
    void sleep(long aMilliseconds);
}

Python code can go as follows:

class EventFactory(object):
    """
    Implementation of org.cohorte.herald.eventapi.IEventFactory
    """
    JAVA_INTERFACE = HERALD_EVENT_FACTORY_INTERFACE

    def __init__(self, java_svc):
        """
        Sets up members
        """
        self._java = java_svc

    def createEvent(self):
        """
        Creates an event for the Java world
        """
        return self._java.make_proxy(EventProxy())

    def sleep(self, milliseconds):
        """
        Sleeps the given number of milliseconds
        """
        time.sleep(milliseconds / 1000.)

    def toString(self):
        """
        Java toString() method
        """
        return "Python Event Factory for Herald"

Register Python implementation as an OSGi service

# Make a Java proxy of the Herald bridge
herald_java = self._java.make_proxy(EventFactory(self._java))

# Register it to the framework
props = self._java.load_class("java.util.Hashtable")()
props.put("service.ranking", 1000)
self._bridge_reg = context.registerService(
    EventFactory.JAVA_INTERFACE, herald_java, props)