Saturday, April 29, 2006

OSGi Design Technique

Details are important when you are responsible for writing a spec. You are the one to get blamed when one of the myriad of details is ambiguous, or god forbid, forgotten. This focus on details sometimes makes me forget how important the high level view is. The details can be perfected, but if it is not useable in real systems, we have a serious problem. I therefore want to discuss some higher level design issues that come up once you have decided to develop your next project on top of an OSGi Service Platform.

Where do you start with design? What are good OSGi based designs? Obviously, most criteria for good design are shared with non-OSGi based systems. However, the OSGi Framework provides an environment for components. Designing with components is clearly not yet mainstream and there are few established rules. So let me give you my 2cts worth.

What is a component? An OSGi component is a dynamically deployable unit that provides a function through a set of services, which are defined by a Java interface. For example, an OSGi Log component would be implemented in a bundle, its packaging, which could potentially contain other components. If this bundle is started it provides a Log Service and a Log Reader Service to the world. Other bundles can get these services and use them as they see fit. From a design point of view we can therefore treat the component as a black box with ports (the services) for the communication.

I know there are today standard module and interface symbols in UML but I never got the hang of them (I really tried!). They happen to be the most complicated symbols in UML, while a component design uses them almost exclusively. Also, the dynamic nature of OSGi services is very difficult to represent with UML. Trying to use UML for what belongs to the primitives of an OSGi Framework tends to clutter the picture. I therefore usually use a circle for a bundle and a triangle for a service. The service can be used in 3 different ways by a bundle, and this needs to be depicted:

1. Consumer – The bundle that gets the service is the consumer. The arrow from the bundle attaches to the horizontal or vertical line on a service triangle. An OSGi service can be consumed many times by any bundle. Many bundles can therefore connect to the horizontal or vertical line of the triangle.
2. Implementer – The bundle that implements the service must register it. This is depicted by drawing a line to a corner of the triangle. An OSGi service can be registered many times by the same or different bundles.
3. Listener – A listener bundle connects to one of the angled lines of the triangle. A listener is notified of registrations, modifications and unregistrations of the service. A service can have many listeners.




A service is identified by its interface. The service can be seen as a joint or flexpoint in the system. It decouples bundles from each other and decoupling is something you have to pay a lot of attention to! This decoupling is achieved because all three involved dependencies are directed towards the service. None of the bundles has a dependency on any of the other bundles. I might bore you, but I can not stress enough how important this concept is!

So where do you need these joints in the system? Well, the simple answer is: everywhere you want to decouple, which should be in a lot of places. The trick is to put a service whenever you can break the coupling between bundles.

Services are obvious for big functions like a log service, a configuration admin service, and, for example, the permission admin service. These types of services are similar to what you would get from JNDI or interfaces that would be injected with systems like Spring. These types of services are used to wire the application to providers of specific types of function blocks. Normally, the dependency on these services is static because the bundle can not operate without the presence of these function blocks.

Services are also applicable when you dynamically need instances of a specific type, but you could not care less how they are implemented. An example of this class is the archetypical OSGi scenario of controlling lights. You would not believe how many home automation protocols exist, and each protocol has its own cumbersome and particular way to control a light. The service registry was developed with this use case very much in mind. Different bundles could register a “Light” service, mapping the interface semantics to different protocols. The bundle that needed to control the lights no longer has to worry about trivial details like bits and protocols; it could just get the Light services and play with them as it sees fit, oblivious of implementation details. This pattern translates well to Bluetooth devices, available database servers, available printers, legacy system connections, etc. This pattern very clearly elucidates why OSGi services are dynamic.

Another class of services is the listeners. After release 1 we realized that we could seriously simplify applications when we used the whiteboard pattern. The whiteboard pattern is an example of inversion of control (IoC). That is: “Do not call us, we will call you”. If you need something from the world or have something useful functionality to offer to the world, register a service and wait till somebody calls you. The basic approach of the whiteboard pattern is to announce what you have, but in no way try to control the usage. You provide, but you do not control. Today there are many standard OSGi services that use this pattern: Event Admin, for example, will send its events to any service that registers itself as an Event Handler. The Event Handler uses properties to select the events it is interested in, preventing unnecessary callbacks. This is an extremely successful model, albeit many programmers have a hard time getting used to the loss of control that they feel.

