JTJ 2011 04
JTJ 2011 04
www.jaxenter.com
TM
In this issue of Java Tech Journal, we take a closer look at the OSGi dynamic module system for Java, with articles that address the controversial topic of OSGi's place in
enterprise development, a deep dive into the Core 4.3 specification, and a tour through some OSGi projects you may not have heard of.
OSGi
A Gentle Introduction to OSGi
The Perfect Starter
#8
OSGi A La Carte
Bundles, Bnd, PAX, Maven and more
Editorial
Index
3 15 20 24 30 37 41
OSGi A La Carte
Bundles, Bnd, PAX, Maven and more
Starting OSGi
OSGi Keypoints
OSGi specifications use Java as a base while avoiding classic Java headaches with a special classloading policy. The OSGi classloader deviates from the standard Java classloading policy while offering a way to support these impossible features: running several versions of the same component inside the same JVM true class reloading With such power, efficient application reloading becomes possible. So OSGi needs to extend standard Java to deliver components, that's why it just wraps the standard Java deployment format (.jar) while adding metadata into the misunderstood META-INF/MANIFEST.MF file. The OSGi platform hosts components offering services to other components (called bundles in OSGi jargon) and may depend on services offered by other bundles. Its a real microcosm but with a dynamic facet, where services can appear or disappear at any time. Figure 1 models such relationships between bundles. MANIFEST.MF file will contain all meta information required to express such relationships for each bundle. The following listing shows contents from one bundle requiring at runtime one service for logging purpose (its the standard OSGi logging service), this service may have different imple-
Starting OSGi
What can a shell do for you? Just getting full access to the bundles lifecycle while also providing an elegant way to integrate your own commands. If the commands list may change from one product to another, every shell will give you at least access to the bundles lifecycle, so you will be able to : install/uninstall a bundle start/stop a bundle get the list of installed bundles with their current state. Choosing a Shell Its a matter of choice but the writer uses felix for its very low footprint and tests its plugins with knopflerfish for convenience (graphic shell is very close to the specifications).
Figure 2: Different States
mentations but thats not the problem for our code. Please refer to the sample code provided in this article.
Bundle Lifecycle
In such a dynamic environment, components (packaged as jar files called bundles) may be installed, deployed, stopped or removed. Figure 2 from the OSGi Alliance website shows transitions into the different states possible for a bundle. The next section introduces OSGi shells, offering commands to control bundles states.
Services & Tracking From the OSGi point of view, a service is just a plain Java interface, this interface may be implemented in different manners. In such a dynamic environment, getting references to one of the compatible implementations is an absolute requirement. You may use one of the following ways to achieve this goal: use standard OSGi API. use the ServiceTracker to get a more convenient result. use the SCR or Declarative Services, to have an easy and powerful way to inject dependencies at runtime, like Spring Core does (Spring simply does dependency injection) OSGi Standard Services List OSGi defines the following list of services: http service, to expose with a Web interface resources contained in one bundle. logging service, to trace events encountered during runtime. event services, is a mono JVM (OSGi container related only) messages broker. configadmin, offers a complete API dedicated to storing configuration data for your bundles. preferences, describes how to store user preferences. metatype, enables modelling of meta data related to your structures and to handle them gently into GUIs. SCR or Declarative Services, is the way to inject dependencies into any service at runtime. Well have a closer look at two of these services: LoggingService and EventAdmin with complete code samples. In the first sample, we will send traces and retrieve them with the LogService API. Sending traces is trivial, just injecting a reference to the LogService, then using it to store LogEntries. Reading these
OSGi Shells
OSGi defines containers made to host applications delivered as bundles (the unit of deployment). The runtime controlling your applications is called a shell like Unix shells manage programs. Working with OSGi means delivering (provisioning) your application as bundles and deploying them into a shell. You may choose between different equivalent OSGi implementations: Apache Felix, Eclipse Equinox, Knopflerfish from Makewave You may use extensions from the OSGi specifications and use: Paremus shell (for Distributed OSGi) Apache CXF Eclipse ECF or for Enterprise OSGi products like: Apache Aries Apache Karaf is a useful shell too
Starting OSGi
traces is not difficult while using the LogReaderService (Listing 1). Figure 3 shows the results of two such bundles installed in a Felix container. Listing 2 illustrates how OSGi provides a smart way to master coupling between bundles using a messages brokerlike : EventAdmin. Sending events with EventAdmin. Figure 4 shows events in action.
The two bundles use a naming convention while sharing a common topic, the object storing messages (events in the EventAdmin wording). It's important to ensure to use the same name in both bundles to get a working communication.
Starting OSGi
strict cutting of responsibilities between components deployed into the OSGi container (bundles). The contract between a bundle and the container is the key point, it is materialized using the META-INF/MANIFEST.MF file. This contract lists explicitly what the component offers to the platform and what it requires from it. Defining services as Java interfaces into API bundles (delivering concrete implementations of this service in separate bundles) and specifying dependencies to the only
API bundle, enables us to change the implementation bundles without any impact on the client components. It's just a component aware manner to translate the TAO of object modelling, where you should use the most generic interface of a class rather than the most specific one. Conforming to this rule is necessary to do modular development. A component requiring a service does not need to know the implementation delivering this service, it is the black box principle. You don't need to be a mechanical specialist to start your car. With such a low level of coupling between components, good design principles become trivial, like the one of mocking components while testing your applications following Test Driven methodologies. Such design is the key to get working architectures in very short timeframes, the whole application feature list is being completed with the next releases if you follow an agile scheduling (XP, Scrum or whatever methodology you want). Many solutions may exist while trying to use a service. If using the basic OSGi API raises many problems and induces a lot of codelines, using the ServiceTracker while injecting service references directly into your component may be the better solution. SCR is a very dynamic and powerful solution, using it can be as simple as using the XML form or annotation as provid-
Figure 5: Releases
Starting OSGi
ed by bnd (refer to the tooling section). Its the best architectural response to the problems raised while trying to handle dependencies to services appearing/disappearing during the
runtime phase. Its not the only one because since early releases of specifications, OSGi provided different ways to do this job (ServiceTracker or through the Service API ).
public void deactivate(BundleContext context){ bc=null; System.out.println("dropping EventAdmin test bundle"); } //deactivate } Receiving events through EventAdmin package com.javaxpert.osgi.demo.eventadmin.receiver; import java.util.Dictionary; import java.util.Hashtable; import org.osgi.framework.BundleContext; import org.osgi.service.event.Event; import org.osgi.service.event.EventConstants; import org.osgi.service.event.EventHandler; import aQute.bnd.annotation.component.Activate; import aQute.bnd.annotation.component.Component; import aQute.bnd.annotation.component.Deactivate; /** * <p> * receives messages from well defined topics those * following the following naming convention : * com/javaxpert/osgi/tests/topicTest* * </p> * @author romje * @see EventHandler * */ @Component(immediate=true) public class EventReceiver implements EventHandler { private BundleContext bc; final static String [] topics = new String[] { "com/javaxpert/osgi/tests/topicTest" }; @Activate public void activate(BundleContext context){ bc=context; System.out.println("Receiver is ready soon..."); Dictionary d = new Hashtable(); d.put(EventConstants.EVENT_TOPIC, topics ); context.registerService( EventHandler.class.getName(), this, d ); } @Deactivate public void deactivate(BundleContext context){ bc=null; System.out.println("dropping test receiver.."); } @Override public void handleEvent(Event event) { System.out.println("Received a message from topic =" + event.getProperty(EventConstants.EVENT_TOPIC) + " containing : " + event.getProperty(EventConstants.MESSAGE) ); } }
Listing 2
package com.javaxpert.osgi.demo.eventadmin.sender; import java.util.HashMap; import java.util.Map; import org.osgi.framework.BundleContext; import org.osgi.service.event.Event; import org.osgi.service.event.EventAdmin; import org.osgi.service.event.EventConstants; import aQute.bnd.annotation.component.Activate; import aQute.bnd.annotation.component.Component; import aQute.bnd.annotation.component.Deactivate; import aQute.bnd.annotation.component.Reference; /** * <p> * Publishes events using the OSGi internal broker * EventAdmin is injected through SCR * </p> * @author romje, [email protected] * */ @Component(immediate=true) public class EventPublisher { private BundleContext bc; private EventAdmin eventService; @Reference public void setEventService(EventAdmin admin){ eventService= admin; System.out.println("Event service injected through SCR"); } //set public void unsetEventService(EventAdmin admin){ eventService= null; System.out.println("unset Event Service"); } //unset @Activate public void activate(BundleContext context){ bc=context; System.out.println(eventService!=null?"OK service ready to send msg":"oops no EVentService yet"); Map properties = new HashMap(); if(eventService!=null){ int number_messages = (int)(Math.random()*10); for(int i=0;i< number_messages;i++){ properties.put(EventConstants.MESSAGE,"message number = "+ i); eventService.postEvent(new Event( "com/javaxpert/osgi/tests/topicTest", properties)); System.out.println("Sent asynchronously a number of messages = "+ number_messages); } } //activate @Deactivate
Starting OSGi
a dedicated tool. Here comes bnd to the rescue. Bnd by Peter Kriens, OSGi Alliance fellow, is a versatile tool, the Swiss army knife OSGi tool. Bnd has three main roles, and it can perform three kind of jobs for you: inspecting a bundle wrapping a library into a compliant bundle creating a bundle from your code Bnd comes with its own syntax and set of directives, its very rich and only dedicated to one thing: having more compliant bundles, more quickly. Bnd scans your code to fetch imports so it computes for you the long list of imported packages.
Starting OSGi
Figures 10 - 12 show different tabs of this versatile tool , each one providing a concrete answer to a frequent need
Heres how to wrap an existing library into a ready to use OSGi bundle. Easy isnt it? Bnd inspects contents from your code and generates the import-package clause from MANIFEST.MF for you. It cant guess what services you want to expose so you must take care of this. You need to provide the privatepackage clause too.
2. IDE integration BndTools by Neil Barlett is the most powerful environment for OSGi development. It is an Eclipse plugin wrapping bnd features with a clear and intuitive interface. It just works!!! BndTools provides a new kind of project with a Bnd OSGi project. After creating such a project youll be able to access the following features:
Starting OSGi
directly test your code in Eclipse with your preferred shell watch/edit the contents from your MANIFEST.MF file inspect the contents from one bundle declare dependencies injection graphically with a dedicated wizard manage your runtime environment (adding bundles to be included in your shell at runtime) handle import/export clauses of your bundles graphically without any other intervention besides drag and drop. This tool is an incredible one, powerful and easy, providing bundles close to the specifications and close to the state of the art in OSGi development. Figure 6 and 7 show BndTools in different situations. Using this tool involves using a workflow like the following: create a new Bnd OSGi project create a Java package create some code (interface + implementation for a service or a single concrete Java class for a client) create a new bnd bundle descriptor adjust the bnd.bnd descriptor to suit your needs run the bnd.bnd with a Run As OSGi application (right click) Here you are, you have created your first bundle with BndTools. Please ensure to modify the Components tab view from each bundle using Declarative Services and adding one or more (maybe a joker) list of components. BndTools used in conjunction with Peter Krienss annotations provide a very convenient way to inject components without even writing a single line of XML as used by SCR. Well take our simple use case once again and rewrite it using BndTools and Bnd annotations.The following listings contain the complete source code for Java code and bnd files required in our context. 3. Debugging with Felix Web bundles What can go wrong during runtime? You may have unsatisfied dependencies, not so easy to find while the application is running (tricky indeed). The best solution is to install Felix WebConsole and to connect to this console through your browser to diagnose the origins of your problem. This is a very nice tool, easy to use and install. It has a few dependencies as shown in the next picture. Figures 10-12 show some facets from this very useful tool. You may use the different tabs offered to ensure that: all bundles have the expected state all dependencies are met messages (events in the EventAdmin wording). Its important to ensure to use the same name in both bundles to get a working communication. bundles implement the expected services Moreover the WebConsole can be used to view trace entries as issued by LogService and last but not least it is an extensible component. To conclude with this tool we should mention these requirements:
code makes usage from NIO so ensure your JVM offers this API webconsole is just a war deployed into the HttpService, so it requires you to install the Jetty Web bundle optional dependency to LogService Provisioning with Felix FileInstall FileInstall provides an easy way to install bundles into your OSGi container, using a single configuration file you will be able to configure one or several repositories (directories) targeted to host bundles and configuration properties file (for the ConfigAdmin Service). This bundle used in conjunction with the SCR is the perfect way to automate application starting, while having no hassles with the runlevels. It is a very convenient way to configure your application simply by setting a few properties as shown in the next sample. This sample shows properties used by Felix FileInstall to configure one deployment directory (felix.fileinstall.dir) and the polling interval (one second here), because Felix Install acts as a watchdog. These properties may be integrated into the Felix config file (living into ${felix.dir}/conf/config.properties).
felix.fileinstall.dir = deploy felix.fileinstall.poll = 1000
Felix FileInstall can be used as a replacement or in conjunction with the OBR (Bundles repository). OBR is an http repository like the ibiblio one for Maven storing many Java projects ready to use in OSGi environments.
Conclusion
I wish you a good trip into this new approach to software development, I am convinced that it should bring you success and fun, success because of its efficiency and great design, fun because of the pleasure felt in designing applications that just work! I have still many things to write about this technology but it is time for me to conclude. Happy coding.
Jerome Moliere discovered Java early 1996, he is a SCJP2 and JBoss certified architect. He is doing consulting and training for his own company Mentor/J. He is about to deliver the first French book dedicated to OSGi. He can be reached at [email protected]. He blogs at http:// romjethoughts.blogspot.com/
References
Pointers - OSGi specifications [1] Felix project: http://felix.apache.org [2] Equinox project: http://www.eclipse.org/equinox [3] Knopflerfish project: http://www.knopflerfish.org [4] Paremus distributed OSGi: http://www.paremus.com [5] Apache Aries: http://aries.apache.org JMS specifications [6] Bnd: http://aQute.biz/bnd [7] BndTools: http://bndtools-updates.s3.amazonaws.com [8] Felix Web Console: http://felix.apache.org/ [9] OBR repository: http://www.osgi.org/Repository/HomePage
10
www.jaxconf.com
Java EE Java Core Java Languages UI/Ajax/Components Agile ALM Android Cloud Web Architecture Portals Webtech & JavaScript Just JSF Fullstack Spring OSGi
Technical presentations and tutorials In-depth coverage of the latest technologies Practical implementation techniques Neutral coverage of the most important Java Ecosystem topics
follow us:
JAXconf Partners:
twitter.com/JAXconf
JAXConf
JAXConf
Organized by:
JAX 2011 Its about you, its about Java, its about
Web, Architecture, Cloud & Agile
JAX is one of the world's most comprehensive conferences on web and enterprise development. It provides the ideal forum for software developers, project managers and architects to learn about all the latest Technology, Architecture and Agile Methodologies. JAX has become internationally renowned for its unique blend of topics, since its conception in 2001. This year JAX is pleased to be working in collaboration with the popular JSF Summit; a conference for application developers, solution architects, and project managers who develop applications with JavaServer Faces (JSF), Seam, Java EE, and related technologies. Wed like to provide you a snapshot of our programme. Please find more updates on www.jaxconf.com!
MOBILE KEYNOTE
Web vs. Apps
Ben Galbraith (Set Direction)
With the recent release of Firefox 4, we're reminded that today's browsers sport amazing capabilities, truly graduating from markup renderers to sophisticated app run-times.
We're sure to see some amazing new web applications just over the horizon that take advantage of these new capabilities. At the same time, the mobile ecosystem is white hot. What relationship do mobile "apps" have with the web and how will these two communities co-exist into the future? Also, how do developers target all of these different platforms? Join Ben and Dion as they share their thoughts on these and other issues.
MOBILE DAY
Android 3.0: Honeycomb Highlights
Chet Haase (Google), Romain Guy (Google)
Come hear engineers from the Android team at Google talk about the latest advancements in the Android platform, and how you can take advantage of these features to create great Android applications.
to create a system that is more than the sum of its parts. Whether they are public or private, cloud platforms impose constraints on guest applications as part of their design, and for sound economic reasons. We draw from several examples of public and private cloud services, and show how the target system influences application design. A common theme is the need to assess modularity and services differently as architectural styles in the cloud. We show some tips and tricks on using and enabling features of Spring in the cloud and draw examples and demos from a wide range of application styles and cloud platforms.
SPRING DAY
Moderator: Rod Johnson
JSF SUMMIT
Moderator: Kito Mann
Originally produced by Kito Mann and JSFCentral.com, JSF Summit is a conference for application developers, solution architects, and project managers who develop applications with JavaServer Faces (JSF), Seam, Java EE, and related technologies.
Productive RIA Development with Spring Web Flow and JSF 2.0
Jeremy Grelle (SpringSource, a division of VMware)
With the onset of JSF 2, it's time for a fresh look at what Java development tools make up the ideal web stack. In this session you'll learn what is important from a Spring developer's point of view: What can I do with Spring and JSF 2? What is the status of the Spring Web Flow integration for JSF? What JSF 2 features are supported and what value does Spring Web Flow provide in a JSF 2 world?
http://jaxconf.com/2011/jsfsummit/
More talks and tutorials on all important Java related topics can be found here:
www.jaxconf.com
OSGi Update
Becomes:
ServiceReference<LogService> lr = context.getServiceReference(LogService.class); LogService log = context.getService(lr);
The changes provide type safe references to OSGi services and avoid the need for explicit casts.
15
OSGi Update
cation defines the built-in namespaces: osgi.wiring.package, osgi.wiring.bundle and osgi.wiring.host, to represent the existing concepts of exporting and importing packages, requiring bundles and being a fragment respectively. For example, within the osgi.wiring.package namespace, an export package is represented by a capability and an import package is represented by a requirement. The idea of generic capabilities and requirements is also added. This allows bundle programmers to define their own namespaces so a bundle can provide a capability with the new Provide-Capability manifest header and have a requirement for a capability with the new Require-Capability manifest header.
These requirements become additional constraints to the resolver in the OSGi Framework and are visible in the new Bundle Wiring API (Figure 1). A bundle cannot be resolved unless its mandatory requirements can be satisfied by a capability from some bundle. The built-in namespaces cannot be used on the new Provide-Capability and RequireCapability manifest headers). In addition to the built-in namespaces, the specification defines the new osgi.ee namespace to replace the org.osgi.framework.executionenvironment framework launching property and the Bundle-RequiredExecutionEnvironment manifest header. Now bundles can use the Require-Capability manifest header to declare a requirement in the osgi.ee namespace on the execution environment. Frameworks can be configured with the new org.osgi.framework.system. capabilities and org.osgi.framework.system.capabilities.extra framework launching properties to provide capabilities in the osgi.ee namespace representing the current execution environment. This will result in the system bundle providing the specified capabilities which can then satisfy the requirement from a bundle.
Figure 3: The wiring for an update bundle that has not been refreshed.
16
OSGi Update
grammers. But the cost of this design choice was an API that is not very object oriented since you have to pass the Bundle objects to the methods. Ten years later, todays resource constrained systems are much bigger, and we also find that the PackageAdmin service does not well model the actual wiring of bundles in the Framework. In 4.3, we introduce the new Bundle Wiring API which replaces PackageAdFigure 4: Relationship between the min and provides a much system bundle and the Framework richer model of the wiring Wiring type relationship between bundles. Instead of using a service to deliver the new API, the API is available via the new, type safe adapt method on Bundle. To learn about the wiring state of a bundle, adapt the Bundle object to the desired bundle wiring type. For example:
BundleWiring wiring = bundle.adapt(BundleWiring.class);
If a bundle has been updated, older revisions and wirings of the bundle may still be in use. All the available revisions of a bundle can be obtained by adapting the bundle to the BundleRevisions type (Figure 3). The system bundle can be adapted to the FrameworkWiring type which provides access to framework wide wiring operations. Using the FrameworkWiring object, bundles can be resolved and refreshed. Refreshing a bundle will result in the non-current revisions and wirings to be released by the Framework. The removal pending bundles, that is, the bundles which have non-current revisions and wirings, can also be obtained. All of these operations are very useful for management code (Figure 4). While PackageAdmin has been deprecated and replaced by the Bundle Wiring API, framework implementations will still implement the PackageAdmin service for some time to come to support existing bundles that use the PackageAdmin service.
Whenever a bundle is installed or updated, a new revision of the bundle is created. A BundleRevision for a bundle contains information about a specific revision of the bundle such as the symbolic name, version and declared capabilities and requirements. The most recent revision of a bundle is called the current revision and can be obtained by adapting the bundle to the BundleRevision type. Whenever a bundle is resolved, a new wiring of the bundle is created. A BundleWiring for a bundle contains information about a specific wiring of the bundle such as the capabilities and requirements that are wired together. The wiring can also be used to scan the class path of a bundle and to obtain the class loader of a bundle. The most recent wiring of a bundle is called the current wiring and can be obtained by adapting the bundle to the BundleWiring type (Figure 2).
Weaving Hooks
Bytecode weaving is becoming very popular particularly in enterprise applications such as those using JPA. There has long been interest in bytecode weaving in OSGi but there has never been an OSGi standard way to do it. In 4.3, we introduce Weaving Hooks. Weaving Hooks are services registered by bundles that are prepared to weave the class files loaded from other bundles. Whenever the Framework is preparing to load a class from a bundle, it first calls the weaving hooks to give them an opportunity to mutate the class file for the class. The Framework will create a WovenClass object for the class being loaded and call the WeavingHook services in service ranking order. Each weaving hook will have the opportunity to mutate the byte array containing the class file of the class to be loaded. Since it is quite common for a weaver to add code which may call classes which are not originally used by the bundle, for example, tracing or logging APIs, the weaver needs to be able to modify the woven bundles wiring so the bundle can access these classes. So the WovenClass object lets the weaving
17
OSGi Update
hook add DynamicImport-Package entries to the bundles wiring. These entries can refer to the packages which contain the classes used by the newly woven class. Once all the weaving hooks have been called, the Framework will put the new DynamicImport-Package entries into effect and call the VM to define the woven class (Figure 6). Since weaving hooks can modify classes from other bundles, care must be taken in developing and deploying weaver bundles to ensure the integrity and security of the system.
Resolver Hooks
In previously released drafts for Core 4.3, there were specification proposals for Composite Bundles and virtual frameworks. These proposals were attempts at defining a grouping model for bundles such that bundles in a group would be able to share packages and services while bundles outside the group would have more limited access. Both of these design proposals have been replaced in the final Core 4.3 specification with the introduction of Resolver Hooks and Bundle Hooks. The Resolver Hooks, along with Bundle Hooks and Service Hooks, provide low level primi-
tives upon which grouping policies for bundles can be implemented. Using these hooks allows different grouping policies to be created rather than specifying a single grouping policy into the Framework. A ResolverHookFactory is a service that is registered by bundles that wish to influence the Frameworks resolver and how it wires bundles together. For each resolve operation, the Framework will call the ResolverHookFactory services, in service ranking order, requesting a ResolverHook object that will be used for the duration of the resolve operation. Each resolver hook object will be called and given the opportunity to influence the resolve operation by restricting the bundles that can be resolved and which candidate capabilities can be used to satisfy a requirement (Figure 7). So, while a resolver hook cant actually make the decisions about how the bundles are wired together, it can influence the choices the resolver can make. This allows a resolver hook to create a grouping policy for bundles with respect to how the bundles can be wired. Using the new Resolver Hooks, the Service Hooks introduced by 4.2, and the new Bundle Hooks, a complete grouping model can be implemented [3]. Since resolver hooks can modify how, and even if, bundles are resolved, care must be taken in developing and deploying resolver hooks to ensure the integrity and reliability of the system.
Bundle Hooks
The Service Hooks introduced by 4.2 and the new Resolver Hooks are important parts of implementing a grouping policy for bundles. With Resolver Hooks you can place limits on how bundles are wired together at resolve time. With Service Hooks you can place limits on what services are visible to a bundle. The missing piece is how to limit which bundles are visible to a bundle. This is the purpose of the newly introduced Bundle Hooks. Bundle Hooks are services registered by bundles that are called by the Framework, in service ranking order, when the Framework must decide whether a bundle can observe
18
OSGi Update
another bundle. Two bundle hooks are defined. The Find Hooks are called by the Framework during the processing of the getBundle(long) and getBundles() methods of BundleContext. These methods are used by bundles to find other bundles. A FindHook is able to remove bundles from the result set thus preventing the calling bundle from observing the removed bundles. The other bundle hook is the Event Hook. The Event Hooks are called by the Framework during the delivery of Bundle Events. An EventHook can remove bundles from the set of bundles whose listeners would receive the bundle event. This prevents the removed bundles from observing the Bundle Event (Figure 8). Bundle Hook implementations must take care to ensure that bundles consistently observe or dont observe other bundles. That is, with the Event Hook, a bundle should see either all or none of the life cycle events for a bundle. Seeing only a partial set of events can result in undefined behavior for the observing bundle.
At the OSGi Alliance, we are continuing to work on new specifications and enhancements to the existing specifications. If you have input or want to participate in the effort, please check out the OSGi Alliance web site [4] for information on joining the OSGi Alliance or providing feedback.
BJ Hargrave is a Senior Technical Staff Member at IBM with over 20 years of experience as a software architect and developer. His focus is small computer operating systems (kernels, file systems, development tools, application binary interface specifications) and Java technology. He holds multiple patents related to Java and is the IBM expert and lead architect for OSGi technologies. BJ holds a Bachelor of Science in Computer Science from Rensselaer Polytechnic Institute and a Master of Science in Computer Science from the University of Miami. BJ has been a leader in the development of the OSGi technology since its inception and was named an OSGi Fellow in 2002 for his technical contributions and leadership in the OSGi Alliance. He is currently CTO of the OSGi Alliance and chair of the OSGi Core Platform Expert Group. BJ is also a committer on the Eclipse Equinox project. Peter Kriens is the OSGi Director of Technology and CEO of aQute. He has worked for many years as a consultant for a large number of international companies, including Adobe, Intel, Ericsson, IBM, and others. In 2001 he was hired by the OSGi Alliance to run their specification process. He is the primary editor of all the specification releases since release 2 in May 2001. In 2002 he became one of the original two OSGi Fellows. He lives in France travels the world to help the different OSGi expert groups to accomplish their tasks.
Summary
Version 4.3 of the Core specification is another incremental improvement over past specifications. The basic abstractions of OSGi: modularity, dynamic life cycle and services, all continue as before. These new features add to the level of introspection and control of the Framework. Some of the new features enable new and powerful capabilities to be built upon the Framework. Take care if you decide to use these low level features since they can have a significant effect on other bundles.
References
[1] http://www.osgi.org/Download/Release4V43 [2] http://www.ibm.com/developerworks/java/library/j-jtp02277/index.html [3] http://underlap.blogspot.com/2011/02/stumbling-towards-better-design.html [4] http://www.osgi.org
Imprint
Publisher Software & Support Media GmbH Editorial Office Address Geleitsstrae 14 60599 Frankfurt am Main Germany www.jaxenter.com Editor in Chief: Editors: Authors: Sebastian Meyen Jessica Thornsby, Claudia Frhling David Bosschaert, Alexander Broekhuis, Holly Cummins, Tim Diekmann, BJ Hargrave, Peter Kriens, Valentin Mahrwald, Jerome Moliere, Richard Nicholson, Marcel Offermanns, Dmytro Pishchukhin Copy Editor: Claudia Frhling, Lisa Pychlau Creative Director: Jens Mainz Layout: Dominique Kalbassi Sales Clerk: Mark Hazell +44 (0)20 7401 4845 [email protected] Entire contents copyright 2011 Software & Support Media GmbH. All rights reserved. No part of this publication may be reproduced, redistributed, posted online, or reused by any means in any form, including print, electronic, photocopy, internal network, Web or any other method, without prior written permission of Software & Support Media GmbH The views expressed are solely those of the authors and do not reflect the views or position of their firm, any of their clients, or Publisher. Regarding the information, Publisher disclaims all warranties as to the accuracy, completeness, or adequacy of any information, and is not responsible for any errors, omissions, inadequacies, misuse, or the consequences of using any information provided by Publisher. Rights of disposal of rewarded articles belong to Publisher. All mentioned trademarks and service marks are copyrighted by their respective owners.
19
4+1 View
The 4+1 views method is a popular method for describing architectures. Architectural views are used to describe the system from the viewpoint of different stakeholders. It is based on 4 views, on top of which use case scenarios are used to describe interaction within the system. The 4 views are: Logical View Process Development Physical
20
BndTools
BndTools is a relatively new tool for building and testing OSGi based projects in Eclipse. It builds on Bnd, which is a powerful command line tool. Bnd is described on its own website as: the Swiss army knife of OSGi, it is used for creating and working with OSGi bundles. Its primary goal is take the pain out of developing bundles. From http://www.aqute.biz/Bnd/Bnd Bnd solves the need to completely write and maintain the manifest file of a bundle. This manifest file is closely related to the classes in the bundle, and updating it can be very error prone. Bnd uses the actual class files to create the manifest file, this includes dependencies to packages, but for example also including packages using wild cards etc. Bnd relies on .bnd files created by the developer to customize the bundle. The file is used to define the bundle symbolic name, the exported and private package, bundle classpath etc. Maintaining these files by hand can be a cumbersome process, typos are easily made resulting in failing bundles. This is where BndTools comes back in the picture. BndTools provides a new project type in Eclipse called an OSGi project. An OSGi project is defined by a bnd. bnd file in which, for example, the build path for the project is defined. This build path can consist of other bundles, but also a classpath containing plain old jar files. A project can consist of one or more bundles, and each bundle is defined by a .bnd file in which the metadata for the bundle is placed. Since BndTools is tightly integrated with Eclipse, Eclipse compiles and builds bundles on code changes. Besides bundles, BndTools also supports run configurations. The configurations are used to launch an OSGi framework with a selected set of bundles. This set of bundles currently automatically includes all bundles from its own project, additional bundles can be selected from a local bundle repository. This bundle repository will be detailed later on. Using the dynamics of OSGi, in combination with the on the fly generation of bundles, BndTools makes it possible to update bundles in the running configuration. Before detailing more about how BndTools works, lets see how this maps on the 4+1 views method. The two views relevant for the developer in this case are still the development and deployment view. From the development viewpoint, a uniform view on all the sources and resources in a project is needed. This view should not assume anything regarding the deployment of the artifacts created out of the source. Since BndTools does not impose a project is a bundle structure, this is exactly what is needed. Secondly, the deployment view is also needed to be able to understand how bundles can and cant interact with each other. For example, packages which are used by a bundle, but are never exported. BndTools (actually Bnd does all the work) provides support for this by analysing the imported packages in the source with the exported packages of bundles. When looking at the 4+1 model, BndTools provides the developer with a complete development view, but still provides enough support to add and point to restrictions which the deployment imposes on the application. Its method is also especially interesting for existing projects, there is no need to divide the source into bundles. The existing project can be kept, only a number of .bnd files are needed to create the bundles. Besides, the better mapping on the 4+1 views, this model also keeps the source within one
project. This makes refactoring work over all bundles instead within one, as is the case with Eclipse OSGi development. Finally, BndTools also has support for a so called repository. The repository is used to store dependencies needed by the projects. This repository is visible as an Eclipse project in your workspace called cnf and can contain both third party dependencies in different versions and stable artifacts that have been released from your own projects (so other projects can depend on them). Using this repository keeps the project clean, no additional bundles need to be placed inside the project. Also using one repository ensures multiple related projects within the workspace use the same available dependencies.
Example
The following simple example will be used to create an application with one Hello World bundle. It is assumed Eclipse with BndTools is up and running. The steps followed will be: Create a new workspace Add a Bnd OSGi project Setup the run configuration Add a new bundle Create a new workspace and select the OSGi perspective. A dialog will be shown asking to create a configuration project. This configuration project contains the bundle repository. After creating the configuration, the workspace will contain one project called cnf. With the OSGi perspective also comes the Repositories view. This view lists all bundles installed in the repository. A BndTools projects comes preconfigured with a list of useful bundles, including Felix, Equinox and many other compendium services. The bundles shown in this view are all located in the cnf project (figure 1).
21
change, it is no longer possible to configure the bnd.bnd" file as a bundle. Bundles can be added by creating a new bundle descriptor. Before creating the bundle, the project needs an OSGi framework and possibly some other bundles. These libraries can be added to the run configuration of the bnd. bnd file. The run configuration can be found on the run tab. The desired OSGi framework can be selected, and bundles from the repository can be added. For this example, Apache Felix is used as framework and the Apache Felix Shell bundles are added. After updating the run configuration, the project can already be run. This is done on the context menu of the bnd.bnd" file. Select Run As -> OSGi Run. This will result in starting the framework with the selected bundles. Since the shell is installed, it is possible to inspect the running bundles. Listing these bundles, using the ps command, will show the system bundle as well as the shell bundles. For the next steps, the framework can be kept running (figure 2).
can be seen. The newly created bundle has been installed in the running framework, and every saved change has resulted in a bundle update. The bundle has been started and the Hellogreeting has been printed. Listing the installed bundles now also shows the created bundle (figure 4).
22
www.jaxente
20 Issue March 11 | presente d by
r.com
TM
ch va Teal Ja rn Jou
the at some of closer look ing , we take a includ JAXmag EE 6 space, this issue of ts g the Java t into the nu es occupyin t an insigh technologi ge X-RS, and Java EE Web ement the illian and JA Arqu ns to impl h the what it mea tour throug and bolts of start with a ! 6 overview cation. Let's EE ifi tion: a Java Profile spec e specifica e of th latest releas
ag JAXm w o
is n
plication assFish ap e, and 3.1 of the Gl sFish releas th, version as Last mon the new Gl 6 for Java EE leased. With re ated server was n Server sl t is still a ho c Applicatio r Java EE 6 e WebLogi ea Oracl ours year, its cl abbing rum e later this e-gr complianc In l the headlin EE 7 and 8. despite al ures in Java technology e new feat ing about th circulat
PDF edition
The free PDF magazine powered by JAXenter! www.jaxenter.com
#6
va EE 6 Ja
verview lease Java EE 6 O e Latest Re
ugh Th A Tour Thro e CDI in G How to Us
iPad edition
Get the FREE App in the iTunes Store!
Java Tech Journal is the digital-only magazine covering all the hot topics for Java and Eclipse developers. Each issue deep dives into one topic, be it the Scala programming language
or Agile development. The magazine provides an insight into emerging trends in the Java universe, and offers best practices for established technologies on a monthly basis.
OSGi la carte
A web search on OSGi will yield a bewildering number of open source projects. Beyond the familiar Equinox and Felix, as OSGi moves into the Enterprise Java space the number of OSGi related projects is increasing. If you are interested in OSGi many of these projects will be useful to you but it may not be immediately obvious how. This article hopes to alleviate this shortcoming with a whirlwind tour through the most useful open source tools the authors have encountered.
By Valentin Mahrwald & Holly Cummins
OSGi as a technology has been around since the late 90s, originally in the embedded space. More widespread interest has arisen after Eclipse adopted OSGi as the integration and plugin technology underlying the Eclipse IDE. This move was followed by the adoption of OSGi as the modularization technology at the heart of most JEE application servers. Even then OSGi was much rarer in the space of individual applications. Only with the advent of a dedicated enterprise OSGi programming model with Spring dmServer have we seen widespread interest in OSGi. Historically, OSGi has often been perceived as a hard technology to get started with especially since OSGi certainly is an invasive technology. Correctly using OSGi and its modularity model requires discipline and forethought from developers and framework authors. Especially assumptions made concerning classloaders often no longer hold in an OSGi environment. However, the benefits of using OSGi for modularization as well as its inherent support for dynamics far outweighs the initial challenges in using it. This article hopes to remove some of the biggest hurdles of using OSGi by introducing an appropriate set of tools, many of which are of recent vintage. The first set of tools is intended to help with the task of developing bundles. Next, we look at the tools that facilitate integration (i.e. in-container) testing with OSGi. Finally, we have a look at deployment and distribution options. It is assumed that the reader has some familiarity with basic OSGi concepts like bundles, bundle manifests, services and OSGi lifecycle. Readers completely new to OSGi are referred to introductory resources such as Neil Bartletts OSGi in practice [1] as well as the OSGi home page [2].
Developing bundles
At the very simplest level an OSGi bundle is just a traditional JAR file whose manifest has some additional headers that define the identity of the bundles as well as its (package) capabilities and requirements its imports and exports. However, the often cited bold claim No more NoClassDefFoundErrors with OSGi relies on correct metadata. A missing import for a needed package can easily mean that OSGi at the very
24
first usage actually introduces more missing classes rather than less. So at the minimum tools for OSGi development should help the developer to produce correct metadata and well-factored bundles. Beyond that development tooling should help with test running the bundles and ideally have support for the OSGi programming models such as the component models, Web Application Bundles, persistence bundles and the like.
For developing more enterprise focussed OSGi applications, for example using JPA end Servlet functionality in bundles, Eclipse Libra [4] promises to be an interesting option. Loosely related to IBM's free (but not open sourced) OSGi development tools [5] this project aims to integrate existing high quality Eclipse tools for JEE development with OSGi specific functionality as defined in the corresponding chapters of the OSGi Enterprise Specification.
25
complex bundle assemblies, which pull classes from multiple sources, bundle verification as well as launching a framework for running an application or running integration tests. The invocations below show very basic usage for converting a JAR to a bundle (Listing 1). Although the above example shows Bnd as a stand-alone command line tool, it can be integrated into Ant or Maven builds. Neil Bartlett has even created a complete Eclipse development environment, BndTools [8], based on Bnd. The complete package includes very capable editors for defining bundles (even several for a single Eclipse project), support for running a collection of bundles and even hot swapping code changes into the running framework. On top of that there are prebuilt templates for defining Declarative services components (Figure 1) and integration tests.
Listing 1
# Display the manifest of some.jar java -jar bnd.jar print -manifest some.jar # Display any unresolved (non-imported) class package references java -jar bnd.jar print -verify some.jar # Convert a plain jar to OSGi. The properties file can be used # to configure imports, exports etc java -jar bnd.jar wrap -properties props.bnd some.jar
Component Models
Finally, no section on OSGi development would be complete without mentioning the component models, which greatly simplify using the OSGi dynamism and in particular OSGi services (or Services as Peter Kriens has dubbed them [11]). These two models absolve the developer from the responsibility of using the complicated OSGi API for services and in part can also hide some of the dynamism where it is not desired. Two component models are standardized as part of the OSGi compendium specification and are in wide use. The older component model, Declarative Services, allows the definition of service components. These components are plain Java classes that are instantiated as well as activated and deactivated by the Declarative Services extender. Components can have dependencies on other services, which are injected by the extender. At runtime components are defined in XML. However, the Bnd tool also allows a simpler property syntax as well as annotations. Built on top of that the BndTools have a set of nice editors and project templates for working with Declarative Services. The code sample below shows an example of an annotated component and the equivalent (generated) XML. The sample component uses zero or more StockProvider services, which can dynamically be added or removed (Listing 2). The newer component model, Blueprint, which was introduced with OSGi Compendium Specification revision 4.2, offers a full dependency injection framework, syntactically based on the popular Spring framework, together with first class support for interacting with the OSGi service registry. Apart from the syntax of the XML component descriptors perhaps the most notable difference between Declarative Services and Blueprint lies in how both expose OSGi service dynamics. Declarative services expose dynamics directly to the client code. A service that is injected via one method (addProvider
Listing 2
@Component public class StocksGui { @Activate public void start() { // start the component, by showing the GUI } @Deactivate public void stop() { // deactivate the GUI } @Reference(type='*') public void addProvider(StockProvider provider) { // respond to a new provider } public void removeProvider(StockProvider provider) { // respond to a provider becoming unavailable } } <scr:component xmlns:scr='http://www.osgi.org/xmlns/scr/v1.1.0' name=' org.jaxlondon.stocks.gui.StocksGui' activate='start' deactivate='stop'> <implementation class='org.jaxlondon.stocks.gui.StocksGui'/> <reference name='provider' interface='org.jaxlondon.stocks.api.StockProvider' cardinality='0..n' bind='addProvider' unbind='removeProvider' policy='dynamic'/> </scr:component>
26
Listing 3
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"> <reference-list id="providers" interface="org.jaxlondon.stocks.StockProvider" availability="optional"> <reference-listener bind-method="addProvider" unbind-method="removeProvider" ref="gui" /> </reference-list> <bean id="gui" class="org.jaxlondon.stocks.gui.StocksGui" init-method="start" destroy-method="stop"> <property name="providers" ref="providers" /> </bean> </blueprint>
Listing 4
// Execute this unit test with the Pax Exam runner @RunWith(JUnit4TestRunner.class) public class ServiceTest { @Test // The bundle context gets supplied by Pax Exam public void apiBundleShouldBeStarted(BundleContext bundleContext) throws Exception { // the test bundle starts together with other bundles, so we use a service // tracker rather than exposing the test to a race condition ServiceTracker tracker = new ServiceTracker(bundleContext, StockProvider.class.getName(), null); tracker.open(); StockProvider provider = (StockProvider) tracker.waitForService(1000); assertNotNull(provider); } // Define the framework configuration(s) to be tested @Configuration public static Option[] configuration() { return options( frameworks( felix(), equinox() ), junitBundles() mavenBundle("org.ops4j.pax.logging", "pax-logging-api"), mavenBundle("org.apache.aries.blueprint", "org.apache.aries.blueprint"), mavenBundle("jaxlondon.stocks", "stocks-api", "1.0-SNAPSHOT"), mavenBundle("jaxlondon.stocks", "stocks-ftse-random", "1.0-SNAPSHOT"), ); } }
in the example), is removed via another method (removeProvider in the example). A component is deactivated when a mandatory service dependency goes away and re-activated when a replacement becomes available. Blueprint, on the other hand, attempts to hide some of these dynamics. For example if a required service dependency becomes unavailable, a Blueprint bean is not stopped or notified. In fact it will continue to operate until the component tries to use the required service in some way. At that point the Blueprint container will pause to wait for a replacement service to become available and then continues the suspended method call on the service. Through this service damping OSGi bundles built on Blueprint can remain oblivious to short outages (due to for example live updates) of their service dependencies while still enjoying the benefits of potentially continuous updates. Of course Blueprint also has support for letting components listen and react directly to service lifecycle events. The Blueprint snippet in Listing 3 shows the Blueprint descriptor equivalent to the Declarative services descriptor shown before.
Deployment
The question of deployment arises relatively early for OSGi projects. With OSGi it is no longer enough to run the Java command with an appropriately long classpath and point to some main class. Instead the task of deploying an OSGi application is complicated by the need first to bootstrap an OSGi framework and then to install and activate the application bundles plus all their dependencies. At the simplest one can start each of the three common open source frameworks (Apache Felix [13] , Eclipse Equinox [14] and Knopflerfish [15]) and then use the default console
27
of the framework all of which are different! or the OSGi framework API to install further bundles. This approach soon becomes highly inconvenient and does not help the accessibility of OSGi frameworks. Especially, for complex applications that use one or more of the compendium or enterprise specifications this way clearly is not an option. Fortunately there are various options both for easily bootstrapping custom slim OSGi runtimes as well as full enterprise strength pre-built runtimes. In almost all cases the various runtime bits are completely runtime-independent as one would expect from the components of a technology focussed primarily on modularity and can be reused in any other of the runtimes.
Pax Runner
As an alternative to the basic native launch facilities of the individual OSGi frameworks, the Pax Runner project [16] provides a unified way to launch any of three open source frameworks (always with the default console installed) and to provision application and support bundles into that framework. This makes starting a simple OSGi application a breeze. Bundles can be provisioned from a variety of sources: files on disk, URLs as well as simple provisioning text files that list bundle resources. In particular there is a lot of flexibility in the URL scheme (through the embedded use of the Pax URL projects); bundles can be sourced directly from a Maven repository by its Maven coordinates. Finally, profiles provide a number of very useful pre-built bundle selections for common capabilities such as a Declarative Services runtime. The command below shows one particular invocation.
pax-run --platform=equinox --profiles=felix.ds <bundles ...>
model, remote access, JAAS based security and provisioning not to mention an excellent and extensible shell (based on the Felix Gogo shell), all of which make working with Karaf a real pleasure. Similar to the profiles that Pax Runner offers are Karaf features, which capture commonly needed functionality. For example, to deploy a Web Application Bundle (WAB) one can simply install the war feature. There is even a feature to deploy a full-fledged Spring dmServer runtime (see below). With a plentitude of predefined EE features, a custom enterprisey runtime that contains just the needed features can be bootstrapped in a breeze. Karaf features can also be used from Pax Runner through the custom scan-features URL scheme. Note that in some cases prerequisites that are available by default in Karaf need to be added manually in a blank Pax Runner framework. One particularly nice option that deserves separate mention is the possibility of provisioning a web console, based on the Apache Felix Web Console [18], which of course can also be installed separately in other runtimes.
Provisioning
Pax Runner profiles and Karaf features rely on pre-defined collections of bundles. This has the benefit that the concrete selection of bundles that make up a feature can be tested reliably. However, this provisioning mechanism is not able to exploit the existence of capabilities in the runtime. For example, the war feature needs the servlet API and will install the Geronimo servlet API bundle regardless of whether the servlet classes are already available (at the right package version) in the runtime. The key challenge for features and profiles are that they are oblivious to the declared bundle dependencies (Import-Package, Require-Bundle etc) and hence the provisioning system cannot avoid duplication. An interesting alternative that does not suffer from this problem is the OSGi Bundle repository technology (OBR), available from Apache Felix OBR [19]. An OSGi bundle repository stores not just bundle binaries but also their capabilities and requirements as extracted from the bundle manifest and possibly other sources (such as component descriptors etc). The provisioner can use these and information about the current runtime to provision exactly what is needed. So provisioning bundle A, which depends on capabilities X and Y where Y is already available in the runtime, will install A and a bundle that provides X (plus any additional transitive dependencies of that bundle). This is a powerful provisioning model that eliminates the need to exactly specify bundle combinations once and for all and shifts the brunt of the work to the provisioning system. For playing around with OBR, Karaf offers an OBR provisioner in the OBR feature. Generating bundle repositories can either be done via the Bindex tool [20], which supports just package and bundle dependencies declared in the bundle manifest, or the Apache Aries repository generator [21], which also generates capabilities and requirements for Blueprint defined services and references this allows servicebased provisioning. A collection of public OBR repositories can be found at Apache Felix Sigil [22].
This command bootstraps an Equinox framework, then installs all the bundles required for the Apache Felix Declarative Services implementation and finally installs all the listed files as bundles into that runtime.
Karaf
One step up from Pax Runner comes Karaf [17], which provides a much more full-fledged proto-runtime while still being very light-weight and fast to start. By default Karaf comes with excellent built-in support for the Blueprint component
Listing 5
Manifest-Version: 1 Application-ManifestVersion: 1 Application-SymbolicName: org.apache.aries.samples.blog.jpa.eba Application-Version: 0.3.0 Application-Name: Apache Aries Blog Sample EBA using JPA Application-Description: This EBA contains the sample Blog application. Application-Content: org.apache.aries.samples.blog.api;version="0.3.1.SNAPSHOT", org.apache.aries.samples.blog.web;version="0.3.1.SNAPSHOT", org.apache.aries.samples.blog.biz;version="0.3.1.SNAPSHOT", org.apache.aries.samples.blog.persistence.jpa;version="0.3.1.SNAPSHOT"
28
different tools and frameworks is staggering. This only goes to show the maturity of the components and benefits of OSGi as a platform for modularity and reuse.
Valentin Mahrwald is a software engineer at the IBM Hursley Development Laboratory in Hampshire. He has over two years of experience working on WebSphere Application Server, most of this time spent on the OSGi Applications feature, for which he has also authored the accompanying IBM RedBook. He is an active Apache Software Foundation committer in the Apache Aries project. Valentin holds a Masters degree in Mathematics and Computer Science from the University of York. Holly is a software engineer at IBM's Hursley labs. She is a popular speaker and has spoken at a variety of industry events including Devoxx, JavaZone, The ServerSide Java Symposium, The Great Indian Developer Summit, and WebSphere User Groups. She has also authored several developerWorks articles. She contributes to the Apache Aries project and to WebSphere feature packs. Holly has been with IBM for nine years. Before joining IBM, she completed a doctorate in quantum computation at the University of Oxford.
References
[1] http://njbartlett.name/osgibook.html [2] http://www.osgi.org [3] http://www.eclipse.org/pde/ [4] http://www.eclipse.org/libra/ [5] http://ibm.co/ai2GUy [6] http://www.aqute.biz/Bnd/Bnd [7] http://njbartlett.name/2010/08/24/osgi-compliance-levels.html [8] http://njbartlett.name/bndtools.html [9] http://maven.apache.org/ [10] http://wiki.ops4j.org/display/paxconstruct/Pax+Construct [11] http://www.osgi.org/blog/2010/03/services.html [12] http://paxexam.ops4j.org/space/Pax+Exam [13] http://felix.apache.org/ [14] http://eclipse.org/equinox/ [15] http://www.knopflerfish.org/ [16] http://paxrunner.ops4j.org/ [17] http://karaf.apache.org/ [18] http://felix.apache.org/site/apache-felix-web-console.html [19] http://felix.apache.org/site/apache-felix-osgi-bundle-repository.html [20] http://www.osgi.org/Repository/BIndex [21] http://aries.apache.org/documentation/tools/repositoryGenerator.html [22] http://felix.apache.org/site/apache-felix-sigil-obr.html [23] http://geronimo.apache.org/ [24] http://eclipse.org/virgo/ [25] http://glassfish.java.net/ [26] http://eclipse.org/gemini/ [27] http://aries.apache.org/ [28] http://wiki.ops4j.org/display/paxweb/Pax+Web [29] http://cxf.apache.org/distributed-osgi.html [30] http://www.eclipse.org/ecf/ [31] http://tuscany.apache.org/
Distribution
Soon after the first steps of OSGi development are taken many people wonder how to connect things up. For example how can I make two OSGi applications running in two different frameworks talk to each other? How easily can OSGi applications be distributed across multiple deployment systems? How can I connect an OSGi application to a legacy JEE application? Apache CXF and Tuscany provide some answers. Apache CXF [29] is the reference implementation of the Distributed OSGi specification. With very simple metadata additions it allows two OSGi frameworks to be connected on the OSGi service levels. This method of distribution fits very nicely with the OSGi service model, which is dynamic from the start. As with most OSGi specification implementations there is an Eclipse equivalent for distributed OSGi in the ECF project [30]. Apache Tuscany [31] can be used to connect OSGi services to non-OSGi artifacts such as traditional Java, Spring or Web components. For this Tuscany supports SCA (Service component architecture) components to be implemented by OSGi services. In this way such services can be consumed by other SCA components, which are not necessarily implemented in OSGi. Similarly OSGi services defined as SCA components can declare references to and thus consume other SCA components as services, which again need no longer be implemented in OSGi.
Conclusion
This brief tour has hopefully inspired the reader with the sense of how much the OSGi ecosystem has to offer. In the authors experience the amount of reuse between the various
29
Persistence
30
Persistence
@Entity @Table(name = "STUDENTS") public class Student { public static final String GET_STUDENTS = "GET_STUDENTS"; public static final String GET_STUDENT_BY_ID = "GET_STUDENT_BY_ID"; @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private int id; private String firstName; private String lastName; @ManyToOne(optional = false) private Group group; public Student() { } public Student(String firstName, String lastName, Group group) { this.firstName = firstName; this.lastName = lastName; this.group = group; } public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public int getId() { return id; } public Group getGroup() { return group; } public void setGroup(Group group) { this.group = group; } }
31
Persistence
<exclude-unlisted-classes>true</exclude-unlisted-classes> to disable scanning of persistence unit by persistence provider and attach only classes that are explicitly listed. The file should be stored under META-INF/persistence.xml path. The next step for the model is to pack all classes into OSGi bundle. (maven-bundle-plugin configuration - Listing 3). The most important OSGi MANIFEST headers are: Import-Package should contain javax.persistence;version ="1.1.0";jpa="2.0" to import JPA packages with required JPA version Export-Package should export model package: org.knowhowlab.tips.jpa.model Meta-Persistence: META-INF/persistence.xml is a relative path to persistence description file Import-Package could contain used JDBC driver package (in our case, this is org.apache.derby.jdbc). As an alternative, this package could be imported by client bundle to decouple model from JDBC drivers. Every JPA provider needs minor fine-tuning of the model bundle. Maven profiles were added to meet these requirements:
Listing 2: persistence.xml
<persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"> <persistence-unit name="jpa.students" transaction-type=" RESOURCE_LOCAL"> <class>org.knowhowlab.tips.jpa.model.Student</class> <class>org.knowhowlab.tips.jpa.model.Group</class> <exclude-unlisted-classes>true</exclude-unlisted-classes> </persistence-unit> </persistence>
EclipseLink profile: name: eclipselink run command: mvn clean install -P eclipselink details: add to imported packages: org.eclipse.persistence. indirection add EclipseLink-specific properties to persistence.xml: - javax.persistence.jdbc.driver - database JDBC driver class name - javax.persistence.jdbc.url - database-specific connection URL - eclipselink.ddl-generation - database generation actions - eclipselink.ddl-generation.output-mode - database generation target OpenJPA profile: name: openjpa run command: mvn clean install -P openjpa details: add to imported packages: org.apache.openjpa. enhance,org.apache.openjpa.util enhance model classes with org.apache.openjpa.enhance.PCEnhancer add OpenJPA-specific properties to persistence.xml: - javax.persistence.jdbc.driver database JDBC driver class name - javax.persistence.jdbc.url database-specific connection URL - openjpa.jdbc.SynchronizeMappings run mapping tool to create database Hibernate profile: name: hibernate run command: mvn clean install -P hibernate details: add to imported packages: org.hibernate. proxy,javassist.util.proxy add Hibernate-specific properties to persistence.xml: - hibernate.dialect - database dialect - hibernate.hbm2ddl.auto - database generation mode - hibernate.connection.url - database connection URL
32
Persistence
JPA Service Specification (OSGi Enterprise Specification) describes that EntityManagerFactory service should be registered for every pair: Persistence Unit and Persistence Provider. In the client bundle on every command call we use EntityManagerFactory service instance that is available in OSGi registry (Client code sample Listing 4). The client bundle OSGi configuration is represented below (maven-bundle-plugin configuration Listing 5). The most important OSGi MANIFEST headers are as follows:
Import-Package should contain javax.persistence;version= "1.1.0";jpa="2.0" to import JPA packages with required JPA version Import-Package should contain model package: org.knowhowlab.tips.jpa.model
33
Persistence
</instructions> </configuration>
34
Persistence
vides the integration with the EclipseLink JPA provider to support the OSGi JPA specification approach that clients can use to get JPA support in an OSGi framework. The latest released version 1.0RC1 (25 March 2011) requires JDBC Service Specification (implemented by Gemini DBAccess) to access database and supports only Equinox as OSGi framework. In Listing 6, you can find a list of configuration bundles:
the programming interfaces and lifecycle rules as defined by the JPA 2.0 specification. In accordance with the fact that the Hibernate community does not supply Hibernate engine with OSGi bundle MANIFEST, we have to create it ourselves with maven-bundleplugin using a simpler version of configuration described by Peter Kriens [10] (Listing 8). The other point that we have to achieve is an activation of Hibernate Persistence Provider that will be available for Aries (Listing 9). Listing 10 shows a list of configuration bundles.
Standalone EclipseLink
It is possible to use EclipseLink as a standalone OSGi JPA provider. This solution has been announced as deprecated since version 2.2.0 but it can be used as well, if you do not
35
Persistence
feel like adding any extra libraries to support JPA. One extra header has been added to the model bundle to make Persistence Units available for the following EclipseLink configuration:
JPA-PersistenceUnits: jpa.students
Conclusion
Summing up everything above, I would like to emphasize that the presented tutorial is only a starting point to use JPA in your OSGi environment. Consequently, we can speak about plenty of things that can be added and tested with the provided configurations: JPA provider features (e.g. cache, external transactions etc.), OSGi Enterprise features (e.g. Blueprint, Data Source Factories, JNDI etc.) and support of different databases.
Available configurations: gemini aries-eclipselink aries-openjpa aries-hibernate eclipselink Available OSGi frameworks: equinox felix kf
Dmytro Pishchukhin is a consultant with over a decade extensive experience in Java, JEE, OSGi. He took a part in many OSGi projects for different markets: automotive, telematics, smart-house, train industry. He is a member of open-source projects related to OSGi technologies: www. ops4j.org and www.knowhowlab.org. Dmytro currently resides in Frankfurt am Main, Germany.
OSGi framework/ Configuration Equinox 3.6.2 [11] Felix 3.2.0 [12] Knopflerfish 3.1.0 [13]
Table 1: Test results
Apache Aries 0.3 with OpenJPA 2.1.0 passed passed ClassLoader issues
36
Modularity
37
Modularity
Figure 2: OSGi technology enables modularity and re-use via two complementary mechanisms. Large monolithic applications may be broken into a number of local or remote interconnect OSGi Services. Meanwhile each Service may be comprised of one or more OSGi bundles.
specific functions, without worrying about their internal details. As long as the module boundaries are invariant, the impact of change is localized to each module and prevented from leaking into the wider system. By allowing parallel engineering teams to concurrently work on different modules within the same system, modularity directly facilitates efficiency increases in the development process. The deliverables from each development team can be independently versioned. Finally, as these modules perform a few, or a single function, they are much easier to exhaustively unit test: the working modules then simple assemble into a full application for integration testing. As complexity is an issue at all structural levels, so modularity must be applied at all structural levels [4]. This realization has, sometimes unknowingly, underpinned a number of recent technology trends including: Business Process Management The codification and modularization of business workflow. Service Oriented Architecture (SOA) The move from business systems rigidly coupled with proprietary protocols to services accessed via common protocols. Cloud Computing The decoupling of applications from the underlying compute resources upon which they run; so allowing a more modular runtime environments. Yet in each of the above transformations the underlying application portfolio remains untouched; each a rotting code-base that drives environmental complexity. To directly address environmental complexity one must also embrace application modularity.
An old Idea
The concept of assembling a product from a set of well-defined re-usable components is not new. Indeed its roots can be traced back to at least 250BC with emperor Qin Shi Huang and his commissioning of the Terracotta Army [7]. Whatever the product, the driver for modularity and subsequent assembly is to; increase and maintain quality, reduce cost and increase output. The modern archetype for modularity and assembly is the automotive industry, where extensive use of standardization, modularity and assembly results in the mass production of affordable automobiles.
38
Modularity
and re-factored without affecting their environment; i.e. the local or remote services with which they interoperate. Hence monolithic applications may be broken into a number of Services; each of which may be independently maintained, enhanced and used outside its initial context. Java Modularity OSGi also provides the software industries modularity standard for Java. Each OSGi Service may be comprised of one or more OSGi bundles modules. In this manner, common infrastructure or processing logic code may be encapsulated within a set of commonly used OSGi bundles and re-used across many OSGi Services. By enabling industry standards based modularity, OSGi technology provides the foundations for any business IT transformation program whose primary aim is to reduce environmental complexity and so medium term application total cost of ownership.
and maintenance. Its not necessary to understand the whole system inside-out, each individual can independently work on small well-defined and decoupled modules. This directly translates to increased project delivery success rates; as small, well-contained projects have a higher success rate than larger and more poorly constrained projects. Hence OSGi is a natural technology partner to the agile development techniques adopted in recent years by many organizations. With the appropriate organizational incentives in place to encourage re-use over code creation; further significant efficiencies are realized by cross team re-use of OSGi bundles and services. 4. Product Delivery By embracing modularity, by breaking large monolithic applications into composite applications comprised of a number of independent modules, an organization naturally moves away from high-risk water-fall product release processes towards lower-risk incremental feature releases. 5. Maintenance From an ongoing maintenance perspective it is now possible to re-factor a composite application; a module at a time; reversing design rot, increasing code re-use, and so systematically driving accidental complexity out of each application and so over time, the environment as a whole. 6. Enhanced IT Governance Structural information is no longer locked away within key members of staff, or out of date configurations; rather it is explicitly defined by OSGi metadata. Courtesy of this metadata, the structure of each composite application is known. It is therefore a simple task to answer questions like: Which software licenses are used? Which production applications are at risk from a third party library with an identified security vulnerability? The structure of a composite application may be rapidly mapped by any OSGi literate engineer; this significantly reducing the amount of forensic work needed to decipher and understand an applications code-base: so decreasing operation risk associated with loss of key development personal. Finally, prior versions of an application may be rapidly reconstituted; this offering great value to those organizations that are required to validate the past behavior of a business system to a regulatory authority. 7. Reducing Operational Risk Increasing Business Agility As the internal structure of monolithic applications is poorly understood, upgrades are complex and high risk. This coupled with the long developer diagnostic/fix cycles, results in production outages and instabilities that may spans several working days or even weeks. Operations respond to this challenge by maintaining a number of isolated horizontal production silos; attempting to ensure service availability by releasing new software, one silo at a time: so increasing op-
39
Modularity
erational management, compute hardware and data-center real-estate costs. Yet stability and agility are closely related concerns. The more agile the business service, the easier it is to change from one well-defined state to the next; whether this be to introduce new business functionality, applying a patch, or rolling back to a previously well known functioning state. With an advanced OSGi based runtime, each application is self-describing; meaning the dependencies between versioned modules and dependencies on runtime infrastructure are known. A business system and any associated runtime middleware services may be dynamically deployed in seconds. Subsequent enhancements may be applied and removed just as rapidly: so significantly increasing business agility, decreasing operational risk and operational expense.
no longer bearable), necessity the mother of all invention will drive organizations towards modular, dynamic assembled, applications and so towards OSGi; the industry standard for Java modularity.
Richard is CEO and Founder of Paremus Ltd and is President of the OSGi Alliance. Richard maintains a keen interest in a number of research areas including Recovery Oriented techniques and Self-Organizing and Complex Adaptive System design. He is specifically interested in the application of such concepts to next generation distributed system designs and is an active contributor to the OSGi Alliance RFP 133 on Cloud Computing. Prior to founding Paremus, Richard headed the European System Engineering function for Salomon Smith Barney/Citigroup. Richard graduated from Manchester University with Honors in Physics and went on to gain an Astrophysics doctorate from the Royal Greenwich Observatory.
References
[1] http://www.standishgroup.com/ [2] http://techdistrict.kirkk.com/2010/02/26/osgi-devcon-slides/ [3] http://www.nist.gov/index.html [4] http://techdistrict.kirkk.com/2009/11/03/turtles-and-architecture/ [5] http://www.osgi.org [6] http://bit.ly/16S0uK [7] http://en.wikipedia.org/wiki/Assembly_line
Setting the configuration can be done through a variety of means. Popular tools for setting ConfigAdmin configuration include the Felix file-install bundle (which takes configuration from a .cfg file) and the Felix Web Console. The ConfigurationAdmin API can also be used to integrate with another configuration data system. Some additional notes; ConfigAdmin uses maps to pass configuration data around, which is very flexible. It is pos-
Listing 1
import java.util.Dictionary; import org.osgi.service.cm.ConfigurationException; import org.osgi.service.cm.ManagedService; public class MyManagedService implements ManagedService { public void updated(Dictionary properties) throws ConfigurationException { String serverURL = "http://localhost:7070/server"; // my default if (properties != null) { Object url = properties.get("server.url"); if (url != null) serverURL = url.toString(); } applyMyConfig(serverURL); // configure the system with the data supplied } }
Listing 2
public void start(BundleContext context) throws Exception { ManagedService ms = new MyManagedService(); Dictionary props = new Hashtable(); props.put(Constants.SERVICE_PID, "my.service.pid"); reg = context.registerService(ManagedService.class.getName(), ms, props); }
41
This can be supported very well through a ManagedServiceFactory. This CAS concept allows the creation of multiple entity instances based on similar configuration data. Each instance of configuration data contains the specifics for creating an image in a particular type of cloud. When created and passed to ConfigurationAdmin, it will call a specific ManagedServiceFactory with the config information. The factory knows how to create the cloud image for its specific cloud from the data provided. Once the image has been created, the factory registers a management object which implements a common management interface as an OSGi service. Finally, the client application that manages the cloud instances (checks their status, starts and stops them etc) has no need to know anything about cloud specifics. It operates on the OSGi Services through the common management interface using CAS ManagedServiceFactories to contol multiple cloud images (Figure 1).
Component Models
While the OSGi framework API is relatively simple to use, it is still considered infrastructure that can bleed into the application code of a bundle. The lookup of services, the tracking of their lifecycle and availability quickly become an overwhelming task to be managed correctly and efficiently. Enterprise OSGi, therefore, provides two interoperable Dependency Injection (DI) based component frameworks, Declarative Services and the Blueprint Container. These component frameworks ensure decoupling of the application code from the OSGi APIs. They provide an OSGi bundle programming model with minimal implementation dependencies and virtually no accidental complexity in the Java code. Furthermore, both frameworks elegantly address the issue of long start-up times when many services are instantiated and made available without being needed as well as the resulting increased memory footprint. Managing the component lifecycle by instantiating services on demand and on-the-fly ensures optimal use of resources. Following OSGi best practices, the provider and the clients of a service are implemented by different components. The bundle containing the shared service interface, for the most part, is implemented and contributed as a simple bundle with no lifecycle of its own. Both the provider and the client components will be wired to it by the DI framework. In the following example we have a simple interface:
public interface PrintDate { public String formatDate(Date date); }
sible to restrict the data to a schema by using the Metatype specification. Its also possible to use CAS to configure multiple instances of entities of similar type. For example, take a cloud toolkit that supports managing cloud instances using a common API. It might support managing cloud instances in EC2, Rackspace and Microsoft Azure. Creating cloud images may be highly specific to the cloud vendor. However, once created, the management operations can be abstracted across cloud providers through a common API.
Listing 3
public class SimpleDateFormatterComponent implements PrintDate { public String formatDate(Date date) { if (date != null) { return new SimpleDateFormat().format(date); } return null; } }
Listing 4
public class PrintDateClient { private PrintDate provider; public void setProvider(PrintDate provider) { this.provider = provider; } }
as well as an implementation (Listing 3) and a consumer that has a member and a setter for the component framework to inject the reference(Listing 4). Lets see how this is implemented in DS and Blueprint.
Declarative Services
Declarative Services (DS) is a simple and yet powerful component model. The component implementation, its provided services, and the service references are documented in a XML file that accompanies the project. The schema of the XML file
42
is defined by the OSGi Alliance and the latest version is 1.1.0. The user code is freed of all references to OSGi API and can thereby be tested easily in JUnit and other Java test frameworks (Listing 5). In order to be processed by DS a bundle has to identify itself as a DS contributor by defining the Service-Component header in the bundle manifest.
Service-Component: OSGI-INF/org.example.ds.client.PrintDateClient.xml
Each component is defined in its own XML file listed in the header and it is possible to use the * wildcard to automatically match all XML files in a given folder. By convention the DS component XML files are stored in the OSGI-INF folder of the bundle. Each component description includes the name of the component and the implementing class.
<implementation class="org.example.ds.client.PrintDateClient"/>
Components can provide services, consume services, or both at the same time. The service and reference elements describe the service interface to be used in the registration of the service or in a filter when resolving service dependencies (Listing 6). In DS all component properties are automatically registered as service properties of the registered service unless they are marked as private. Private properties start with a . in the name and are only visible to the component implementation. Using attributes on the reference element for services it is possible to declare the client interest in multiple services of the same type and whether those references are mandatory for the lifecycle of the component or optional.
In this example the cardinality of 1..n indicates that the client is interested in all services matching the filter criteria and it requires at least one to become functional. DS handles dependency management on behalf of the component. By setting the policy attribute in the reference element to static, DS ties the life span of the component to the availability of the reference. If set to dynamic DS tries to find an alternate suitable candidate to remove the reference that has failed. Only if no replacement can be found, the component is deactivated and its services unregistered. By default, DS initiates the lifecycle of components automatically by calling the default constructor. It is possible to provide configuration properties for the instance as well as delaying the instantiation of a component until its registered service is requested by a client. These activation policies are declared as attributes of the component. The component implementation can participate in the activation process by implementing the activate() method. This allows for client bundles to start their processing once all dependencies are satisfied.
public void activate() { System.out.println(this.provider.formatDate(new Date())); }
Listing 5
<?xml version='1.0' encoding='utf-8'?> <scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="org.example.ds.client.PrintDateClient"> <implementation class="org.example.ds.client.PrintDateClient"/> <reference name="provider" interface="org.example.api.PrintDate" bind="setProvider"/> </scr:component>
Listing 6
<reference name="provider" interface="org.example.api.PrintDate" bind="setProvider"/> <service> <provide interface="org.example.api.PrintDate"/> <service>
0..1 1..1 0..n 1..n one or no reference (optional dependency) one reference (mandatory dependency) zero or many references (all available dependencies) one or many references (at least one reference is required)
A similar callback for the deactivation is available by implementing the deactivate() method. DS supports the factory pattern for components by setting the factory attribute on the component declaration. DS then registers a org.osgi.service. component.ComponentFactory service on behalf of the component that allows clients to create new instances with a given configuration. The description of the component and its implementation has to be understood as templates for individual instances. To configure the instances on demand or at startup time, DS integrates very tightly with the Configuration Admin Service (CAS). Components are typically configured with static property defaults in the component XML file. In order to support more dynamic configurations, DS uses the name of the component as a PID to obtain a configuration from CAS, see Configuration Admin Service. The configuration-policy attribute of the component element controls the configuration policy used by DS. If set to ignore, the configuration is not obtained from CAS. Setting the value to require makes it mandatory for a PID to be available from CAS and optional will use the configuration from CAS when it is available.
Blueprint Container
The Blueprint Container specification is based on the popular Spring framework and the work that was done by the Spring Dynamic Modules project to integrate it with OSGi. The definition of components as beans will look very familiar to those with experience in Spring. There are now multiple open and closed source implementations available, namely Eclipse Gemini, Apache Aries, and Virgo from SpringSource (VMWare).
43
DS and the Blueprint framework are very similar. The most obvious similarity is the use of XML files to describe the components, their lifecycle, and their interactions among each other and with the OSGi framework. Youll find an Example Blueprint definition file in Listing 7. DS is very efficient and meant for lightweight components with focus on startup times and memory footprint, Blueprint is more focused on enterprise applications demanding a high degree of flexibility and extensibility. Components in Blueprint are referred to as beans. In its simplest form a bean definition contains an id and an implementation class.
<bean id="client" class="org.example.bp.client.PrintDateClient"/>
DS and Blueprint both provide the ability to have multiple instances of a declared reference injected. The Blueprint declaration
<reference-list id="providers" interface="org.example.api.PrintDate"/>
This simple example assumes the presence of a public default constructor. Blueprint does, however, support the passing of static properties as well as references to other beans and other non standard constructors. Similar to DS, beans are defined in one or more XML files inside of a bundle. The bundle has to indicate its support for Blueprint by providing the Bundle-Blueprint header in the manifest file.
Bundle-Blueprint: OSGI-INF/org.example.bp.client.xml
expects the bean to take a List<org.example.api.PrintDate> as the argument for the setter. The list is automatically updated with available references. In DS the same was declared using the cardinality attribute on the reference element. Like DS, Blueprint differentiates between mandatory and optional dependencies, which has an impact on the lifecycle of the bean and its availability to others. Of course, Blueprint beans can implement and export services to the OSGi service registry.
<service id="providersvc" interface="org.example.api.Printdate" ref="provider"/>
The value of the header may point to individual definition files or to directories inside the bundle. It may also use the * wildcard character to match multiple files in a single location. The definition of a single component in Blueprint may span across multiple definition files. This allows for clearer separation of concerns and modularity in the definition itself. Bundle fragments may also contribute bean definitions and can be reused among multiple components. In DS fragments can contribute component definitions but they have to be complete as they cannot span multiple files. In Blueprint references and services are defined separately from the bean implementation declaration. This allows for service references to be declared once and reused multiple times by one or multiple beans.
<reference id="provider" interface="org.example.api.PrintDate"/>
A client declares a private member provider of the type org. example.api.PrintDate together with a public setter for Blueprint to call with the referenced object.
Listing 7
<?xml version="1.0" encoding="UTF-8"?> <blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"> <bean id="myid" class="org.example.bp.MyClass" /> <service id="srvc" interface="org.example.api.PrintDate" ref="myid"/> </blueprint>
The registered service can be augmented with properties that can then be used in filters specified in the reference element. Instead of listing interfaces individually, Blueprint can introspect the implementation and select the service interfaces automatically from the implementation. The properties of the service registration can be individually configured, which was not possible in DS where all public properties are part of the registration automatically. In general, Blueprint beans are instantiated when all mandatory references are satisfied and they are referenced by other beans or their service is requested. Services provided by beans become available to others once a bean has been initialized. As soon as mandatory dependencies are no longer satisfied the services of a bean becomes unavailable. Blueprint has many configuration options to customize the initialization and dependency management. This includes, among others, the ability to immediately instantiate beans on startup or delay their creation as well as customizing the callbacks for lifecycle and dependency injection handling. Among the significant differences between Blueprint and Declarative Services is the overall availabilty and lifecycle of components that have declared their dependencies to be managed by a component framework. In DS, components become available and unavailable as soon as their dependencies are satisfied or unsatisfied. This may lead to component thrashing in larger configurations, where objects are created and destroyed in high frequency. Blueprint, on the other hand, uses dynamic proxies that are injected into beans. The proxies are able to cope with the temporary unavailability of services by blocking the calling thread for a configurable amount of time until a replacement is found. After the timeout has expired, the proxy will throw a org.osgi.framework.ServiceUnavailableException for the client to handle. However, neither the proxy nor the bean will need to be destroyed unnecessarily.
44
The use of dynamic proxies implies that a service has to implement an interface and cannot be a simple class. This is different from DS, where services can be provided by classes without implementing an interface.
Jasper project to compile .jsp files into Java servlets on demand. The simplicity of the programming model makes the HTTP Service very appealing for simple projects already implemented in OSGi. However, the service interface lacks support for common features like servlet and context listeners. The current version has support for the Java Servlet Specification in version 2.1. Web Applications Specification Most features that are missing in the HTTP Service Specification are provided by the Web Application Specification, which in its current release supports the Java Servlet Specification 2.5 and Java Server Pages Specification 2.1. It is fair to say that the vast majority of Java based enterprise applications are written as Java EE web applications and packaged as war files. To ease the adoption and integration with OSGi the Web Applications Specification defines a standard way of taking an existing war file and converting it into an OSGi bundle to be used in the framework on-the-fly. Provided you have deployed a compliant web container implementation in your framework, simply install a bundle from a URL that starts with webbundle:. The web container implementation registers a URL Handler that understands the protocol and performs the conversion into a bundle during the installation. Every bundle requires a set of mandatory headers, like Bundle-SymbolicName and Bundle-Version and these may not always be available in the war file. Therefore, it is possible to pass the header values in the URL used for installation.
webbundle:file:///wars/myapp.war?Bundle-SymbolicName=com.example
The first argument registers the content under the /files context path and the second argument points to the location of the resource, in this case the root of the bundle. It is also possible to point to a folder in the file system here. Registering a servlet is very similar:
svc.registerServlet(/path, myServlet, initparams, null);
The headers are passed in the URL query part separated by &. The installation turns the war file into a OSGi Web Application Bundle (WAB). A WAB is differentiated from other bundles by the presence of the Web-ContextPath header.
Web-ContextPath: /path/to/my/app
Here the servlet is mapped to the /path context path. The initparams argument is a java.util.Dictionary with configuration parameters for the servlet. The last argument for both calls is a org.osgi.http.HttpContext object. The HTTPService provides the createDefaultHttpContext method to obtain the default implementation, passing null has the service pick the default. The user can implement the HttpContext in order to support authentication and more advanced resource mapping. In order for two servlets to share the same ServletContext, they have to pass the same HttpContext object in the registerServlet call. Java Server Pages are a very popular technology and can be registered using a proxy servlet like the one provided by the
The OSGi Web container implementation is implemented as an extender that automatically discovers and registers web applications found in WABs. A WAB may contain an optional web.xml file located at WEB-INF/web.xml. The web.xml file is interpreted the same way as is defined by Java EE. Like other bundles WABs have import-package and exportpackage headers that wire the implementation to other bun-
Listing 8
ServiceReference ref = ctx.getServiceReference(HttpService.class.getName()); if (ref != null) { HttpService svc = (HttpService) ctx.getService(ref); if (svc != null) { // register resources and servlets } }
45
dles. The Bundle-Classpath header has to contain the entries for WEB-INF/classes and all jars in WEB-INF/lib. It may also include further resources available in the WAB. While the installation of an existing war file is the easiest way, the full potential for web applications is only achieved when the application is implemented as a WAB from the ground up and makes use of the module, lifecycle, and service layers of OSGi. By referencing packages from other bundles, web applications can significantly reduce their memory footprint. Using the service registry it becomes very easy to contribute content to the web application from other bundles. The Web Application Specification provides servlets access to the bundle context by setting the osgi-bundlecontext property in the ServletContext.
BundleContext ctxt = (BundleContext) servletContext.getAttribute ("osgi-bundlecontext");
Web container implementations support JSP pages in the web.xml as defined by .jsp extension mappings or using the jsp-group element. It may optionally support Servlet annotations defined by JSR 250 Common Annotations for the Java Platform. In that case it will scan the implementation classes for support of annotations unless the metadata-complete attribute on the web-app element in the web.xml file is set true. If annotations are used, the WAB has to import the appropriate packages.
mind. This is especially true for Java EE Naming clients that use the JRE provided javax.naming.InitialContext to obtain a context for their application and use it for lookup of resources. The mechanism by which implementations of the JNDI context are provided is not very suitable for modular environments with different class loaders per bundle. The lookup mechanism of JNDI is also very rigid and not as dynamic as the OSGi service layer. The Enterprise Specification describes how OSGi aware clients can obtain a javax.naming.Context object from a org.osgi. service.jndi.JNDIContextManager service instead of using the static javax.naming.InitialContext class. The static javax. naming.NamingManager.getObjectInstance() mechanism is replaced by a call to a org.osgi.service.jndi.JNDIProviderAdmin service. Multiple implementations of context and Object factories can be dynamically installed and updated. To support existing non-OSGi aware clients compliant implementations provide a compatibility layer that sets the JDNIInitialContextFactoryBuilder and the ObjectFactoryBuilder singletons in the JRE such that it uses the BundleContext of the client bundle to obtain a reference to the JNDIContextManager service to obtain the appropriate JNDI context.
Remote Services
OSGi Services provide a Service Oriented Architecture within the OSGi framework. Unlike many other service frameworks (such as Spring or java.util.ServiceLoader), OSGi Services are dynamic. They can come and go at any time. Besides, Service registrations can hold arbitrary properties which make it possible to select Services from a larger set based on servicespecific metadata. While ordinary OSGi Services operate within the JVM, the OSGi Remote Services specification takes the OSGi Service concept across machine boundaries. This makes it possible to invoke remote entities through the Service programming model. For example, take a Display Service. This Service represents electronic traffic warning displays. A controller might address displays by road number and direction or zip code. Each road sign registers a Remote Service to access its display. The example Service has the following API:
public interface DisplayService { String getText(); void setText(String text); }
A controller doesnt always need to know the exact displays to set, in some cases blanket messages need to be set on all displays in a certain area, for instance with a given post code, like a weather warning. OSGi Remote Services is an excellent technology to realize this functionality. It makes OSGi Services available through the network by adding some extra properties, the main one being service.exported.interfaces. When this property is set to * all the interfaces registered for the Service are made available remotely. When a Remote Services-compliant discovery system is used the Service is registered with this discovery system which allows Remote Service consumers to find
46
Figure 2
Figure 3
Figure 4
the Service without having to know where they are located beforehand. To set a message for an area, the controller selects the displays by zip code and sets the message accordingly across all relevant displays. Heres how three displays could register themselves as Remote Services (Figure 2, 3 and 4). The Service consumer doesnt need to pass any special properties to select Remote Services. Depending on the configured discovery system these will automatically appear on demand in the local Service Registry.
So a road-side display controller application could use an org.osgi.util.tracker. ServiceTracker or a Service Injection framework such as Declarative Services or Blueprint to look up the required Services using an LDAP filter like this one: (&(objectClass= DisplayService) (zipcode=95054)) and set the value Warning: widespread fog on all Services found. Since the integration of Remote Services is done through the OSGi Service Registry they work with any framework that works with the OSGi Service Registry. The Remote Services specification doesn't describe the network protocol and data binding to be used for the remote communication. A wide variety of options is available such as REST, SOAP/HTTP, plain sockets or RMI. This is entirely up to the implementation. However if a standard is used for the networking layer, it opens up the possibility to access the Remote Service from non-OSGi consumers.
47
The essence of the Event Admin service is very simple. A bundle can generate events and other bundles can register themselves to consume these events. Events are published on topics; essentially /-separated paths. An event can hold a map of arbitrary properties as data. For
example to create a trade event for an imaginary trade system, you could use the following code in Listing 9. Event consumers are registered with the Event Admin service under the topic paths they wish to receive events for. My event handler may look like in Listing 10. To receive events, I register this handler with the OSGi Service Registry (Listing 11). In this example my handler receives callbacks for the acmeand foobar stocks. I can also use a wildcard at the end of the topic path in the handler registration. For example registering a handler under stock/us/nasdaq/* instructs Event Admin to send all Nasdaq stock events to the handler. It's also possible to filter out events on additional event properties, for instance to limit events received to ones that relate to large trades only.
JMX Support
The JMX specification enables control of the framework through JMX. Framework operations such as installing, starting, stopping, updating and uninstalling a bundle are supported as well as query operations for Bundles and Services. Additionally, the JMX specification provides access to functionality from StartLevel and PackageAdmin. A small number of compendium services are also supported through JMX, such as CAS. A screenshot can be found in figure 6 of OSGi JMX support in the JBoss AS7 OSGi Framework via Jconsole.
Listing 9
Map<String, Object> trade = new HashMap<String, Object>(); trade.put("CURRENCY", "USD"); trade.put("PRICE", 1742); trade.put("AMOUNT", 1000); Event event = new Event("stock/us/nasdaq/acme", trade); EventAdmin eventAdmin = ... // obtain Event Admin Service... eventAdmin.postEvent(event);
Listing 10
public class MyEventHandler implements EventHandler { public void handleEvent(Event event) { // process the event updateChart(event.getTopic(), event.getProperty("PRICE")); } }
David Bosschaert works for JBoss at Red Hat. He has been developing software since 1983 and coding Java since 1997. He spends most of his time on Open Source OSGi projects such as the JBoss OSGi Framework and Apache Aries and is also one of the OSGi Enterprise Expert Group co-chairs. You can reach him at [email protected] Tim is working at TIBCO Software Inc. as a Sr. Architect. He is responsible for theOSGi based runtime platform of the ActiveMatrix product suite. Previously, he was working for Siemens Communications as Principal Engineer, where he was also in charge of the OSGi based runtime platform. In the OSGi Alliance, Tim serves as the co-chair of the Enterprise Expert Group since its inception in November 2006. Tim holds a MS in Computer Science from University of Kaiserslautern, Germany.
Listing 11
EventHandler handler = new MyEventHandler(); Dictionary props = new Hashtable(); props.put(EventConstants.EVENT_TOPIC, new String [] { "stock/us/nasdaq/acme", "stock/us/nasdaq/foobar" }); bundleContext.registerService(EventHandler.class.getName(), handler, props);
References
[1] Where can I get an implementation of an OSGi spec? A list of all OSGi technologies and where to get them can be found here: http://en.wikipedia.org/ wiki/OSGi_Specification_Implementations [2] Find the latest OSGi specifications here: http://www.osgi.org/Specifications [3] Acknowledgements: clip art: openclipart.org [4] Traffic sign generator: http://www.customsigngenerator.com/digital.asp
48