A Comparison of Eclipse Extensions and OSGi Services

DZone 's Guide to

A Comparison of Eclipse Extensions and OSGi Services

· Java Zone ·
Free Resource

Since Eclipse adopted the OSGi runtime in version 3.0, there has been some tension between the Extension Registry, which has been a feature of Eclipse from its beginning, and the Service Layer, which came from OSGi and pre- existed the involvement of Eclipse. The cause of the tension is that these two models overlap somewhat, and because they are both intended to solve very similar problems. However “the Devil is in the details”, and these two models are different enough to make it impractical for them to be merged. Therefore developers of Eclipse plugins and RCP applications need to make a choice between the two.

Until very recently, the choice for Eclipse developers has been very clear: the Extension Registry is still used in almost all plugins and RCP applications, to the exclusion of OSGi Services. This is reinforced by the tooling that is available in Eclipse PDE, which provides lots of support for extensions and none for services.

However, recent developments in OSGi have further blurred the boundaries between the two models, and the tools are evolving too. This leads to the inevitable question: “which one is best”?

Structure of the article

This article is intended primarily for Eclipse developers who are reasonably familiar with the “Eclipse Way” of plug-in development with extension points and extensions, but do not have much experience of OSGi services. As such, there is not a lot of discussion of how extensions work or why they exist. The section that follows is just a brief overview.

After that, we discuss OSGi services in a little more depth, including some example code. We talk about the issues that Eclipse developers might come across when getting to grips with services. We will also discuss some of the newer facilities available in OSGi which may help to overcome those issues.

Finally we wrap up with a comparison grid and a conclusion with some recommendations and further reading.

The Eclipse Extension Registry

The Extension Registry is a place where extension points are matched up with extensions. An extension point is a declaration made by a plug-in to say that it is open to being extended with new functionality in a particular way. It is found in the plugin.xml file for the plug-in, and it consists of:

  • An extension point ID, which consists of a “namespace” and suffix. The namespace is usually the ID of the plugin in which the extension point is defined, but it need not be. This is different from an “XML namespace”.

  • A human-readable name.

  • An XML schema document, which defines the structure of the meta-data that extensions are required to supply.

An extension is the flip-side of the coin. It is a declaration by a plug-in to say that it provides functionality to extend another plug-in. It is also found in the plugin.xml and it specifies:

  • The ID of the extension point.

  • An XML node, which must comply with the schema specified by the extension point.

After a plug-in is installed and enters the RESOLVED state, Eclipse queries it for contributions to the extension registry. A plug-in can contribute either extensions or extension points, or both. The result of the scan is cached between runs of Eclipse, so the only time that all of the plug-ins are scanned is when Eclipse is started for the first time, or when your run it with the -clean command line switch.

At this point, Eclipse has done very little work. You could think of the registry as being just like a pair of HashMaps, that allow Eclipse to lookup either extensions or extension points by their ID. So far, we have simply dropped a few items into the HashMaps.

Some time later, a plug-in may decide to query the registry. Usually this is done by the definer of an extension point. Essentially that plug-in asks “who has declared that they have extensions for me?” The registry API provides the plug-in with a snapshot of all the currently installed extensions for the ID that was queried, as an array of data structures that closely resemble the actual XML nodes given by the extension. And that is (almost) the whole story for the extension registry: it enables plug-ins to search for meta-data declared by plug-ins. The key thing to notice here is that no Java classes in the extension plug-in have yet been loaded. We have merely loaded some XML data; this takes far less time and memory than creating a ClassLoader and using it to load code.

Of course Java code has to be loaded at some point. When does that happen? It depends on the definer of the extension point. So far it has queried the extension registry and obtained meta-data, but that meta-data often contains the name of a Java class. In order to make use of that class, the plug-in asks the extension registry to load and instantiate the class.

So it is up to the definer of the extension point to decide when the code in the extensions is loaded. It’s perfectly possible to immediately load all of the classes; however this usually isn’t necessary. Typically the meta-data is sufficient to create some kind of placeholder, and then the actual class is only loaded when the user expresses some interest in it.

For example, the org.eclipse.ui.actionSets extension point can be used to add buttons to the application toolbar. Clicking a button executes a task of some kind, which is implemented as Java code. However, until the button is clicked it consists solely of an icon and a label. Therefore the meta-data for the extension point includes the text for the label and the resource path of the icon. No code is loaded until the user has expressed an interest in the button, i.e. by actually clicking on it.

