Skip to content
This repository has been archived by the owner on Jul 18, 2022. It is now read-only.

Osgi integration

fschoeppl edited this page Feb 13, 2012 · 4 revisions

##Architecture of the OSGi-backmeup-protoype

The backmeup-prototype has been extended with a module called play-osgi, based on https://github.com/mathieuancelin/play-osgi. On bootstrap the module starts an Apache Felix OSGi container. An overview of the prototype can be seen in the following diagram:

overview picture

After the OSGi container has been started, a new thread starts and periodically checks a deployment directory for newly added and recently deleted bundles. These bundles will be automatically started / uninstalled. Additionally the module provides an injection mechanism for controller classes of the backmeup-prototype:

@Inject @OSGiService Iterable<Interface> interfaceServices;

The injector automatically detects the @OSGiService annotation within all controllers of the backmeup-prototype and provides access to all available OSGi-services that implement the given interface.

The following figure gives a detailed explanation of the architecture:

detailed prototype architecture

After you run the command play run the play-Framework activates all modules which have been placed in the modules directory. This triggers the onApplicationStart method of the class OSGiPlugin, which starts the Apache Felix OSGi container. Then it registers an instance of the class DeploymentMonitor which periodically searches and starts bundles found in the autodeploy directory. The autodeploy directory can be configured within the application.conf file (take a look at the Optional Steps section for more details). Next the module starts a dependency injector (Injector.inject) which handles occurrences of the @OSGiService annotation. This annotation can be used within controllers to lookup OSGi services.

The blueprint bundles handle the XML-configurations found in each bundle (path META-INF\spring\*.xml) and instantiate the OSGi services and dependent classes. An example service org.backmeup.file.sample has been added, which exports a service that implements the IFileService interface. The controller DatasourceProfiles and the view datasources\newhave been adjusted to print all available services (their titles) as links.

What do I have to do in order to run the play-osgi branch?

The following things must be done:

  1. Get the newest sources from git: git clone

  2. Switch to osgi-integration branch: git checkout osgi-integration

  3. Pull the osgi-integration: git pull

  4. Configure the prototype as described in the Getting Started section (https://github.com/backmeup/backmeup-prototype)

  5. Copy autodeploy/org.backmeup.file.api*.jarto lib folder.

  6. play run

  7. Open the "New Datasource" page and watch the new link "SampleFileService". (You might remove the org.backmeup.file.sample*.jar file from your autodeploy folder to unload it.)

How can I run the project with tomcat?

  1. Setup a database (e.g.: http://www.apachefriends.org/en/xampp-windows.html) [required because memory and file-mapped db's are not working within a webcontainer]

  2. Specify the database within your application.conf (e.g.: db=mysql://user:password@localhost/backmeup)

  3. Generate a web archive: play war backmeup-prototype -o war-backmeup-prototype --zip

  4. Download and install tomcat (e.g. http://tomcat.apache.org/download-60.cgi)

  5. Copy war-backmeup-prototype.war to %TOMCAT_HOME%\webapps

  6. Make sure the autodeploy folder has been setup correctly (see Optional Steps)

  7. Start tomcat and access it via web (e.g. http://localhost:8080/war-backmeup-prototype/datasources/new)

How can I use OSGi services within a controller?

You have to create a variable within your controller in the following way:

@Inject @OSGiService Iterable<Interface> interfaceServices;

It will be automatically populated with all OSGi-services that implement the Interface and can be used from any method within this class:

public void aSampleMethod() {
  for (Interface service : interfaceServices) {
    // do something with your services
  }
}

You might even pass all the services to your model by calling the 'render' method with the services as argument.

Note: If you create a new field that shall be injected, you'll have to restart the play-framework because the injector gets called only once while the first initialization; otherwise the value of the field will be null. That does however not disable dynamic loading of bundles, because the Iterable<Interface> is a proxy that accesses the OSGi layer on call.

Optional steps

  • If you want to use a different autodeploy folder, simply create one and copy the following blueprint bundles + dependencies into it (all required bundles can be found in the autodeploy folder of backmeup-prototype):

    • com.springsource.org.aopalliance-1.0.0.jar

    • gemini-blueprint-*.jar

    • org.apache.commons.logging_1.1.1.jar

    • org.springframework*.jar

      To use the new autodeploy folder you have to edit your application.conf and set the key osgi.autodeployDirectory. E.g. osgi.autodeployDirectory=C:\tmp\autodeploy\ (default: autodeploy).

  • If you want to use the sample-bundle aswell, you'll have to copy org.backmeup.file.api*.jar and org.backemup.file.sample*.jar to the autodeploy folder.

  • You may specify the OSGi temporary directory in your application.conf by setting the key osgi.tempDirectory. E.g. osgi.tempDirectory=C:\tmp\osgi\ (default: osgiTmp).

  • If you use a library within a bundle and a controller of the backmeup-prototype (or view), you'll have to copy it into the lib folder of the backmeup-prototype. Additionally you have to specify all packages that will be shared between the bundle and the backmeup-prototype by extending the osgi.systemPackages setting within the application.conf. This must be done because play and OSGi use their own class loaders. Accessing methods and passing / returning class instances created from different class loaders does not work. If the packages are shared between OSGi and play, OSGi will use the play class loader for the specified packages and therefore no class mismatches occur.

    Consider following example: Library org.backmeup.file.api contains the interface org.backmeup.file.api.IFileService which uses additional classes specified in package org.backmeup.file.data. The bundle org.backmeup.dropbox implements IFileService and provides it as an OSGi service. The controller DatasourceProfile of the backmeup prototype accesses all IFileService services:

      @Inject @OSGiService private static Iterable<IFileService> services;
      public static void createNew() { 
        User user = Security.connectedUser(); 
        List<String> listServices = new ArrayList<String>(); 
        for (IFileService ifs : services) { 
          listServices.add(ifs.getTitle()); 
        } 
        render(user, listServices);
      }
    

    As we are using IFileService within a controller and within a bundle, we have to share its package between the OSGi realm and the play-realm. Therefore we set osgi.systemPackages this way:

      # OSGi Plugin configuration
      osgi.systemPackages=models,play,org.apache.log4j,org.backmeup.file.data,org.backmeup.file.api