-
Notifications
You must be signed in to change notification settings - Fork 1
Osgi integration
##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:
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:
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\new
have been adjusted to print all available services (their titles) as links.
The following things must be done:
-
Get the newest sources from git:
git clone
-
Switch to osgi-integration branch:
git checkout osgi-integration
-
Pull the osgi-integration:
git pull
-
Configure the prototype as described in the Getting Started section (https://github.com/backmeup/backmeup-prototype)
-
Copy
autodeploy/org.backmeup.file.api*.jar
to lib folder. -
play run
-
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.)
-
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]
-
Specify the database within your
application.conf
(e.g.:db=mysql://user:password@localhost/backmeup
) -
Generate a web archive:
play war backmeup-prototype -o war-backmeup-prototype --zip
-
Download and install tomcat (e.g. http://tomcat.apache.org/download-60.cgi)
-
Copy
war-backmeup-prototype.war
to%TOMCAT_HOME%\webapps
-
Make sure the autodeploy folder has been setup correctly (see Optional Steps)
-
Start tomcat and access it via web (e.g. http://localhost:8080/war-backmeup-prototype/datasources/new)
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.
-
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 keyosgi.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
andorg.backemup.file.sample*.jar
to the autodeploy folder. -
You may specify the OSGi temporary directory in your
application.conf
by setting the keyosgi.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 theosgi.systemPackages
setting within theapplication.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 interfaceorg.backmeup.file.api.IFileService
which uses additional classes specified in packageorg.backmeup.file.data
. The bundleorg.backmeup.dropbox
implementsIFileService
and provides it as an OSGi service. The controllerDatasourceProfile
of the backmeup prototype accesses allIFileService
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 setosgi.systemPackages
this way:# OSGi Plugin configuration osgi.systemPackages=models,play,org.apache.log4j,org.backmeup.file.data,org.backmeup.file.api