Figure 1 shows a UML-style sequence diagram of how extension point definers and extension providers interact with the extension registry.


Figure 1: Extensions. Click on image for full size


Another interesting aspect of extensions is that they needn’t result in any code being loaded at all. It is entirely up to the definer of the extension point. There are many extension points in the core RCP plug-ins that do not require a class attribute. For example, all of the Help documentation in Eclipse is contributed through extensions, and there is no Java code involved — just HTML files.

The points to take away from this are:

  • extensions are declarations

  • plug-ins consult extensions to create placeholders for functionality

  • the functionality behind the placeholder is realized when the extension point definer chooses, which enables lazy loading and smaller memory usage

  • extensions need not be associated with executable Java code

OSGi Services

By contrast, an OSGi Service is a Java object (or, if you prefer, a POJO). It is registered in the Service Registry under the name of a Java interface.

Unlike extensions, which are scanned and registered during start-up, services are not automatically registered. To register a service, a bundle must first create an object, and then it must make a call to the OSGi API to register the object as a service. For example suppose we have a service that is defined by the interface org.example.ICustomerLookup and a class that implements it called DbCustomerLookup. We could register it as follows:

public void start(BundleContext context) {
// Create the service object
DbCustomerLookup lookup =
new DbCustomerLookup("jdbc:mysql:localhost/customers");

// Create the properties to register with the service
Dictionary properties = new Hashtable();
properties.put("dbname", "local");

// Register the service
context.registerService(ICustomerLookup.class.getName(), lookup,

There are a number of ways for a bundle to lookup and use a service from another bundle. This is slightly harder because the service layer in OSGi is implicitly dynamic — we have to be prepared for the fact that services can come and go at any time. Therefore the familiar technique of looking up a dependency once and caching it will not work in OSGi. One solution is to lookup the service every time we need to access it, but as the following code shows this can quickly become cumbersome:

public void start(BundleContext context) {
this.context = context;

public String getCustomerName(long id) {
ServiceReference ref = context.getServiceReference(
if(ref != null) {
ICustomerLookup lookup = (ICustomerLookup)
if(lookup != null) {
Customer cust = lookup.findById(id);
return cust.getName();

// Couldn't get name -- service not available
return null;

Figure 2 shows a sequence diagram of the steps involved in registering and consuming a service.


Figure 2: Services. Click on image for full size


Because doing this is so awkward, there is a utility class that can be used to make things much easier. It is called ServiceTracker and can be used as follows:

public void start(BundleContext context) {
this.custLookupTracker = new ServiceTracker(context,
org.example.ICustomerLookup.class.getName(), null);

public String getCustomerName(long id) {
ICustomerLookup lookup = (ICustomerLookup)
if(lookup == null) {
return null; // Alternatively might throw an exception
} else {
Customer cust = lookup.findById(id);
return cust.getName();

ServiceTracker also makes other types of interaction with services easier, such as keeping track of when the service is registered and unregistered. Doing this with the lower level APIs such as ServiceListener can be quite error-prone, so it is recommended to always use ServiceTracker to consume services.

Notice that in both registering services and accessing services, the interaction with OSGi is through an instance of the BundleContext interface. In fact, the BundleContext interface is the only way for bundles to interact with the facilities of the OSGi runtime. Furthermore, the only way we can get a BundleContext is to wait for the OSGi runtime to give one to us — we do this by providing a BundleActivator for our bundle. When the bundle is started, the runtime calls the start() method of our BundleActivator and supplies a BundleContext instance. Before our bundle can be started, it must be loaded. Therefore, until the bundle is loaded, there can be no services registered. Suppose, then, that all the functionality of our application is implemented as OSGi services. Which bundles do we start?

There are three options. First, we could start none of them. This clearly doesn’t work. Second, we could start all of them. This works, but it would result in slow startup times, and our application would use more memory than it needs to get a particular job done. The third option is to know in advance which bundles need to be started, and only start those. This option is very hard to achieve when services are registered by programmatic code, as we have just described. The problem is that a bundle has total freedom to register a service whenever it chooses, or alternatively it might not register a service at all because of certain preconditions. For example, suppose we have service A and service B. it is very common for service B to have a dependency on service A, i.e. service B uses the facilities of A to get its own work done. To support this scenario, the bundle that registers service B can install a listener, and ensure that service B registers only when service A becomes available. This is just one scenario — there are many more possibilities. A bundle might even decide only to register a service when started on Fridays between 1PM and 2PM. Because control is in the hands of arbitrary programmatic logic, the possibilities are infinite and unpredictable.

So, because bundles have such flexibility in registering services, it is really only possible to build an application out of services when the preconditions of all the services are carefully documented. This is clearly impractical for applications like the Eclipse IDE, where the base application is extended by plug-ins from third parties. In fact, it can quickly become impractical for large applications, even those built by a single team. But Declarative Services can help (see next section).

So do services have any advantages over extensions? In my opinion, yes, they do have one significant advantage: they are very much better at dealing with dynamic installation and uninstallation than extensions. This is not to say that extensions do not handle dynamic behaviour. They do, but some people feel the API is complex and difficult to work with, and the impression when working with it is that the dynamic aspects were bolted on top of an existing API rather than being part of the API from the start. In fact that’s exactly what happened. Before Eclipse 3.0 the extensions API was not dynamic, and the core of the API has not changed since then. By contrast the API for working with services is inherently dynamic. This is sometimes inconvenient — one is forced to think about the dynamic aspects even when one doesn’t want to! — but in truth this is good discipline, since the real world is intrinsically dynamic.

There are some scenarios where the advantages of services outweigh the problems related to activation. Take for example servers. In an ideal world, servers should almost never be shut down, but keep going and going until the hardware they run on wears out. In this context, we might as well start all bundles when the server comes up. It may take longer to start, but what do we care about a few extra minutes in start-up time if the server is going to be running for months or years? Actually developers care, because they need to quickly deploy and test new versions of their code to development servers. However, here again the dynamic qualities of services can help, because new versions can be deployed to a running server wihout needing to restart the whole thing.

Another key difference is in the way that services and extensions interact with their consumers. The extension model is essentially “one-to-many”, meaning that an extension is explicitly intended for consumption by one particular plug-in; i.e. the definer of the extension point. On the other hand services use a “many-to-many” model, meaning that a single service can have many consumers. Services are registered so that anybody can find them and use them. For example, imagine the scenario of publish/subscribe messaging. Each publisher could be matched with multiple subscribers, and each subscriber could receive messages from multiple publishers.

So what we really want is something that combines the advantages of both extensions and services. Something that is implicitly dynamic like services, but loaded “on demand” like extensions. Ideally, something that can also simplify the code that application developers must write.

The first steps towards such a solution were taken by Humberto Cervantes and Richard S. Hall in their Service Binder library. This attempted to bring a declarative flavour to OSGi services, along with automating the wiring up of dependencies between services. Service Binder, together with some input from the Eclipse developers (who by this point had become heavily involved in OSGi) evolved into a framework called Declarative Services (DS), developed within the scope of OSGi Release 4. An implementation of Declarative Services can be found in the Equinox project. Equinox is an implementation of OSGi Release 4 and it has been at the core of Eclipse since version 3.0.

Declarative Services

The key observation that led to Service Binder and Declarative Services was that there are actually two separate responsibilities involved in offering a service. Firstly somebody has to create an implementation of a service. Secondly somebody has to publish the service in the service registry. In the traditional services model we described above, those two somebodies were usually the same – i.e. the bundle that implements the service also registers it. However if we separate the two responsibilities, then we can achieve something really powerful.

That is what Declarative Services does. The responsibility for implementing services remains with the bundles as before; however the responsibility for registering services is subsumed by a special bundle called the Service Component Runtime or SCR. So instead of each bundle needing supply code to register its services, it simply allows the SCR to register those services on its behalf.

Naturally the SCR needs some way to know about services which it is supposed to register. As the name “Declarative Services” suggests, this information is provided declaratively. In fact, we’ve come full circle back to XML files. A bundle containing services that it wants the SCR to manage on its behalf contains one or more XML files, with each file representing a “Service Component”. The SCR scans bundles for these XML files, and registers the services described therein. As opposed to extensions (where there is a single XML file per bundle and it is always called plugin.xml), there can be an arbitrary number of XML files per bundle, with arbitrary names. Therefore the files have to be listed in the bundle manifest under a new Service-Component in order for SCR to find them.

Now, the scenario above is still not “on demand”. To support lazy registration, Declarative Services has the notion of “delayed” services. When the SCR registers a delayed service, it creates a proxy object to act as a placeholder, and registers that in the service registry. From the point of view of a consumer, the service is now available for use, however the bundle containing the real service implementation has not been started yet. Then when a consumer tries to actually use the service, the SCR detects this, and asks the OSGi runtime to fully load and activate the bundle. It then subtitutes the proxy for the real service. A key difference between extensions and Declarative Services is that, for the consumer, DS implements laziness transparently, i.e. the code that uses a service need not know or care that the service is temporarily only represented as a placeholder. In contrast, the consumer of an extension must create and manage the placeholder explicitly, and choose when to swap the placeholder for the real implementation.

Figure 3 shows the sequence diagram for Declarative Services. Notice that all of the steps from the vanilla OSGi services diagram are still present. DS refines the services model, rather than replacing it.


Figure 3: Declarative Services. Click on image for full size


Another problem we identified with services — namely that programmatic code has too much flexibility with regard to whether and when it registers services — is also addressed by Declarative Services. The logic controlling the registration of services is specified via declarations, which are easy to access and reason about. This makes it much easier for adminstrators to, say, work out why a particular service won’t come up, and then remedy the situation.

Composing Services

One very interesting and powerful feature of Declarative Services is the ease with which one can compose services.

As mentioned earlier, it is quite common to find two services, A and B, where service B depends on service A. That is, when a method on service B is called, it may make one or more calls to service A to achieve its end result. Next suppose that service C depends on service B: we have started to create a graph of dependent services. Declarative Services makes this graph easy to construct. In the XML file for service B, we simply create a reference to service A – then SCR will wire up the dependency whenever it can be satisfied.

Note that, services being dynamic, there are some interesting questions that arise. For example, what happens if service A goes away – what should we do with service B? Should we kill it, or should it continue working anyway? The answer to this depends on whether the dependency is optional or mandatory. Next, what happens when there are twenty instances of A? Does B want them all, or just one? If just one, which one do we choose? Finally, suppose B is bound to a particular instance of A, and that instance goes away, but there is already a suitable subsitute available (e.g. one of the remaining 19 instances). Should we switch B to use the new A, or do we need to kill B and then create a new B pointing at the new A?

These are all valid questions, and the answer in each case is that it depends on our requirements. Therefore DS provides control in the three dimensions involved:

  1. Optional vs mandatory.
  2. Unary vs multiple.
  3. Static vs dynamic.

Combining the first two axes gives the familar four choices of 0..1 (optional + unary), 1..1 (mandatory + unary), 1..n (mandatory + multiple) and 0..n (optional + multiple). The third axis is less familiar. A dependency is dynamic if it can be hot-swapped, i.e. if service B can be supplied subtitute instances of A. Sometime this isn’t possible; for example A might be stateful, or B may simply not be able to handle substitution because of the way it was programmed. We say that the dependency is static – we must destroy B and create a new instance of it.

All of the above actions naturally can cause follow-on effects in the larger graph. If service C has a static, mandatory dependency on B, and service B has a static, mandatory dependency on A, then every time an instance of A goes away we find that both B and C must be stopped and restarted. When the graph is large, we find that a single service restart can cause an avalanche of restarts across the system. However the avalanche stops when it hits an optional or dynamic dependency. So for the most scalable solution, it is good practice to make your dependencies optional and dynamic whenever possible.

Note that all of the above can be achieved with OSGi services. DS is built on services, after all. But the code required to handle all of the scenarios and their corner cases is complex and error-prone. By contrast, DS lets you specify declaratively what the behaviour should be, and is tested thoroughly for the corner cases.

Making a Choice

It might seem that Declarative Services can do everything that extensions can do, and in addition is better at dealing with dynamics. Also since DS is a part of the OSGi specification whereas extensions are an external extra (albeit part of every Eclipse download), there should be a natural desire to use DS.

Unfortunately this is not quite the case yet. The “delayed” services feature requires some small tweaks to the basic Equinox runtime, and these tweaks have not been implemented yet in the released version 3.2. They do not appear at all yet (at the time of writing) in the other open source OSGi runtimes, Apache Felix and Knopflerfish. They do appear in the latest milestone releases of Equinox 3.3, but you may feel it is risky to use a milestone release in a production application.

Also, there is simply no tooling available in the Eclipse Plugin Development environment (PDE) at the moment for Declarative Services. Building bundles with DS requires maintaining XML files according to a special schema, keeping a list of those XML files in the bundle manifest and ensuring it remains synchronised, and keeping XML files up to date with changes in the Java code as the class and method names evolve. By contrast PDE provides lots of support for graphical editing of extensions and extension points, refactoring support and so on. So the current tooling in Eclipse strongly encourages you to use extensions rather than DS.

Finally, DS is not the only solution to the problems we described with services. Two alternatives from Apache Felix are the Felix Dependency Manager, and a library called iPOJO. However I believe that the stiffest competition will come from the Spring Framework.

In 2006, Spring continued to spread its influence to almost all corners of the Java world. Rod Johnson (the father of Spring) declared that 2006 was the year Spring became ubiquitous. I think Rod was exaggerating, but only slightly: in all likelihood 2007 will be the year.

What does Spring have to do with Eclipse and OSGi? Well, just as Spring 2.0 was being prepared for final release, several of the core developers working on Spring started to take notice of OSGi, and they liked what they saw. In particular they liked services, which they realized were similar in many ways to the “beans” that Spring wires together. However OSGi is dynamic, whereas Spring is largely static. Another thing that the Spring developers noticed was that the programming model for services was somewhat awkward to use, and tended to involve a fair amount of repetitive boilerplate code. They reckoned that if Spring and OSGi could work together, then the resulting platform would benefit from OSGi’s strength in dynamics and Spring’s strength in simplified programming models and reduced boilerplate. Therefore a decision was made to build support for OSGi in Spring 2.1.

There is, frankly, a very high degree of overlap between Spring’s OSGi support and Declarative Services. The Spring developers looked at Declarative Services and decided that Spring already does a lot of what DS does, and does it better. This point is debatable. But the upshot is, the long term success of DS is by no means guaranteed. Despite being the de jure standard from the OSGi specifications, developers tend to favour a de facto standard — which may well end up being Spring. In fact, recent suggestions from Peter Kriens (the OSGi Evangelist) indicate that he is in favour of Spring-OSGi becoming part of the OSGi specification in Release 5.

By the way, it’s important to note that (just like DS) Spring’s OSGi support will require the same runtime tweaks to allow for on-demand usage. Also Spring-OSGi is in its infancy, and is absolutely not suitable for production usage at the moment. Declarative Services is somewhat more mature, but the implementation available in Eclipse is still a little buggy. In part this is due to a chicken-and-egg problem — if more developers were using DS and reporting bugs, then DS would become more stable. But until it is stable, many developers hold back on using it.

So, will DS or even Spring-OSGi someday replace the use of extensions in Eclipse? It’s conceivable, yes. But it’s highly unlikely to happen for a few years. By that time I believe that Eclipse will be widely used both for server platforms as well as IDEs and GUIs, and with the widened scope Eclipse may need a more flexible model than is provided by extensions. However, extensions will certainly be around for a long time yet.

So what should we do today? Should we start planning our migration from extensions to Declarative Services or Spring-OSGi? Should we be worried about building our applications with extensions, which may be heading towards obsolescence?

No, not at all. If extensions are a good fit for your requirements, then have no fear: use extensions. They are mature and will be supported for a long time into the future. So does that mean you should avoid services, or DS or Spring-OSGi? Also no. If they are a good fit for your requirements, use them. Well, it would be prudent to wait for Spring-OSGi to mature, but traditional services are very mature already, and DS is mature enough for early adopters to start using.

Alas, the qualification “if they are a good fit for your requirements” is not so easy to evaluate. In practise, you may find your requirements could be satisfied by both extensions and services. The hard part is deciding which is the best fit. Here are a few guidelines.

For people buiding plug-ins that will be installed into a larger application such as the Eclipse IDE, the choice is extremely clear: use extensions. That is simply the only way at the moment, since you have to use what the host application uses. If you write your plug-ins using only services, there will simply be nobody listening at the other end.

If you are building an RCP application, the choice is still fairly clear: use extensions, mostly. It is not impossible to abandon extension and use services instead, especially if you have control over the whole application. But by doing so you will be sacrificing a lot of the existing framework of RCP, which expects you to be using extensions. You will have to reimplement the entire infrastructure of views, perspectives, editors, action sets etc. Also, you will have issues with activation, and you will not benefit from lazy loading unless you go with Declarative Services (or Spring-OSGi) plus the latest milestones of Eclipse 3.3.

On the other hand, you might find some parts of your application work well with services. If that’s the case then by all means use them in addition to extensions. But be sure to understand the activation issues, and have a plan for ensuring the plug-ins that need to be started actually get started.

If you’re using Eclipse or OSGi to develop something other than an RCP application — such as a server, or perhaps a batch process — then services may be a better bet. In these kinds of applications, hot-swapping functionality without downtime can be more important than fast start-up. Again, there is nothing to stop you using extensions, but you will have to deal with the dynamic extensions API and its warts.

Common Misconceptions

Before concuding, lets take a quick look at some common misconceptions. The following arguments are sometimes used to justify a preference for extensions or services:

  1. “Extensions are not pure OSGi”. This is not true. The Extension Registry is implemented by the bundle org.eclipse.equinox.registry, which depends on org.eclipse.equinox.common. These bundles are implemented with pure OSGi code. There are no secret hooks into specific features of Equinox (the Eclipse implementation of OSGi) and therefore there is no reason, at least in theory, that extensions cannot be used on other OSGi runtimes such as Apache Felix or Knopflerfish.

  2. “Services do not have meta-data.” This is also wrong. Services can be published with any number of arbitrary properties, and these properties can be easily accessed by service consumers. Extensions perhaps provide more flexible meta-data than services (i.e. an XML node versus a list of name/value pairs) but this is unlikely to be a real differentiator.

  3. “Extensions are a legacy of Eclipse 2.0”. This is true in a sense, but “legacy” can imply “obsolete”. As has been argued, extensions are anything but obsolete, and will not be for some time to come.

Comparison Matrix

  Extensions Services Declarative Services Spring-OSGi
What are registered? XML declarations, optionally containing class names. Java objects. Placeholder proxies for Java objects, replaced by real Java objects on first use. Placeholder proxies for Java objects, replaced by real Java objects on first use.
How are they registered? All <extension> nodes in the plugin.xml are automatically registered. Through the BundleContext API All service component XML files declared through the Service- Component manifest entry are automatically registered. All Spring XML files contained in the META-INF/spring folder of a bundle, or declared through the Spring-Context
How are they consumed? Queried by extension point ID. Registry returns all entries, consumer must iterate them to find which one(s) it wants. Queried by interface name, plus a property filter. Usually the filter is specific enough to ensure just one match. Internally uses same query over interface name plus filter, but the query is performed within SCR. Matching services are supplied to consumer code via JavaBean-style setter methods. Same as for DS, but can additionally supply matching services via constructor arguments.
What is the cardinality? Conventionally, one to many. One extension point has many extensions, but each extension has exacly one extension point. However another plug-in can query extension points that it doesn’t own. Many to many. One service can be used by multiple consumers, and one consumer can use many services. Same as for services Same as for services
When are they loaded? Extension declarations are loaded during start-up, or when a new plug-in is installed. Classes named in the extension are loaded lazily, i.e. only when needed. The class that implements a service must be loaded and instantiated before the service can be registered. This happens only when the bundle is explicitly started. For delayed services, the SCR registers a placeholder proxy service immediately when a DS-enabled bundle is resolved. The real class is loaded and instantiated when the service is first used. Same as for DS.
How is dynamic installation/uninstallation dealt with? Either query on each use or track with ExtensionTracker. Either query on each use or track with ServiceTracker. SCR calls methods on the component to supply it with the latest available matching service. It can also call an unset method when the service becomes unavailable. Similarly to DS, supplies latest matching service through setter method on the bean.
Can caching references to extensions/services cause problems? Yes, and as a legacy of pre-OSGi usage, some plug-ins still do this. Yes, but this is strongly discouraged by the specification, and in practice happens rarely. No, SCR does not do this. No, Spring-OSGi does not do this.


In this article I have described in general terms some of the strengths and weaknesses of Eclipse-style extensions and OSGi-style services. However I would not wish my readers to take away a simplistic message that “extensions aren’t dynamic” or “services can’t be used in RCP applications.” I’m afraid the issues are too subtle for that, and there is no substitute for making your own evaluation in the context of your requirements. To help you do that, I leave you with some references to further information on each of the subjects discussed.



I would like to thank Alex Blewitt, Jeff McAffer and Peter Kriens for their invaluable input into this document. However, all opinions expressed are mine, as are all errors and omissions.



Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}