The best litmus test for a service is: “Do I decrease coupling”? If I put a service here, do we need less people to decide upon its interface then when I put it there? If you can minimize interactions between bundles (implementations) you are moving in the right direction. The reason that you want to minimize the coupling is because this usually directly translates to development cost. Trying to agree on interfaces between 10 parties is a lot harder than agreeing between 2 parties. Later phases are also more complex when more coupling is present. For example, testing decoupled components is so much easier than components that are coupled to the kitchen sink as well as to the coffee maker.

At first this way of designing is cumbersome, you have the feeling you create lots of interfaces and do not do anything really productive like writing code. However, hours spent selecting those interfaces are probably your most productive hours of the entire project. Do not hesitate to throw designs and start over from scratch. For one customer, I found almost 200 deliverables (bundles, OSGi services, or external interfaces). This large number explained why they had had so much problem progressing with the development of the system. Doing this analysis gave them an insight in the complexity for the first time. A part of that system is shown in the following picture (the parallelograms are web services). Though I can not show the details due to confidentiality agreements (the fuzziness is on purpose), it shows the extensive use of services and bundles.





After you have done this work, the next step is to develop the service interfaces. This is frustrating work! It usually involves hard negotiations between different parties at the time that most participants have not much of a clue yet. So assume you won’t get it right the first time. However, do not worry about it too much because it will need iterations anyway. Your gain is that you minimized the parties involved in a discussion because you minimized coupling. Most of the time, a service interface is owned by a small group or even a person, and used by other groups or persons. If you did the design right, you should have found the minimum number of interactions. So yes, it will be a lot of work but at least it will be the minimal amount of work.

A key advantage with this model is that you now have a relatively stable set of services and that all involved parties can start coding against these interfaces, and even compile. For larger projects it is worth the effort to develop test stubs early in the process. This will allow the users of the interfaces to test their code as well. If you can get the group(s) responsible for implementing these key services to write them, you will notice that they usually modify them in this process because they learn a lot from this experience.

The next phase is implementing the bundles. This is usually the longest part because it means getting things to work really. Do not hesitate to refactor the service interfaces when you learn the original design was flawed. Developing software is in a large part a discovery process, refactoring is inherent in the fact that your insights change. If you had followed the guidelines and had minimized the overall decoupling of the system, refactoring of the interfaces should be straightforward. Never hesitate to improve the service interfaces if you see a possibility where you can do better. You might save a few days by ignoring these improvements but you will pay much more later if you ignore those improvements.

A well designed component system will notice that interactions between groups are significantly less and more focused on specific service interfaces than monolithic designs. Obviously, this directly translates in development dollars.

The only caveat I know is the surprise that comes at integration time when you do not prepare early for that surprise. Unconstrained, bundle programmers will happily code away and implement the requested functionality in the best way they can. However, what they can not see is how their components will work when put together with 200 other components. A typical example is the initialization time. Bundle programmers will not notice a 2 second initialization time because they do a simple DNS lookup in the Bundle Activator. However, multiplying this with 200 will not put a smile on your manager’s face: 400 seconds is still six and a half minute. If this happens a day before the navigation system needs to be delivered, it will be sufficient time to walk to your desk and pack your belongings. Therefore, a component design requires early integration and lots of later integrations. This is the only way to find bottlenecks early on.

Hmm, maybe this subject is a bit too much for a blog, I do not think I ever got to page 5 before. However, this subject needs more attention because designing with services for an OSGi service platform is different than writing a normal Java application. Let me know if you think this is useful or if I should stick to the details from now on …

Peter Kriens

Monday, April 24, 2006

maven

This weekend Richard S. Hall and his wife Ya-Ching visited us. We picked them up from Nîmes train station after which we had an original French lunch under the city trees. I am pretty sure not enough of this was spent on Richard and me because obviously we had a lot to discuss. To my shame I must admit we probably bored our partners to death with our lingo. Fortunately my wife is hardened after watching me talk shop for over 26 years with hundreds of technical guests.

Though we had lots of subjects we wanted to discuss, it often turned back to Richard pressuring me to become an Apache Felix committer (Ok, I wore my Eclipse committer shirt). So during the weekend we download the Apache Felix source code on my disk. The first hurdle was maven, so far I resisted maven because ant, its predecessor, has always left me with a bad taste in my mouth. However, Apache projects are more or less forced to use maven because it provides an interesting shared repository model, which is obviously crucial for an organization like Apache. Unfortunately, the repository architecture is based on simple hard references instead of the more powerful capability/requirement model of the OSGi bundle repository.

