The OSGi (Open Service Gateway initiative) specification describes a modular system and a service platform for the Java programming language that implements a complete and dynamic component model.
A service-oriented architecture that decouples components, and enables these components to dynamically discover each other for collaboration. Service provider component must register services after that consumer component will use this.
The framework is conceptually divided into the following areas:
Pre-requsite
Instructions assumes that jdk, Apache Felix 4.4.1 is installed without any error.
Following image will guide us to start Apache Felix 4.4.1.
Implemenation instructions
Click here to download source code of above example
-
Bundles (JAR file): Bundles are normal jar components with manifest headers. Bundles provide (export) and reuse (import) services via the OSGI framework. It defines encapsulation and declaration of dependencies (how a bundle can import and export Java packages and required component service packages). It implements specified interface (services) and these services will registered using Service Registry.
-
Services: The services layer connects bundles in a dynamic way by offering a publish-find-bind model.
-
Services Registry: The OSGI Framework interface for management services (ServiceRegistration, ServiceTracker and ServiceReference).
-
Life-Cycle: OSGi provide an API for managing bundles life-cycle states (Install[1]/Resolve[32]/Start[2]/Stop[4]/Update[8]/Uninstall[16]) ,so OSGi framework RI will control bundle lifecycle.
-
Security: The layer that handles the security aspects by limiting bundle functionality to pre-defined capabilities.
- Required Software
- Create a Simple spring project name "sample-osgi". Following image will guide us. Add the required libraries in classpath. - osgi.cmpn-5.0.0.jar - osgi.core-5.0.0.jar - osgi.enterprise-5.0.0.jar
- Create following packages. - service.provider - service.consumer
-
Create build.xml and build.properties and following snippet.
- content of build.xml.
<?xml version="1.0" encoding="UTF-8"?> <project name="sample-osgi" default="deploy" basedir="."> <!-- Import machine-specificsettings --> <property file="build.properties" /> <!-- Setup build paths --> <property name="build.dir" value="${basedir}/build" /> <property name="build.lib" value="${basedir}/lib" /> <property name="line.separator" value="," /> <property name="build.resource" value="${basedir}/resources" /> <property name="build.classes.dir" value="${build.dir}/classes" /> <property name="build.bundles.dir" value="${build.dir}/bundles" /> <property name="build.test.dir" value="${build.dir}/tests" /> <!-- Load the bnd custom task --> <taskdef resource="aQute/bnd/ant/taskdef.properties" classpath="${bnd.path}" /> <!-- Set aclasspath for the OSGi libraries --> <path id="osgilibs"> <fileset dir="${osgi.path}" includes="*osgi*.jar" excludes="*resource*"/> <fileset file="${bnd.path}" /> </path> <!-- TARGET : clean ; cleans all build o u t p u t s --> <target name="clean" description="Clean all build outputs"> <delete dir="${build.dir}" /> </target> <!-- TARGET : compile; compiles Java sources --> <target name="compile" depends="clean" description="Compile Java sources"> <pathconvert pathsep="${line.separator}" refid="osgilibs" property="build.classpath.list" /> <echo message="*****ClassPath Entries*****" /> <echo message="${build.classpath.list}" /> <mkdir dir="${build.classes.dir}" /> <javac optimize="on" includeantruntime="on" includejavaruntime="on" srcdir="src" destdir="${build.classes.dir}" debug="true" classpathref="osgilibs" /> <mkdir dir="${build.test.dir}" /> </target> <!-- TARGET : bundle ; g e n e r a t e s bundle JARs using bnd --> <target name="bundle" depends="compile" description="Build bundles"> <mkdir dir="${build.bundles.dir}" /> <!-- Convertan ANT file sett a flat list of files --> <pathconvert property="bnd.files" pathsep=","> <fileset dir="${build.resource}"> <include name="*.bnd" /> </fileset> </pathconvert> <bnd classpath="${build.classes.dir}" failok="false" output="${build.bundles.dir}" exceptions="true" files="${bnd.files}" trace="true" /> </target> <!-- TARGET : deploy ; clean felix-cache and start felix server --> <target name="deploy" depends="bundle" description="Build bundles"> <delete dir="${felix.home}/felix-cache" /> <copy todir="${felix.home}/bundle" overwrite="true"> <fileset dir="${build.bundles.dir}"> <include name="*.jar" /> </fileset> </copy> <tstamp> <format property="current.time" pattern="MM-dd-yyyy hh:mm:ss aa Z" /> </tstamp> <echo message="build finished at ${current.time}" /> </target> </project>
- content of build.properties. Please these value will changed in your case.junit.path=F:/dev/test/junit-4.12.jar bnd.path=F:/dev/felix 4.4.1/biz.aQute.bnd-latest.jar felix.home=F:/dev/felix 4.4.1/felix-framework-4.4.1/ osgi.path=F:/dev/felix 4.4.1/osgi
- Create example service interface "ExampleServiceInterface" in service.provider package and add following snippet.
- Create example implementation class ExampleServiceImpl which will implement service interface "ExampleServiceInterface" in service.provider and add following snippet.
- Create class ProducerActivator in service.provider and add following snippet.
- Create bnd file for producer app "sample-osgi-provider.bnd" in resource folder.
- Create class ExampleConsumer in package service.consumer and add following snippet. This class will consume the example service provided by service provider app.
- Create class consumer activator class in service.consumer.
- Create bnd file for consumer app "sample-osgi-consumer.bnd" in resource folder.
- now we will run build.xml. ant target "deploy" will create example consumer application first and then it will copy application jar to auto-deploy folder of felix.
- Open command prompt and go to felix.home and execute java -jar bin/felix.jar. This will start felix. Please check following image that will be the output.
/** * * Copyright © Kaustuv Maji , 2015 * Repos - https://github.com/kaustuvmaji * Blog - http://kaustuvmaji.blogspot.in */ package service.provider; /** * Example service interface. * * @author kmaji * */ public interface ExampleServiceInterface { /** * Printing message. * * @param message */ public void message(String message); }
/** * * Copyright © Kaustuv Maji , 2015 * Repos - https://github.com/kaustuvmaji * Blog - http://kaustuvmaji.blogspot.in */ package service.provider; import org.osgi.service.log.LogService; /** * Example Implementation class for service interface. * * @author KMaji * */ public class ExampleServiceImpl implements ExampleServiceInterface { private LogService logservice; /** * @param logservice */ public ExampleServiceImpl(LogService logservice) { this.logservice = logservice; } @Override public void message(String message) { logservice.log(LogService.LOG_INFO, "service provider printing message. -> [ " + message + " ]"); } }
/** * * Copyright © Kaustuv Maji , 2015 * Repos - https://github.com/kaustuvmaji * Blog - http://kaustuvmaji.blogspot.in */ package service.provider; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; import org.osgi.framework.BundleEvent; import org.osgi.framework.BundleListener; import org.osgi.framework.ServiceReference; import org.osgi.framework.ServiceRegistration; import org.osgi.service.log.LogService; /** * @author KMaji */ public class ProducerActivator implements BundleActivator, BundleListener { protected ServiceRegistration<?> registration; private ServiceReference<?> ref; private LogService logservice; @Override public void start(BundleContext context) throws Exception { context.addBundleListener(this); logservice = log(context); registration = context.registerService(ExampleServiceInterface.class.getName(), new ExampleServiceImpl(logservice), null); logservice.log(LogService.LOG_INFO, context.getBundle().getSymbolicName() + " started."); } @Override public void stop(BundleContext context) throws Exception { context.removeBundleListener(this); logservice.log(LogService.LOG_INFO, context.getBundle().getSymbolicName() + " stoped."); } @Override public void bundleChanged(BundleEvent event) { } private LogService log(BundleContext context) { this.ref = context.getServiceReference(LogService.class.getName()); if (ref != null) { logservice = (LogService) context.getService(ref); } logservice.log(LogService.LOG_INFO, " Starting log service for sample osgi example app."); return logservice; } }
Bundle-Version: 0.0.0 Bundle-Copyright: © kaustuv maji Bundle-Vendor: Knowledge Bundle-DocURL: http://kaustuvmaji.blogspot.in Import-Package: org.osgi.*,\ org.osgi.framework.*,\ org.osgi.service.*,\ org.osgi.util.*,\ * Export-Package: service.provider Service-Component: * Bundle-Activator: service.provider.ProducerActivatornow we will run build.xml. ant target "deploy" will create example service provider application first and then it will copy application jar to auto-deploy folder of felix.
/** * * Copyright © Kaustuv Maji , 2015 * Repos - https://github.com/kaustuvmaji * Blog - http://kaustuvmaji.blogspot.in */ package service.consumer; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.Timer; import service.provider.ExampleServiceInterface; /** * @author KMaji * */ public class ExampleConsumer implements ActionListener { protected ExampleServiceInterface service; protected Timer timer; public ExampleConsumer(ExampleServiceInterface service) { super(); this.service = service; timer = new Timer(1000, this); } public void startTimer() { timer.start(); } public void stopTimer() { timer.stop(); } /* * (non-Javadoc) * * @see * java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent) */ @Override public void actionPerformed(ActionEvent e) { service.message("from consumer 1"); } }
/** * * Copyright © Kaustuv Maji , 2015 * Repos - https://github.com/kaustuvmaji * Blog - http://kaustuvmaji.blogspot.in */ package service.consumer; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceReference; import org.osgi.service.log.LogService; import service.provider.ExampleServiceInterface; public class ConsumerActivator implements BundleActivator { protected ExampleConsumer consumer; protected ServiceReference<?> ref; private LogService logservice; @Override public void start(BundleContext context) throws Exception { LogService logservice = log(context); logservice.log(LogService.LOG_INFO, "Starting " + context.getBundle() + "!"); logservice.log(LogService.LOG_INFO, "Log service found for " + context.getBundle().getSymbolicName() + "!"); ref = context.getServiceReference(service.provider.ExampleServiceInterface.class.getName()); if (ref != null) { logservice.log(LogService.LOG_INFO, "Found service reference and now trying to consume provided service!"); consumer = new ExampleConsumer((ExampleServiceInterface) context.getService(ref)); if (consumer == null) { logservice.log(LogService.LOG_INFO, "consumer didn't found provider service :("); } consumer.startTimer(); } logservice.log(LogService.LOG_INFO, "Started " + context.getBundle() + "!"); } @Override public void stop(BundleContext context) throws Exception { logservice.log(LogService.LOG_INFO, "Stopping " + context.getBundle() + "!"); if (consumer != null) { consumer.stopTimer(); } logservice.log(LogService.LOG_INFO, "Stopped " + context.getBundle() + "!"); } private LogService log(BundleContext context) { this.ref = context.getServiceReference(LogService.class.getName()); if (ref != null) { logservice = (LogService) context.getService(ref); } logservice.log(LogService.LOG_INFO, " Starting log service for sample osgi example app."); return logservice; } }
Bundle-Version: 0.0.0 Bundle-Copyright: © kaustuv maji Bundle-DocURL: http://kaustuvmaji.blogspot.in Bundle-Vendor: Knowledge Service-Component: * Import-Package: * Export-Package: service.consumer Bundle-Activator: service.consumer.ConsumerActivator
kmaji /cygdrive/f/dev/felix 4.4.1/felix-framework-4.4.1 $ java -jar bin/felix.jar [INFO] Started bridged http service [INFO] Started bridged http service ____________________________ Welcome to Apache Felix Gogo g! 2015-01-03 19:58:20.319:INFO:oejs.Server:jetty-8.1.14.v20131031 2015-01-03 19:58:20.459:INFO:oejs.AbstractConnector:Started SelectChannelConnector@0.0.0.0:8080 [INFO] Started Jetty 8.1.14.v20131031 at port(s) HTTP:8080 on context path / [Bundle id { 20 } ( name resources.kaustuv-osgi-log.0.0.0)] :3: | BundleEvent STARTED [Bundle id { 22 } ( name resources.sample-osgi-provider.0.0.0)] :3: | BundleEvent RESOLVED [Bundle id { 21 } ( name resources.sample-osgi-consumer.0.0.0)] :3: | BundleEvent RESOLVED [Bundle id { 21 } ( name resources.sample-osgi-consumer.0.0.0)] :3: | Starting log service for sample osgi example app. [Bundle id { 21 } ( name resources.sample-osgi-consumer.0.0.0)] :3: | Starting resources.sample-osgi-consumer [21]! [Bundle id { 21 } ( name resources.sample-osgi-consumer.0.0.0)] :3: | Log service found for resources.sample-osgi-consumer! [Bundle id { 21 } ( name resources.sample-osgi-consumer.0.0.0)] :3: | Started resources.sample-osgi-consumer [21]! [Bundle id { 21 } ( name resources.sample-osgi-consumer.0.0.0)] :3: | BundleEvent STARTED [Bundle id { 22 } ( name resources.sample-osgi-provider.0.0.0)] :3: | Starting log service for sample osgi example app. [Bundle id { 22 } ( name resources.sample-osgi-provider.0.0.0)] :3: | ServiceEvent REGISTERED [Bundle id { 22 } ( name resources.sample-osgi-provider.0.0.0)] :3: | resources.sample-osgi-provider started. [Bundle id { 22 } ( name resources.sample-osgi-provider.0.0.0)] :3: | BundleEvent STARTED [Bundle id { 0 } ( name org.apache.felix.framework.4.4.1)] :3: | BundleEvent STARTED [Bundle id { 0 } ( name org.apache.felix.framework.4.4.1)] :3: | FrameworkEvent STARTED [Bundle id { 22 } ( name resources.sample-osgi-provider.0.0.0)] :3: | service provider printing message. -> [ from consumer 1 ] [Bundle id { 22 } ( name resources.sample-osgi-provider.0.0.0)] :3: | service provider printing message. -> [ from consumer 1 ] [Bundle id { 22 } ( name resources.sample-osgi-provider.0.0.0)] :3: | service provider printing message. -> [ from consumer 1 ] [Bundle id { 22 } ( name resources.sample-osgi-provider.0.0.0)] :3: | service provider printing message. -> [ from consumer 1 ] [Bundle id { 22 } ( name resources.sample-osgi-provider.0.0.0)] :3: | service provider printing message. -> [ from consumer 1 ] [Bundle id { 22 } ( name resources.sample-osgi-provider.0.0.0)] :3: | service provider printing message. -> [ from consumer 1 ] [Bundle id { 22 } ( name resources.sample-osgi-provider.0.0.0)] :3: | service provider printing message. -> [ from consumer 1 ] [Bundle id { 22 } ( name resources.sample-osgi-provider.0.0.0)] :3: | service provider printing message. -> [ from consumer 1 ] [Bundle id { 22 } ( name resources.sample-osgi-provider.0.0.0)] :3: | service provider printing message. -> [ from consumer 1 ] [Bundle id { 22 } ( name resources.sample-osgi-provider.0.0.0)] :3: | service provider printing message. -> [ from consumer 1 ] [Bundle id { 22 } ( name resources.sample-osgi-provider.0.0.0)] :3: | service provider printing message. -> [ from consumer 1 ]Now from console log snippet we can clearly figure out that service provider application already registered service interface and this service interface prints the message which is sent from consumer application. So if we refer to Figure no 1 Bundle B is our service provider bundle and Bundle A is our consumer bundle. Bundle B export and register service in osgi framework and Bundle A consumes it.
- Apache felix web-console
- Bundles management: url -> http://localhost:8080/system/console/bundles using this we can life-cycle of bundles. We can also install and un-install bundles.
- Log Service: url -> http://localhost:8080/system/console/logs using this we can check all the logs messages.
- Service management : url -> http://localhost:8080/system/console/services using this we can check all the available services the consumer app can consume.
Click here to download source code of above example
Source Code
- References:
European Union laws require you to give European Union visitors information about cookies used on your blog. In many cases, these laws also require you to obtain consent.
As a courtesy, we have added a notice on your blog to explain Google's use of certain Blogger and Google cookies, including use of Google Analytics and AdSense cookies.