-
Notifications
You must be signed in to change notification settings - Fork 3
HowTo Grails OSGi integration in 5 minutes
With Arkadiko, integrating OSGi into any Spring Framework driven application is a piece of cake!
Here is an example using the Grails trip-planner app developed on the IBM DeveloperWorks blog a couple years back: http://www.ibm.com/developerworks/java/library/j-grails01158/
Setting up Grails:
- download from http://grails.org/Download
- install http://grails.org/Installation
Setting up the app:
- extract it
- cd into the
src/trip-planner
(let's assume the app is extracted to/opt/src/trip-planner
- execute
grails upgrade
(cause the code is a little old) - test the app by running
grails run-app
(open the url given in the browser)
In order to see what's going on we'll enable info logging for Grails. Open up /opt/src/trip-planner/grails-app/conf/Config.groovy
and at about line 62 (after the large log4j block) paste the following:
log4j = {
root {
info()
}
}
Now that logging is enable we need to add a couple of jars to the project:
- Arkadiko arkadiko-0.0.4-111108112238.jar
- some OSGi implementation (I used Equinox for this test, the following bundles are from the the 3.7 release org.eclipse.osgi_3.7.0.v20110613.jar)
In order to make this a little more interesting, let's install some other bundles, a simple logging adapter. That bundle uses declarative services, so we also have to install a few other bundles to enable support for it. Here is the list:
- bundle-log-adapter.jar
- org.eclipse.equinox.ds_1.3.0.v20110502.jar
- org.eclipse.equinox.util_1.0.300.v20110502.jar
- org.eclipse.osgi.services_3.3.0.v20110513.jar
Also, we'll download the Felix Gogo shell so that you can interact with the OSGi framework from the command line, once the app is up and running:
- org.apache.felix.gogo.runtime-0.10.0.jar
- org.apache.felix.gogo.shell-0.10.0.jar
- org.apache.felix.gogo.command-0.12.0.jar
The first two jars, arkadiko-0.0.4-111108112238.jar and org.eclipse.osgi_3.7.0.v20110613.jar, we'll place in /opt/src/trip-planner/lib
. The remaining jars we'll place into /opt/src/trip-planner/lib/osgi-plugins
.
Finally, we're ready to integrate the OSGi framework.
Open up /opt/src/trip-planner/web-app/WEB-INF/applicationContext.xml
and immediately after the opening beans tag paste the following:
<bean
id="framework"
class="com.liferay.arkadiko.util.AKFrameworkFactory"
factory-method="init"
destroy-method="stop"
>
<constructor-arg>
<map>
<entry key="org.osgi.framework.bundle.parent" value="app" />
<entry key="org.osgi.framework.startlevel.beginning" value="5" />
<entry key="org.osgi.framework.storage">
<!-- This is where the OSGi framework with save it's data. -->
<value>/opt/src/trip-planner/osgi-data</value>
</entry>
<entry key="org.osgi.framework.system.packages.extra">
<!-- List any packages that are needed in the framework from the app's classpath. -->
<value>org.apache.commons.logging</value>
</entry>
<entry key="bundles.force.start">
<value>true</value>
</entry>
<entry key="bundles.to.install">
<value>
lib/osgi-plugins/org.eclipse.equinox.util_1.0.300.v20110502.jar,
lib/osgi-plugins/org.eclipse.osgi.services_3.3.0.v20110513.jar,
lib/osgi-plugins/org.eclipse.equinox.ds_1.3.0.v20110502.jar,
lib/osgi-plugins/bundle-log-adapter.jar,
lib/osgi-plugins/org.apache.felix.gogo.command-0.12.0.jar,
lib/osgi-plugins/org.apache.felix.gogo.runtime-0.10.0.jar,
lib/osgi-plugins/org.apache.felix.gogo.shell-0.10.0.jar
</value>
</entry>
<entry key="project.dir">
<value>/opt/src/trip-planner</value>
</entry>
</map>
</constructor-arg>
</bean>
<bean
id="com.liferay.arkadiko.AKBeanPostProcessor"
class="com.liferay.arkadiko.AKBeanPostProcessor"
init-method="afterPropertiesSet"
>
<property name="framework" ref="framework" />
<property name="ignoredBeanNames">
<list>
<value>grailsApplication</value>
<value>grailsResourceLoader</value>
</list>
</property>
<property name="ignoredClassNames">
<value>org.codehaus.groovy.grails.commons.spring.GrailsRuntimeConfigurator</value>
</property>
</bean>
The first bean is a factory that sets up the framework that is required by the second bean which is a BeanPostProcessor (processes all other beans). Of course there are some limitations to what we can do, and only interfaces can be wired using OSGi because Arkadiko has to be able to create a proxy. So we have to filter out some beans that are not using interfaces, like grailsApplication
, grailsResourceLoader
, and the class org.codehaus.groovy.grails.commons.spring.GrailsRuntimeConfigurator
(these were discovered by trial and error, but only took a few attempts to find which beans couldn't be proxied).
That's it! We've now integrated OSGi into our Grails app by using Arkadiko.
So, how do we know it's working? Earlier we enabled more extensive logging, and added some useful bundles, so the first thing we should notice in the log are statements something like the following:
...
Running Grails application..
2011-11-09 00:19:03,651 [main] INFO http11.Http11Protocol - Initializing Coyote HTTP/1.1 on http-8080
2011-11-09 00:19:03,652 [main] INFO core.StandardService - Starting service Tomcat
2011-11-09 00:19:03,652 [main] INFO core.StandardEngine - Starting Servlet Engine: Apache Tomcat/6.0-snapshot
...
2011-11-09 00:19:04,667 [com.liferay.arkadiko.bundle.log.adapter.LogListenerImpl@19166179] INFO bundle-log-adapter - ServiceEvent REGISTERED {org.osgi.service.log.LogListener}= {component.name=com.liferay.arkadiko.bundle.log.adapter.LogListenerImpl, component.id=0, service.id=34}
2011-11-09 00:19:04,669 [com.liferay.arkadiko.bundle.log.adapter.LogListenerImpl@19166179] INFO bundle-log-adapter - BundleEvent STARTED
2011-11-09 00:19:04,676 [com.liferay.arkadiko.bundle.log.adapter.LogListenerImpl@19166179] INFO gogo.command - ServiceEvent REGISTERED {org.apache.felix.gogo.command.Basic}={osgi.command.function=[bundlelevel,frameworklevel,headers,help,install,lb,log,refresh,resolve,start,stop,uninstall,update,which], osgi.command.scope=felix, service.id=35}
2011-11-09 00:19:04,678 [com.liferay.arkadiko.bundle.log.adapter.LogListenerImpl@19166179] INFO gogo.command - ServiceEvent REGISTERED {org.apache.felix.gogo.command.Inspect}={osgi.command.function=[inspect], osgi.command.scope=felix, service.id=36}
2011-11-09 00:19:04,680 [com.liferay.arkadiko.bundle.log.adapter.LogListenerImpl@19166179] INFO gogo.command - ServiceEvent REGISTERED {org.apache.felix.gogo.command.Files}={osgi.command.function=[cd,ls], osgi.command.scope=felix, service.id=37}
2011-11-09 00:19:04,683 [com.liferay.arkadiko.bundle.log.adapter.LogListenerImpl@19166179] INFO gogo.command - ServiceEvent REGISTERED {org.apache.felix.gogo.command.OBR}={osgi.command.function=[deploy,info,javadoc,list,repos,source], osgi.command.scope=obr, service.id=38}
...
So we know our bundles are loading. But what did Arkadiko do to our other beans? If we look a little further into the log we should find statements something like:
...
2011-11-09 00:19:04,838 [com.liferay.arkadiko.bundle.log.adapter.LogListenerImpl@19166179] INFO eclipse.osgi - **ServiceEvent REGISTERED** {org.springframework.beans.factory.FactoryBean, org.springframework.beans.factory.InitializingBean, org.springframework.context.ApplicationContextAware}={original.bean=true, bean.id=**pluginManager**, service.id=47}
____________________________
Welcome to Apache Felix Gogo
g! 2011-11-09 00:19:04,849 [com.liferay.arkadiko.bundle.log.adapter.LogListenerImpl@19166179] INFO eclipse.osgi - **ServiceEvent REGISTERED** {org.codehaus.groovy.grails.plugins.GrailsPluginManager}={original.bean=true, bean.id=**pluginManager**, service.id=48}
2011-11-09 00:19:04,862 [com.liferay.arkadiko.bundle.log.adapter.LogListenerImpl@19166179] INFO eclipse.osgi - **ServiceEvent REGISTERED** {javax.servlet.Filter, org.springframework.beans.factory.BeanNameAware, org.springframework.web.context.ServletContextAware, org.springframework.beans.factory.InitializingBean, org.springframework.beans.factory.DisposableBean}={original.bean=true, bean.id=**characterEncodingFilter**, service.id=49}
...
We can see that all of the supported beans were published into the framework. This also means that they can be used, replaced or augmented dynamically from within the OSGi framework.
As you may notice also, there is a statement in the log Welcome to Apache Felix Gogo. This is a hint that the Gogo shell is running, and in fact it's running on stdout
which where the logs are being printed. So we should simply be able to type help
into the shell where we started the Grails app.
We should get the following output:
...
Server running. Browse to http://localhost:8080/trip-planner
2011-11-09 00:19:08,129 [main] INFO plugins.DefaultGrailsPluginManager - Started to scan for plugin changes in every 5000ms.
help
felix:bundlelevel
felix:cd
felix:frameworklevel
felix:headers
felix:help
felix:inspect
felix:install
felix:lb
felix:log
...
g!
Typing help lb
gives us the following:
g! help lb
lb - list all installed bundles
scope: felix
flags:
-l, --location show location
-s, --symbolicname show symbolic name
-u, --updatelocation show update location
lb - list installed bundles matching a substring
scope: felix
flags:
-l, --location show location
-s, --symbolicname show symbolic name
-u, --updatelocation show update location
parameters:
String subtring matched against name or symbolic name
g!
And there you have it! OSGi integrated into your Spring/Grails app.
Admittedly this is a pretty basic app with boring beans. But there is no limit to the number of beans that Arkadiko can theoretically bridge into the OSGi framework.