The interesting approach of maven is that it does not try to be a scripting language (which ant tried) but that it works with a declarative model. Project rules are defined in a central place shared between different products while products only declare information. This looks very familiar to me because that is how I always used make (and also later when I was forced to use ant). Redundancy is the root of all software evil, and most ant files I have seen are so redundant because of their copy-paste history that they put Lucifer to shame. Maven addresses this issue by rigidly specifying a project directory structure, which is excellent.

In Maven, each deliverable needs a pom file. A pom file is, you guessed right, an XML file. How anybody can use XML for a human writeable/readable format escapes me, but it has taken epidemic forms. Not sure it is caused by CS students not reading the Dragon Book, or that there are too few CS students writing open source software? Anyway that was enough ranting. The pom file describes the unique facts of your deliverable and its dependencies. Maven reads the pom file and provides this information to the overall shared rule set that then builds your product accordingly.

A crucial aspect of maven is dependency handling. The pom file refers to dependent JARs by a symbolic name. A URL based repository is used to retrieve those dependencies automatically when needed. This works fairly well though I had some troubles operating offline (and the dependency set is amazingly large, I think it downloaded the whole of Apache, though we might have missed Geronimo).

Maven provides a plugin model for special actions. Plugins are activated from the pom file and can access the information in the pom file. Enrique Rodriguez created a special Maven-OSGi plugin that handles the OSGi required manifest entries. When we looked to this I noted that the pom files also contained the import package clauses. This is of course a maintenance nightmare because they depend on the actual code. I recently had written a certifier that basically contains all the required code to calculate the imports, and much more. So I indicated to Richard that it would be a couple of hours work to automatically generate this information. The advantage of Java class files is that they contain so much information.

This sounded like fun so we added the imports. This turned out to be so easy that we decided to do some extra checking. We verified the export statement, we detected bundle activators and allowed them to be automatically set, and we added the hard to write yourself “uses” directive on an export. Obviously we took care to be backward compatible, if you specified the header in the pom file, we verified it. Otherwise we generated it. This is all pretty complex stuff but it went amazingly smooth. I have released the code to Felix so now the Felix community must take a look and see if it fulfils their needs and quality requirements. I guess that is going to be the hard work.

Doing this was just a fun exercise; I always enjoy doing these joint exercises because you learn so much working with someone else. Explaining to our partners that this is more fun than enjoying the sunny weather with them was the hard part.

Peter Kriens

P.S. The OSGi Alliance has a public webinar the Thursday 27th of April. Please join us for information about the new membership class, plans, and the possibility to ask the questions about the OSGi Alliance you were always afraid to ask.

P.P.S. For JavaOne I am still looking for 2-4 slide presentations.

Wednesday, April 19, 2006

OSGi and Navigation

One of the most exciting devices I know is a navigation system. I can still feel the awe for this technology despite understanding mostly how it works. It has something uncanny when you follow the instructions of a computer voice you end up right on the exact doorstep. It is amazing. Trying to explain how it works to people usually shows that most people think that the GPS satellites know exactly where you are. It makes you wonder how much people really worry about privacy invasion …

Navigation systems can exemplify why OSGi is important. Currently, all navigation systems that I know are closed boxes. The vendor provides a fixed set of functionality and that is it. However, this means that the navigation system works for the common tasks but not for more specialized tasks. The navigation system vendor has neither the money nor the knowledge to address an almost infinite need of requirements in the real world. These specialized tasks might address a smaller audience than the general tasks, however, the margins in addressing these smaller markets are usually much higher.

This is therefore a perfect example why these systems should have an OSGi Framework and a standardized interface to the navigation system. Allowing third parties to integrate seamlessly with a navigation systems enables third parties to build applications on top of it. Did you ever look at Google Maps? For example, a housing application, earthquakes, or even a game. This creativity and market opportunities are released because Google provides the access to the maps and other “details” while the developer can focus on his specialty. This model is obviously very successful for both parties. In this case Google gets to sell advertisements and the site gets some interesting new functionality.

This exact model is also possible with embedded devices. The only difference is that the vendor can make his profit more easily by selling the device and add-ons. For example, a real estate agent needs to drive a route when she shows a customer potential properties. A plain off the shelf navigation systems is awkward because then she must fill in all the addresses. A small bundle could make a world of difference. It could obtain the addresses from a database, convert them to the navigation system, create the route and provide all the details of the properties when the car approaches. This can seriously reduce the amount of work for the real estate agent, meaning she is willing to pay real money for such a service.

There are many more similar scenarios:
  • Games using real world maps and positioning (maybe not such a good idea in a driving car)

  • Destinations that move. For example navigating to a person, querying the position and then navigating to that person wherever he is.

  • Traffic alerts

  • Showing the position of other people

  • Taxis, receiving the route from the dispatcher

  • And so much more …
So why aren’t there any navigation systems that have an OSGi environment? Well, actually there are, the BMWs 7 series has one and some others are in the works. Siemens VDO has been very instrumental in driving this direction. However, none of these systems accept foreign bundles; they use the OSGi architecture to simplify their own development process.

The key reason is of course fear for the future. There are some scary aspects in allowing other parties to use your device. You need more memory and a bigger CPU, which could be prohibitive in a highly competitive market. However, costs are never a problem when the user gets a significant advantage, unfortunately, he first has to see this advantage before believing it. Fortunately there are two trends that will make this feasible soon. Navigation systems are becoming commodities, which will make the vendors look for features, and the price of memory and CPUs is dropping faster and faster.

Another problem currently is that there is no standard API to manage the navigation system from another bundle. The reason that I wrote this blog because I started working on a Navigation Model Service for the OSGi Alliance which made me realize how much you could do with this API. And best of all, once there is a standard API, you might even run these navigation applications in your car as well as in your new OSGi Mobile Platform phone.

Peter Kriens

Monday, April 17, 2006

A Strong Lesson About Modularity

Last week I learned a strong lesson about modularity: “Investigate before you take the easy route”. It started with a problem on the Felix mailing list. A Felix user had experienced Class Not Found exceptions for a Swing class that he did not use at all. Inspecting his code, there was no sign of him using that Swing class; the only reference was to a class that used the culprit as super class. The OSGi specifications only mandate the imports of classes you directly use.

The suspicion quickly turned to the boot class path. Normally, a VM uses hierarchical delegation. If a class loader gets a request for a class, it should first ask its parent loader, which should ask its parent, etc. The VM’s loader is at the root. This is a simple delegation policy with flaws (but that is another story).

However, the OSGi specifications forbid the delegation to the parent except for java.* packages. Why? We had found that bundles did not import packages they expected to be on the boot class path. This made it impossible to replace or add those packages by other bundles because the other bundles were never consulted; the request was delegated to the boot class before the package lookup was done.

Substitutability is one of the best features that an OSGi framework brings along, it was therefore clear that we had to deny the automatic parent lookup. This requires frameworks to export any packages that are on the boot class path.

However, unfortunately there is code delivered with the Java VM that implicitly assumes the parent delegation model. When it needs to load a class it uses whatever class loader is at hand, assuming that in the end the boot class path loader is used and the class is found in the end. It should be clear from the previous description that this is not true for an OSGi framework, causing seemingly random failures in bundles. In a previous version of Java there was a VM bug in the verifier that used the wrong class loader, breaking the modularity, which did not help as well. For pragmatic reasons we therefore added the org.osgi.framework.bootdelegation (Section 3.8.3) property. This property is a list of packages that requires delegation to the boot class path, bypassing the controlled class loading mechanism.

Ok, back to the original problem. As you can understand, we thought that the Class Not Found exception was caused by a VM bug or by some class that used the wrong class loader. The standard solution to these problems is adding the package to the org.osgi.framework.bootdelegation, and be done with it. The list showed some pressure to Richard Hall, the main Felix core committer. However, he was stubborn. His solution was to add the missing package to the imports of the bundle. I was against this solution because if this was caused by the VM bug, the standard boot class path delegation was the solution. Problems should be fixed at the right place, fixing a symptom is bound to bite you later.

Other people joined the discussion and we found out that one framework vendor had default set the org.osgi.framework.bootdelegation to *, which basically means the old parent delegation model. This is ok for a deployment but it is bad during development. A * for boot delegation effectively hides any import problems. This was Richard’s greatest objection, delegating everything to the boot class path would not allow you to find class path problems until you were in the field.

During the discussion I was getting the uneasy feeling we had screwed up in the specification if these types of problems were popping up. So I asked Richard to send me the offending bundles. Assuming this was a VM bug, I tried to create a smaller problem with the same sequence. However, I could not get it to fail. I therefore decided to recreate the bundle using my own build environment. This environment uses BTool which analyzes the bundles and write the manifest. To my surprise, BTool created an import statement for the class that generated the error; the code must therefore refer to the class despite the fact it was not directly using it. I immediately realized how stupid I was; this was the same bug we had had last year and that I had solved by extending BTool. I had been sidetracked by the VM bug and boot class path delegation discussion!

Last year I had analyzed that the compiler can insert a reference to a superclass if a method of the superclass is used on a subclass. For example, of you use the HttpServlet class and you refer to for example getServletInfo, the compiler will insert a reference to the GenericServlet class, even though you do not import this in your source file.

So what did I learn from this exercise? First, Richard was right on two counts. He resisted the pressure to make boot class path delegation default * and he was right (for the wrong reason!) to import the culprit class in the bundle. After this exercise, he decided to improve Felix by analyzing Class Not Found exceptions and provide a clear message how to solve them.

However, the most important lesson I learned is that we need a simple tool to verify a bundle. In my sparse spare time I started to write a simple certifier. It is still in its infancy, but I already find lots of errors in freely available bundles. Nevertheless it might be useful so you are free to download the jar (or exe) it and use it. Just run it with:

java –jar certifier.jar (filedir)…

Please note that this is not an official OSGi bundle and has no official status, use it at your own risk.

I’ll probably make some updates in the coming weeks. Feedback appreciated!

Peter Kriens

Friday, April 7, 2006

The Bundle Repository

First, if you go to JavaOne, get your calendar and not the following information:

  • Wednesday, May 17 10:30 PM 50 Franciscan II & IIIComponent Programming with OSGi

  • Thursday, May 18, 08:30 PM 50 Esplanade 304/306The OSGi Service Architecture, From Embedded to Enterprise

I sure hope to see you there! While we are at it, the OSGi Alliance organizes a webinar. This webinar will take place at Thursday, April 20, 2006, 9:30 AM - 11:00 AM US Eastern time. The webinar will provide updates on: Plans for upcoming and future OSGi technology releases, OSGi technology with JSR 291, Dynamic Component Support for Java™ SE, Expanding OSGi Alliance participation: new Adopter Associates class of membership, and OSGi Alliance leveraging of open source.

Time for the real stuff! The OSGi Alliance has been working on a Bundle Repository for the last few months. A bundle repository is a natural extension to the OSGi Alliance because they want to promote a bundle market. Markets perform best when they are transparent; a searchable repository provides for this transparency. A bundle repository is not a new idea; Richard S. Hall pioneered a repository with his Oscar Bundle Repository (OBR). OBR was an XML based federated repository combined with a tool that could run on any Framework. The tool made it very easy to manage a framework installation from within the framework itself. Richard has helped us develop the version we are introducing today. He is also working inside Apache Felix to make a compatible bundle repository application.

The most visible part of the repository is the web based interface. You can search for bundles, which are then presented in a list. You can select a number of bundles and resolve these bundles. Resolving the bundles means that their dependencies are used to find other bundles that can resolve those dependencies. This will give you a nice list of bundles that you can download and install. When you hover over the link of a bundle, you see the description. Clicking on the link gives more detailed information. This window also contains comments and if you wish, you can add new comments. The web based interface enables you to brows the repository at your leisure. Richard Hall will soon make an updated version of OBR available that uses this repository.

From a technical point of view I think the repository is quite interesting. We have used a very generic capability-requirements model. This model is partly derived from JSR 124: J2EETM Client Provisioning Specification but is simpler and more powerful. Each bundle (resource as we call it, we can also handle other things than bundles) has a set of capabilities (property sets) and requirements, which are extended OSGi filters. A resource has a set of mandatory or optional requirements. Requirements can require a single instance out of many, or it can actually use many. The Bundle Repository is not an OSGi standard specification; it is only a utility provided by the OSGi Alliance. However, we have described the format and requirements in an RFC that is publicly available. This RFC also contains an API to access a repository locally. Richard Hall’s OBR tool will use this API (which, again, is not part of the OSGi specifications).

Currently the repository contains over 700 bundles from ProSyst, Eclipse, the old Oscar repository, and some of mine. The goal of this repository is to become the central clearing house for bundles. We are therefore very interested in parties that are willing to become part of the OSGi Bundle Repository. Participating is rather easy; you will have to host a repository.xml file and your bundles on any host. Creation of this XML can be done in several ways. The hardest way is to hand code it, I do not recommend that approach. You can write your own program to generate the file, however, we have also written a generic one for you. The bindex utility is a small Java program that can traverse a directory and generate the repository.xml file from the manifest in the bundles. If your manifest is nicely formatted (description, license, etc) then you get a very expressive repository file. You can send the URL for this repository to me. After we verified that you are a legitimate company or person we will add this to our main repository.

As a note, the repository and the web based interface are hosted on an OSGi Framework running on bundles.osgi.org, we are surely eating our own dog food. The software has been written from scratch. I am very interested in feedback around this repository. Please send me your ideas of how to extend the repository, or to get rid of the inevitable bugs. You can use our bugzilla or you can mail me.

Enjoy!

Peter Kriens

Monday, April 3, 2006

Misconceptions about OSGi Headers

This week there was an interesting discussion on a mailing list that showed a number of misconceptions about the difference between importing a package (Import-Package) or importing a Bundle (Require Bundle). This is a complicated and subtle area so the misconceptions are likely to be widespread. I'll try to clear up some of these misconceptions in this blog.

Require-Bundle ensures that the required bundles are initialized before you can use them.
False. Require-Bundle and Import-Package only relate to resolving. Resolving is the process where different bundles are wired to each other on package level. From the perspective of a bundle, this is an atomic process. The start/stop primitives are completely independent from this resolving process. The only difference between Require bundle and Import Package is granularity. Require bundle is internally transformed to the same wires as import package uses (except when the more esoteric split packages are desired).

Any bundle can contribute classes to imported packages False. The Framework must select a single exporter for a package that is imported. We call the case where a package can come from multiple sources a split package. This is a common case with the traditional Java class path and a potential source for errors because a package should contain highly cohesive classes; there are also security implications. To address this problem Java added sealed packages. On top of this, the OSGi Specifications added the constraint that a package must have a single source.

This said, there is an exception because in certain cases (Java localization for example), split packages are a necessity. Require Bundle can therefore be used as a façade to multiple bundles that are aggregated. From the outside it looks like the bundle exports a single package but it gets the content from its bundle classpath or other required bundles. Fragments can also be used to provide split packages. However, split packages should be exceptions because of the related security and confusion problems.

With require bundle you are ensured all packages come from the same source This is true, but the same result can be better achieved with Import-Package and the uses directive. When packages are not cohesive and are aware of each other’s implementation details then it is paramount that they actually import the same package. In those cases packages can not be substituted independently. Import-Package solves this problem with a package directive that lists the referred (used) packages. For example bundle A has package p that uses package q. The Framework ensures that A, and all its wired bundles, share the same class loader for package q.

Require-Bundle can actually worsen the problem because it can use packages that are internal. The requiree can easily get into trouble if it imports these private packages. For example, a bundle requiring Xerces could separately import javax.xml.parsers. If this package is also available privately to the Xerces bundle then a class cast exception will occur.

You must import all packages of an exporter False. A bundle should only import the packages that it actually uses. This list is easy to generate from the class files (next generation Eclipse PDE will track this) and it is usually shorter than most people think. Well designed libraries have a few access points. These access points must be exported to use the library, however, all the packages that can be referred from the exported package do not have to be exported or imported. Once you have an object from a library, any classes that are linked from this object are automatically loaded from the same class loader. Most Java standards limit the use of a library to a single package that is shared between all implementations. For example, if you use the Apache Derby database you should not have to import any packages from that library, importing java.sql from the Java runtime should be sufficient.

Bundles are versioned, packages not False. Both bundles and packages are versioned. It is true that most programmers tend to ignore versions all together but good developers version both their bundles and packages.

A Required Bundle is a closed collection of code False. A bundle can be extended by fragments.

Peter Kriens

Blog Archive