Chapter 24. OSGi and Spring

OSGi and Spring are, in many ways, a very natural technology combination. They approach different problems from different directions, but they do so in a similar spirit. It's only natural, then, that SpringSource, the company that stewards the Spring framework, should turn its eye to OSGi.

OSGi—which was formerly known as the Open Services Gateway initiative, though the name's obsolete now—has its roots in the embedded space, where dynamic service provisioning is far more important than it is in the gridiron world of enterprise applications. It provides a services registry as well as an application life cycle management framework. Beyond this, OSGi provides such features as granular component visibility via a highly specialized class-loading environment, service versioning and reconciliation, and security. OSGi provides a layer on top of the JVM's default class loader. The deployment unit for OSGi is a bundle, which is essentially a JAR with an augmented MANIFEST.MF. This manifest contains declarations that specify, among other things, on what other services the bundle depends, and what service the bundle exports.

OSGi has gained some notoriety because of Eclipse, which uses it for the plug-in model. This is a natural choice, because Eclipse needs to allow plug-ins to load and unload, and to guarantee that certain resources are made available to plug-ins. Indeed, the hope of an enhanced "module" system for Java has loomed large for many years, manifesting in at least a few JSRs: JSR-277, "Java Module System," and JSR-291, "Dynamic Component Support for Java SE." OSGi is a natural fit because it's been around for many years, matured, and has been improved on by many more vendors still. It is already the basis of the architecture of a few application servers.

OSGi is important today, more than ever, in the enterprise space because it represents a solution that can be gracefully layered on top of the Java Virtual Machine (JVM) (if not existing application servers) that can solve problems frequently encountered in today's environments. ".jar hell," the collision of two different versions of the same JAR in the same class loader, is something most developers have encountered. Application footprint reduction provides another compelling use of OSGi. Applications today, be they .war or .ear, are typically bundled with numerous .jars that exist solely to service that application's requirements. It may be that other applications on the same application server are using the same jars and services. This implies that there are duplicated instances of the same libraries loaded into memory. This situation's even worse when you consider how large typical deployed .wars are today. Most .wars are 90% third-party JARs, with a little application-specific code rounding out the mix. Imagine three .wars of 50 MBs, or 100 MBs, where only 5 MBs are application-specific code and libraries. This implies that the application server needs to field 300 MBs just to meet the requirements of a 15-30 unique MBs. OSGi provides a way of sharing components, loading them once, and reducing the footprint of the application.

Just as you may be paying an undue price for redundant libraries, so too are you likely paying for unused application server services, such as EJB1.x and 2.x support, or JCA. Here again, OSGi can help by providing a "server à la carte" model, where your application is provisioned by the container only with the services it needs.

OSGi is, on the large, a deployment concern. However, using it effectively requires changes to your code, as well. It affects how you acquire dependencies for your application. Naturally, this is where Spring is strongest and where dependency-injection in general can be a very powerful tool. SpringSource has made several forays into the OSGi market, first with Spring Dynamic Modules, which is an enhanced OSGi framework that provides support for Spring and much more. Then, on top of Spring Dynamic Modules, SpringSource built SpringSource dm Server, which is a server wired from top to bottom with OSGi and Spring. SpringSource dm Server supports dynamic deployment, enhanced tooling, HTTP, and native .war deployment. It also sports superb administrative features.

OSGi is a specification, not a framework. There are many implementations of the specification, just as there are many implementations of the Java EE specification. Additionally, OSGi is not a user component model, like Spring or EJB 3. Instead, it sits below your components, providing life-cycle management for Java classes. It is, conceptually, possible to deploy to an OSGi runtime in the same way that you deploy to a Java EE runtime, completely unaware of how Java consumes your .jar files and manifests and so on. As you'll see in this chapter, however, there's a lot of power to be had in specifically targeting OSGi and exploiting it in your application. In this chapter, we will discuss Spring Dynamic Modules, and to a lesser extent, Spring dm Server.

Getting Started with OSGi

Problem

You understand OSGi conceptually, but you want to see what a basic, working example with raw OSGi looks like. It's hard to appreciate the sun, after all, if you've never seen the rain.

Solution

In this solution, we'll build a simple service and then use it in a client. Remember, in OSGi, anything used by something else is a service. "Service" doesn't imply any concrete inheritance; it doesn't imply transactional qualities, and it doesn't imply RPC. It's merely a class on whose concrete, black-box functionality and interface your class relies.

How It Works

In this example, we'll use Eclipse's OSGi distribution, Eclipse Equinox. There are many distributions to choose from. Popular ones include Apache's Felix and Eclipse's Equinox. You may use any distribution you want, but for this example, the instructions will be for Felix. The concepts should be the same across implementations, but the specifics may vary wildly in both commands and mechanism.

OSGi and JavaBeans

This is sort of like what a JavaBean was originally intended to be. These days, OSGi is starting to take on the very vivid marketing life that JavaBeans did before it. You'll occasionally note products promoting chief among their upgrades their new, internal use of OSGi, as products did years ago with JavaBeans and object-oriented programming ("Now object-oriented!"). Be mindful of the hype.

The helloworld-service Service

Let's first examine the Java code for the service's interface. It describes a service whose sole function is to take as inputs a target language and a name and to return as output a greeting.

package com.apress.springrecipes.osgi.helloworld.service;

public interface GreeterService {
    String greet(String language, String name);
}

The implementation's similarly plain. It hard-codes the greetings for three languages and satisfies the interface.

package com.apress.springrecipes.osgi.helloworld.service;

import java.util.HashMap;
import java.util.Locale;
import java.util.Map;

public class GreeterServiceImpl implements GreeterService {

    private Map<String, String> salutation;

    public GreeterServiceImpl() {
        salutation    = new HashMap<String, String>();
        salutation.put(Locale.ENGLISH.toString(), "Hello, %s");
        salutation.put(Locale.FRENCH.toString(), "Bonjour, %s");
        salutation.put(Locale.ITALIAN.toString(), "Buongiorno, %s");
    }

    /**
     * @param language Can be any language you want, so long as that language is one of
     *                   <code>Locale.ENGLISH.toString()</code>,
     *                   <code>Locale.ITALIAN.toString()</code>, or
     *                   <code>Locale.FRENCH.toString()</code>.
     *                   :-)
     * @param name       the name of the person you'd like to address
     * @return the greeting, in the language you want, tailored to the name you specified
     */
public String greet(String language, String name) {
        if (salutation.containsKey(language))
            return String.format(salutation.get(language), name);
        throw new RuntimeException(String.format("The language you specified "+ 
The helloworld-service Service
" (%s) doesn't exist", language)); } }

As you can see, the code is simple and, in point of fact, does nothing to betray the fact that we're going to deploy it on top of OSGi. The next class, called an Activator, is required for every bundle. The Activator registers services and receives a life cycle hook to set the stage for the service. Similarly, it reacts to events and register listeners.

package com.apress.springrecipes.osgi.helloworld.service;

import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import java.util.Properties;

public class Activator implements BundleActivator {

    public void start(BundleContext bundleContext) throws Exception {
        System.out.println("Start: ");
        bundleContext.registerService(
        GreeterService.class.getName(),
                new GreeterServiceImpl(),
                new Properties());
    }

    public void stop(BundleContext bundleContext) throws Exception {
        System.out.println("Stop: ");  // NOOP
    }
}

The Activator implements BundleActivator, which has a few life cycle callback methods. We avail ourselves of the start method when the JAR is installed to register the service that's contained. We could register many services. The first parameter, a String, is the service name, sort of like a JNDI name or a Spring beanName. The second parameter is the implementation of the service. The third parameter—the java.util.Properties object being passed to the registerService—are key/value pairs, called service attributes. The client can use them together as a predicate to qualify what service should be returned when looking the service up in the registry. Here, we specify nothing.

This is all the Java code for this service, but we do need to expand on the MANIFEST itself a little bit, to specify extra metadata that OSGi uses in deploying the service. How you do this is entirely at your discretion, and it's simple enough that you could get away with doing it by hand. We use a Maven plug-in that handles the minutiae for us, though there are other approaches as well. Remember, OSGi bundles are simply standard .jar files with customized MANIFESTs that OSGi consumes at runtime. The configuration of the Maven plug-in is simple. The plug-in wraps the bnd command line tool. The bnd tool dynamically interrogates classes for their imports and generates OSGi–compliant entries. We repeat it here mainly for illustrative purposes. For fully working code, see the source code for this book. Note that the plug-in produces OSGi–compliant bundles that work in any container. To read more on the plug-in itself, see http://felix.apache.org/site/apache-felix-maven-bundle-plugin-bnd.html.

...
<plugin>
                <groupId>org.apache.felix</groupId>
                <artifactId>maven-bundle-plugin</artifactId>
                <extensions>true</extensions>
                <configuration>
                    <instructions>
<Export-Package>com.apress.springrecipes.osgi.helloworld.service</Export-Package>
<Bundle-Activator>com.apress.springrecipes.osgi.helloworld.service.Activator
The helloworld-service Service
</Bundle-Activator> </instructions> </configuration> </plugin> ...

The relevant bits are in bold. It tells the plug-in to add to our MANIFEST certain properties: an Export-Package directive and a Bundle-Activator header. The Export-Package directive tells the OSGi environment that this JAR, a bundle, vends the classes in that package, and that those classes should be made visible to the client. The Bundle-Activator directive describes to the OSGi environment, which class implements BundleActivator, and should be consulted when life cycle events occur.

The preceding plug-in takes care of specifying on which other bundles our bundle depends, using the Import-Package directive. The final, resulting MANIFEST.MF (in target/classes/META-INF) is telling.

Manifest-Version: 1.0
Export-Package: com.apress.springrecipes.osgi.
helloworld.service;uses:="org.osgi.framework"
Private-Package: com.apress.springrecipes.osgi.helloworld.service,
Built-By: Owner
Tool: Bnd-0.0.311
Bundle-Name: helloworld-service
Created-By: Apache Maven Bundle Plugin
Bundle-Version: 1.0.0.SNAPSHOT
Build-Jdk: 1.6.0_14-ea
Bnd-LastModified: 1243157994625
Bundle-ManifestVersion: 2
Bundle-Activator: com.apress.springrecipes.osgi.
helloworld.service.Activator
Import-Package: com.apress.springrecipes.osgi.helloworld.service,
org.osgi.framework;version="1.3"
Bundle-SymbolicName: com.apress.springrecipes.osgi.helloworld.service.
helloworld-service

This describes the dependencies, exports, and layout of the bundle fully to the OSGi runtime, and makes it easy for clients to know what they're getting when they use this bundle. This rounds out the code for the service. Let's install it into the OSGi environment and then start in using it as a client. The installation procedure is very specific to each tool.

Installing Equinox

Assuming that you've downloaded Equinox from http://www.eclipse.org/equinox/ (this book was written against 3.4.2) and unzipped it, change to the installation directory and, on the command line, type the following:

java -jar eclipse/plugins/org.eclipse.osgi_YOUR_VERSION.jar -console

Naturally, substitute YOUR_VERSION for the one that applies to the version of the distribution that you downloaded. We're using 3.4, which is the latest stable release. This will start an interactive session. You can type help to see the list of available commands. You can issue the services command to list the bundles already installed. To install the bundle, assuming you've put the JAR produced from previous steps for the service at the root of your file system (C:/, or /) issue:

install file://helloworld-service-1.0-SNAPSHOT.jar or install file:/C:
Installing Equinox
/helloworld-service-1.0-SNAPSHOT.jar

This installs the JAR in the OSGi registry and produces an ID that can be used to refer to the bundle. Use it as the operand to the start command.

start 3

This will start the bundle and ready it for use by other bundles.

Using the Service in a Client Bundle

Using the service is almost exactly the same as creating the service, except that we need to specify our dependence on the service in the bundle. Let's first review the client-side Java code. In this case, we simply look up the service and demonstrate it in the Activator for the client bundle. This is simple, and to the point, though not necessarily typical. In the source code for the book, this is a different Maven project, called helloworld-client.

package com.apress.springrecipes.osgi.helloworld.client;

import com.apress.springrecipes.osgi.helloworld.service.GreeterService;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import java.util.Arrays;
import java.util.Locale;

public class Activator implements BundleActivator {

    public void start(BundleContext bundleContext) throws Exception {
        ServiceReference refs[] = bundleContext.getServiceReferences(
                          GreeterService.class.getName(), null);
        if (null == refs || refs.length == 0) {
            System.out.println("there is no service by this description!");
            return;
        }
GreeterService greeterService = (GreeterService)
                    bundleContext.getService(refs[0]);

       String[] names = {"Gary", "Steve", "Josh", "Mario",
           "Srinivas", "Tom", "James", "Manuel"};

        for (String language : Arrays.asList(
                Locale.ENGLISH.toString(),
                Locale.FRENCH.toString(),
                Locale.ITALIAN.toString())) {
            for (String name : names) {
                System.out.println(greeterService.greet(language, name));
            }
        }
    }

    public void stop(BundleContext bundleContext) throws Exception {
        // NOOP
    }
}

The salient code is in bold. Here, we look up a ServiceReference in the OSGi registry. We use the same name as we provided when we registered the class in the registry. The second argument, null, is where we would specify any values to narrow the criteria for the search for a service. Because there's only one that could possibly match in this case, we won't specify anything. Note that there is no guarantee you'll get a reference to the service, or that you'll get only one. Indeed, you may be given any number of ServiceReferences, which is why the return type is scalar. This is a very different paradigm than more traditional component models such as EJB, which treat the inability to return a handle to a service as an error. This is also somewhat counterintuitive from how traditional service registries (such as JNDI) work. When we're sure we have a handle to a service, we redeem it for an interface to the actual service itself, somewhat like an EJBHome, using the bundleContext.getService(ServiceReference) method. You can see, already, where Spring might be able to lend a hand—in this resource lookup and acquisition logic.

Let's examine the final MANIFEST for the client. It's not much different from what we've done before. It differs mainly in that it lists our service as a dependency. Apart from that, it's pretty boilerplate. The Activator is the only thing that's changed from the previous example. If you're following with Maven, don't forget to specify the changed Activator class in the plug-in. Additionally, we're using the interface from the service JAR we produced in the last example. The Maven plug-in automatically adds this to your Import-Package MANIFEST header.

Manifest-Version: 1.0
Export-Package: com.apress.springrecipes.osgi.helloworld.client;
uses:="com.apress.springrecipes.osgi.helloworld.service,org.osgi.framework"
Private-Package: com.apress.springrecipes.osgi.helloworld.client,
Built-By: Owner
Tool: Bnd-0.0.311
Bundle-Name: helloworld-client
Created-By: Apache Maven Bundle Plugin
Bundle-Version: 1.0.0.SNAPSHOT
Build-Jdk: 1.6.0_14-ea
Bnd-LastModified: 1243159626828
Bundle-ManifestVersion: 2
Bundle-Activator: com.apress.springrecipes.osgi.
helloworld.client.Activator
Import-Package: com.apress.springrecipes.osgi.
helloworld.client,com.apress.springrecipes.osgi.
helloworld.service,org.osgi.framework;version="1.3"
Bundle-SymbolicName: com.apress.springrecipes.osgi.helloworld.client.helloworld-client

Nothing too exceptional here, except the aforementioned Import-Package. Install the bundle as we did for the service. When the bundle begins to load and start, it calls the start method of the Activator. You should see greetings being enumerated on the console. You've successfully completed your first OSGi deployment.

install file://helloworld-client-1.0-SNAPSHOT.jar.
start 2

You should see the output, as expected, greeting each name.

osgi> install file://helloworld-client-1.0-SNAPSHOT.jar.

Bundle id is 2

osgi> start 2
Hello, Gary
Hello, Steve
Hello, Josh
Hello, Mario
Hello, Srinivas
Hello, Tom
Hello, James
Hello, Manuel
Bonjour, Gary
Bonjour, Steve
Bonjour, Josh
Bonjour, Mario
Bonjour, Srinivas
Bonjour, Tom
Bonjour, James
Bonjour, Manuel
Buongiorno, Gary
Buongiorno, Steve
Buongiorno, Josh
Buongiorno, Mario
Buongiorno, Srinivas
Buongiorno, Tom
Buongiorno, James
Buongiorno, Manuel
osgi>

Getting Started Using Spring Dynamic Modules

Problem

You've got a feeling for how OSGi works, what it's capable of, and even how to go about creating a simple "hello, world!" example. Now, you want to start using Spring to smooth over some of the minutiae of resource acquisition and to help build more reliable systems in an OSGi environment.

Solution

Use Spring Dynamic Modules to provide the integration. Spring Dynamic Modules is a framework on top of OSGi that works with any OSGi environment. It provides tight integration for Spring dependency injection in the world of OSGi, which includes support for things like application context discovery, interface-based service injection, and versioning.

How It Works

Spring Dynamic Modules is a very powerful API for integration with the OSGi environment. You need the Spring framework itself, and the Spring OSGi JARs, as well. If you're following along using Maven, the JARs can be added by using SpringSource's OSGi bundle repository. This repository exports the Spring framework JARs, as well as those of countless other open source projects, in an OSGi–friendly format under a Maven/Ivy–friendly repository. For more information on the repositories, see http://www.springsource.com/repository/app/faq. To get access to them from Maven, add the repositories to your pom.xml configuration file, at the bottom, before the closing </project> element:

<repository>
            <id>com.springsource.repository.bundles.release</id>
            <name>SpringSource Enterprise Bundle Repository - SpringSource Bundle 
How It Works
Releases</name> <url>http://repository.springsource.com/maven/bundles/release</url> </repository> <repository> <id>com.springsource.repository.bundles.external</id> <name>SpringSource Enterprise Bundle Repository - External Bundle
How It Works
Releases</name> <url>http://repository.springsource.com/maven/bundles/external</url> </repository>

The SpringSource Enterprise Bundle Repository provides numerous OSGi–friendly jars files. To see if yours is already supported, search for it at http://www.springsource.com/repository.

We'll use this infrastructure to rebuild our previous "hello, world!" example, this time relying on Spring to provide the injection of the service itself and to make writing the client more in line with what we've come to expect from Spring development. We've already deployed the service, so we don't need to rework any of that. Let's instead concentrate on a new client bundle.

Let's explore our revised client code. The entirety of the client is one Java class and two Spring XML application context files. One file has the OSGi–friendly Spring Dynamic Modules namespace imported; the other is a standard Spring application context.

When we're finished and deploy the final bundle to Equinox, the XML context files loaded in the META-INF directory will be loaded. It is through the magic of OSGi extender models that this works. OSGi enables deployed bundles to scan other deployed bundles and react to qualities of those bundles. In particular, this is sort of like what Spring does when it scans a package for classes with annotations. Here, Spring Dynamic Modules scans our deployed bundles and loads an ApplicationContext (actually, the specific type of the ApplicationContext is OsgiBundleXmlApplicationContext) into memory based on an event, or a trigger. There are two ways to trigger this behavior. The first is to explicitly specify in the META-INF/MANIFEST.MF file the attribute Spring-Context, which allows you to override the default location it consults. Otherwise, by default, Spring Dynamic Modules will look for the XML file in the META-INF/spring directory of a bundle. Typically, you'll split your OSGi–specific Spring configuration and your plain-vanilla Spring configuration into two different files, of the form: modulename-context.xml and modulename-osgi-context.xml.

The Java code is like that of any other standard Spring bean. In fact, for all intents and purposes, this code has no knowledge of OSGi. It does have knowledge of Spring itself, though there's no reason it needs to. The @Autowired field-injection and InitializingBean interface are just for convenience and brevity's sake.

package com.apress.springrecipes.osgi.springdmhelloworld.impl;

import com.apress.springrecipes.osgi.helloworld.service.GreeterService;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.Arrays;
import java.util.Locale;

public class SpringDMGreeterClient implements InitializingBean {

    @Autowired
    private GreeterService greeterService;

    public void afterPropertiesSet() throws Exception {
      for (String name : Arrays.asList("Mario", "Fumiko", "Makani"))
        System.out.println(greeterService.greet(Locale.FRENCH.toString(), name));
    }
}

Let's explore the Spring XML files. The first one, src/main/resources/META-INF/spring/bundle-context.xml, a standard Spring XML application context, should not be very surprising. It contains just one bean definition.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
How It Works
http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context
How It Works
http://www.springframework.org/schema/context/spring-context.xsd"> <context:annotation-config/> <bean name="springDMGreeterClient" class="com.apress.springrecipes.osgi.springdmhelloworld.impl.SpringDMGreeterClient"/> </beans>

Exploring the Spring Dynamic Modules application context (src/main/resources/META-INF/spring/bundle-context-osgi.xml), we see little that's different or unusual, except an osgi namespace.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:osgi="http://www.springframework.org/schema/osgi"
  xsi:schemaLocation="http://www.springframework.org/schema/beans 
How It Works
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/osgi
How It Works
http://www.springframework.org/schema/osgi/spring-osgi.xsd"> <osgi:reference id="greeterService" interface="com.apress.springrecipes.osgi.helloworld.service.GreeterService"/> </beans>

Here, we've imported a new namespace, osgi, which enables us to use the osgi:reference element. The osgi:reference element proxies an OSGi service. The proxy manages awareness of whether the service has been removed or not. This might happen, for example, if you unload the service to replace it. If the service is removed and you make a call against the proxy, it will block, waiting for the service to be reinstalled. This is called damping. Furthermore, the proxy itself can be referenced for standard dependency injection into other beans. Remember: when we registered the service with OSGi in the Activator for the greeter service, we passed in an interface as well as the implementation to the bundleContext.registerService invocation. This interface is what we're using to look up the service here.

Already, we've reaped the benefits of OSGi and Spring Dynamic Modules. This application is infinitely more robust because, as a client to a service, it's immune to outages in the service itself and because any number of other clients can now also use the service in the same way, without loading duplicate versions of the jar.

In order for this example to run, we need to deploy all the dependencies of the client into Equinox so that they can be managed. In this case, that implies that we have to install all the bundles for Spring and all the dependencies that Spring itself has. To simplify this process, we'll have Equinox automatically load the JARs at startup. The simplest way to do this is to modify Equinox's config.ini file. The file will be located under the configuration directory, under the eclipse/plugins folder. The folder won't be present if you haven't run the console as explained in previous exercises. The configuration folder is where Equinox keeps state between sessions. Create the file with a text editor. We're going to reference the JARs that are required by this project. To obtain those JARs using the Maven project, you can issue mvn dependency:copy-dependencies, which will place the jars in the target/lib folder of the current project, where you can grab them. I would put them in a folder under the OSGi Equinox directory so that you may reference them quickly, using relative paths. You can visit the source code for this book to see the exact Maven configuration I've used. Now that you've got the JARs, modify the config.ini file and list the JARs. My config.ini looks like this:

osgi.bundles=spring/com.springsource.org.aopalliance-1.0.0.jar@start, 
How It Works
spring/com.springsource.org.apache.commons.logging-1.1.1.jar@start, spring/helloworld-service-1.0-SNAPSHOT.jar@start, spring/org.osgi.core-1.0.0.jar@start, spring/org.osgi.core-4.0.jar@start, spring/org.springframework.aop-2.5.6.A.jar@start, spring/org.springframework.beans-2.5.6.A.jar@start, spring/org.springframework.context-2.5.6.A.jar@start, spring/org.springframework.core-2.5.6.A.jar@start, spring/org.springframework.osgi.core-1.1.3.RELEASE.jar@start, spring/org.springframework.osgi.extender-1.1.3.RELEASE.jar@start,
How It Works
spring/org.springframework.osgi.io-1.1.3.RELEASE.jar@start eclipse.ignoreApp=true

These declarations tell Equinox to load and start the JARs at launch time. We put the JARs in a folder called spring, which itself is located under the eclipse/plugins folder.

We have one last thing to do to see it all working. We need to install and start the client. There is no change in this process from before. We repeat it here for clarity. Run the Equinox console:

java -jar eclipse/plugins/org.eclipse.osgi_YOUR_VERSION.jar -console

Then, install and start the client:

install file:/path/to/your/client/jar.jar
start 12

If everything goes to plan, you should see the application contexts recognized by Spring, and you should, toward the end of the output, see the output from the invocation of the service.

...terService,org.springframework.context.annotation.internalAutowiredAnnotationPro...
equiredAnnotationProcessor,springDMGreeterClient]; root of factory hierarchy
Bonjour, Mario
Bonjour, Fumiko
Bonjour, Makani
May 25, 2009 11:26:04 PM org.springframework.osgi.context.support.AbstractOsgiBu...
INFO: Publishing application context as OSGi service with properties {org.spring...
iserecipes.springdmhelloworld, Bundle-SymbolicName=com.apress.springenterprisere...

Exporting a Service Using Spring Dynamic Modules

Problem

You want to create services and have those automatically installed in the registry, as we did in the first recipe, available for other services to depend on. This process is different because we will no longer register the services in Java code, and instead will let Spring export the service on our behalf.

Solution

You can use Spring Dynamic Modules configuration schema to export a service. The service will be made available to other beans as well as other OSGi components.

How It Works

The approach is similar to that of the other configurations. We will create a bundle and deploy it. Create a Spring XML configuration (src/main/resources/META-INF/spring/bundle-context.xml) for our regular Spring beans, just as we did in the previous recipe.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:osgi="http://www.springframework.org/schema/osgi"
       xsi:schemaLocation=" http://www.springframework.org/schema/beans
                            http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
                            http://www.springframework.org/schema/osgi
                            http://www.springframework.org/schema/osgi/spring-osgi.xsd">

    <osgi:reference id="greeterService"
         interface="com.apress.springrecipes.osgi.helloworld.service.GreeterService"/>

</beans>

Here, we declare a bean named greeterService that we will reference.

In a separate file (src/main/resources/META-INF/spring/bundle-osgi-context.xml), we will export the service using the Spring Dynamic Modules configuration schema. Here, we'll use the osgi:service element to export the bean as an OSGi service, classified by the interface we specify. Note that we could, technically, have specified a concrete class for the value of interface, though it's not recommended. In our example, we want our service to advertise that it supports multiple interfaces, so we'll specify both of them.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns:osgi="http://www.springframework.org/schema/osgi"
       xmlns:util="http://www.springframework.org/schema/util"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
How It Works
http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/beans/spring-util.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/osgi http://www.springframework.org/schema/osgi/spring-osgi.xsd"> <context:annotation-config/> <osgi:service auto-export="all-classes" ref="greeterService"> <osgi:interfaces> <value>com.apress.springrecipes.osgi.helloworld.service.GreeterService</value> <value>com.apress.springrecipes.osgi.helloworld.service.GreetingRecorderService</value> </osgi:interfaces> </osgi:service> </beans>

You can abbreviate the syntax by using an anonymous bean. An anonymous bean specified inside of the osgi:service element allows you to avoid cluttering the namespace. The previous salient pieces, slightly changed to use an anonymous bean, look like this:

<osgi:service   interface="com.apress.springrecipes.
osgi.helloworld.service.GreeterService">
    <bean class="com.apress.springrecipes.osgi.helloworld.
service.GreeterServiceImpl"/>
</osgi:service>

Remember, as these beans are proxies, some may load asynchronously or take a longer time to register. This implies that you may have timing issues to resolve in configuring your service. For this, Spring Dynamic Modules provides the depends-on attribute, which lets your bean wait for another bean. Suppose our greeterService depended on a dictionaryService, which itself took a long time to load:

<osgi:service  depends-on="dictionaryService"
interface="com.apress.springrecipes.osgi.helloworld.service.GreeterService">
    <bean class="com.apress.springrecipes.osgi.helloworld.service.GreeterServiceImpl"/>
</osgi:service>

Interfacing with the OSGi Runtime

You can interact with the OSGi infrastructure in some interesting, more metaprogramming-oriented ways. Spring surfaces a lot of this functionality if you want to use it. The first, most direct connection to OSGi is the bean that's created on your behalf when you export a service. This bean, an instance of org.osgi.framework.ServiceRegistration, is in turn a delegate to the Spring bean you have defined. You can inject this instance if you want and manipulate it, just as with any other Spring bean. Define an ID on the osgi:service element to be able to reference it.

By default, beans created in a Spring application context are global to the entire OSGi runtime, including all clients that use it. Sometimes, you may want to limit the visibility of a service so that multiple clients each get their own instance of the bean. Spring Dynamic Modules provides a clever use of the scope attribute here, allowing you to limit beans exported as services to the client, or service importer.

<bean scope ="bundle"     id="greeterService"
class="com.apress.springrecipes.osgi.helloworld.service.GreeterServiceImpl"/>

  <osgi:service
interface="com.apress.springrecipes.osgi.helloworld.service.GreeterService"
ref="greeterService"     />

The OSGi runtime surfaces events based on the life cycle of services. You can register a listener to react to the life cycle of a service. There are two ways to do this, one using anonymous inner beans and one using a named reference.

<osgi:service  id="greeterServiceReference"
interface="com.apress.springrecipes.osgi.helloworld.
service.GreeterService">
    <registration-listener registration-method="greeterServiceRegistered"
                                       unregistration-method="greeterServiceUnRegistered">
 <bean class="com.apress.springrecipes.osgi.helloworld.service.
Interfacing with the OSGi Runtime
GreeterServiceLifeCycleListener"/> </registration-listener> </osgi:service>

Spring Dynamic Modules is relatively flexible with respect to the prototype of the method:

public void serviceRegistered(    ServiceInstance serviceInstance, Map serviceProperties)
public void serviceUnregistered(ServiceInstance serviceInstance, Dictionary serviceProperties)

Naturally, there's a similar feature for client-side proxies. The feature is a listener on the osgi:reference element. Here, we use an inner bean inside the osgi:listener element, though you can also use the ref attribute on the osgi:listener element and avoid the inner bean if you wish.

<osgi:reference id="greeterService"
interface="com.apress.springrecipes.osgi.
helloworld.service.GreeterService">
   <osgi:listener bind-method="greeterServiceOnBind"
            unbind-method="greeterServiceOnUnbind" >
       <bean class = "com.apress.springrecipes.osgi.
Interfacing with the OSGi Runtime
helloworld.client.GreeterClientBindListener"/> </osgi:listener> </osgi:reference>

Spring Dynamic Modules also supports injection and manipulation of bundles themselves. An injected bundle is of type org.osgi.framework.Bundle instances. The simplest use case is that you want to obtain an instance of the org.osgi.framework.Bundle class from an already loaded bundle in the system. You specify the symbolic name to help Spring look it up. The Symbolic-Name is a MANIFEST.MF attribute that every bundle should specify. Once acquired, the Bundle can be interrogated to introspect information about the bundle itself, including any entries, its current state (which can be any of: UNINSTALLED, INSTALLED, RESOLVED, STARTING, STOPPING, or ACTIVE), and any headers specified on the bundle. The Bundle class also exposes methods to dynamically control the life cycle of the bundle, in much the same way as you might from the Equinox shell. This includes things like stopping a bundle, starting it, uninstalling it, and updating it (that is, replacing it with a new version at runtime, for example.)

<osgi:bundle id ="greeterServiceBundle"
             symbolic-name="symbolic-name-from-greeter-service" />

You can inject into a variable of type org.osgi.framework.Bundle, just as you would any other bean. More powerful, however, is the prospect of dynamically loading and starting bundles using Spring. This sidesteps the shell we used earlier to install a service. Now, that configuration is built into your application and it will be enforced on your application context's startup. To do this, you need to specify the location of the .jar to be installed and optionally an action to take, such as start, when the bundle is installed into the system.

<osgi:bundle
         id ="greeterServiceBundle"
                location= "file:/home/user/jars/greeter-service.jar"
                symbolic-name="symbolic-name-from-greeter-service"
                action="start"
 />

You can specify what action the bundle should take on the event that the OSGi runtime is shut down using the destroy-action attribute.

Finding a Specific Service in the OSGi Registry

Problem

OSGi will let you maintain multiple versions of a service in your registry at the same time. While it is possible to ask the registry to simply return all instances of the services that match (i.e., by interface), it can be useful to qualify them when searching.

Solution

OSGi, and Spring Dynamic Modules on top of it, provides many tools for discriminating services both in publishing and consuming services.

How It Works

Multiple services of the same interface may be registered inside of an OSGi environment, which necessitates a conflict-resolution process. To aid in that, Spring Dynamic Modules provides a few features to help.

Ranking

The first feature is ranking. Ranking, when specified on a service element, allows the ascription of a rank relative to other beans with the same interface. Ranking is specified on the service element itself. When encountered, the OSGi runtime will return the service with the highest-ranking integer value. If a version of a service is published with a higher integer, any references will rebind to that.

<osgi:service
ranking="1"
interface="com.apress.springrecipes.osgi.helloworld.service.GreeterService">
    <bean class="com.apress.springrecipes.osgi.helloworld.service.GreeterServiceImpl" />
</osgi:service>
...
<osgi:service
ranking="2"
interface="com.apress.springrecipes.osgi.
helloworld.service.GreeterService">
    <bean class="com.apress.springrecipes.osgi.helloworld.service.GreeterServiceImpl"/>
</osgi:service>

If you want to bind to a specific service of a particular ranking, you can use a filter on your osgi:reference element.

<osgi:reference id="greeterServiceReference"
   interface="com.apress.springrecipes.osgi.helloworld.service.GreeterService"
  filter="( service.ranking = 1 )"
  />

Service Attributes

A more robust solution to service discrimination is service attributes. A service attribute is an arbitrary key and value pair that the service exports, and on which lookups for a service with multiple matches can be predicated. The service properties are specified as a Map element. You may have as many keys as you want.

<osgi:service  ref="greeterService"    interface="com.apress.springrecipes.
osgi.helloworld.service.GreeterService">
 <osgi:service-properties>
   <entry key="region" value = "europe"/>
</osgi:service-properties>
 </osgi:service>

If you wanted to look this service up, you would use a filter attribute for the client. Here's how you might specify the osgi:reference element to find this service as a client.

<osgi:reference id="greeterService" interface="com.apress.springrecipes.
osgi.helloworld.service.GreeterService"
filter="(region=europe)"
  />

There are also many standard attributes that the runtime configures for all services. For a good list, consult http://www.osgi.org/javadoc/r2/org/osgi/framework/Constants.html. You may also use the bean name of the original service as a predicate for finding a service. This will be very familiar.

<osgi:reference id="greeterServiceReference"
interface="com.apress.springrecipes.osgi.helloworld.service.GreeterService"
bean-name="greeterService"
  />

Cardinality

There are frequently situations where OSGi will return more than one instance of a service that satisfies the interface, especially if you aren't able to specify which one you're looking for using the methods discussed before. Take, for example, a deployment where you have multiple GreeterServices deployed for various regions. Spring Dynamic Modules provides the set and list interfaces to retrieve multiple references and populate a java.util.Set and java.util.List, respectively.

<list id="greeterServices"
     interface ="com.apress.springrecipes.osgi.helloworld.service.GreeterService"
     cardinality="1..N" />

Note the cardinality element, which stipulates how many instances are expected. 0..N stipulates that any number of references are expected. 1..N stipulates that at least one instance is expected. On a single reference element, only two values for cardinality are acceptable: 0..1, and 1..1. This has the effect of saying that fulfillment of the dependency for a reference is not mandatory (0..1) or that it's mandatory (1..1).

You may fine-tune the collections returned to you. For example, you might specify a comparator element or attribute to sort the collection returned. The bean you reference should implement java.util.Comparator. Unless this logic is extraordinarily involved, it might be an ideal place for using Spring's scripting support to inline the java.util.Comparator implementation in the Spring application-context XML file.

<list id="greeterServices"
     interface ="com.apress.springrecipes.osgi.helloworld.service.GreeterService"
     cardinality="1..N"     comparator-ref="comparatorReference" />

Publishing a Service Under Multiple Interfaces

Problem

Your bean implements many interfaces, and you want those interfaces to be visible to clients of the service.

Solution

Spring Dynamic Modules supports registering beans under multiple interfaces. It also provides extra flexibility in auto-detecting the interfaces.

How It Works

Spring Dynamic Modules creates a proxy for you based on the interface you specify. A side effect is that the other interfaces your bean implements won't be visible. To be able to access a bean by other interfaces, you may enumerate the other interfaces in the bean's registration, which will make it available under all of those interfaces. Note that it's illegal to specify both the interface attribute and the interfaces attribute: use one or the other.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:osgi="http://www.springframework.org/schema/osgi"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
How It Works
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
How It Works
ttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
How It Works
ttp://www.springframework.org/schema/osgi http://www.springframework.org/schema/osgi/spring-osgi.xsd"> <context:annotation-config/> <bean id="greeterService" class="com.apress.springrecipes.osgi.helloworld.
How It Works
service.GreeterServiceImpl"/> <osgi:service ref="greeterService"> <osgi:interfaces> <value>com.apress.springrecipes.osgi.helloworld.service.GreeterService</value> <value>com.apress.springrecipes.osgi.helloworld.service.GreetingRecorderService</value> </osgi:interfaces> </osgi:service> </beans>

This is powerful in its own right, but Spring Dynamic Modules can help even more. The service element supports an auto-export attribute, which starts auto-detection of interfaces on the bean and publishes them under the detected interfaces. There are four options: disabled, interfaces, class-hierarchy, and all-classes.

The first option, disabled, is the default behavior. It works with whatever interfaces you've explicitly configured on the bean using the interfaces element or the interface attribute. The second, interfaces, registers the service using the interfaces implemented by a bean but not its superclasses or the implementation class. If you want to include all superclasses as well as the current implementation class, use class-hierarchy. If you want everything: superclasses, implementation class, as well as all interfaces on the implementation class, choose all-classes.

Having said this, you should probably stick to explicitly specifying the interfaces of your bean. The auto-detection may overexpose your bean, revealing crucial private implementation knowledge. More to the point, sometimes it may not expose enough. Perhaps you forgot that the functionality that you're trying to export is specified on an interface on a superclass? Don't risk either, and instead prefer explicit configuration.

Customizing Spring Dynamic Modules

Problem

Spring Dynamic Modules is a powerful tool, and it provides reasonable defaults (and results) for very little investment. The main work of Spring Dynamic Modules is done through extenders, which sometimes require customization.

Solution

Spring Dynamic Modules provides strong support for fragments, part of the OSGi specification, to override key infrastructure beans Spring uses in service of the extenders.

How It Works

Extenders provide a way to let a bundle control the loading process of another bundle. This magic is most clearly exemplified in Spring Dynamic Modules's ability to auto-load Spring XML application contexts detected in the META-INF/spring/ folder, or those configured by the Spring-Context MANIFEST.MF attribute. Spring provides two extenders: one for web-based bundles (spring-osgi-web-extender, whose trigger is being deployed in a bundle ending in .WAR) and one for normal bundles (spring-osgi-extender).

Customizing these extenders is key to customizing Spring Dynamic Modules's behavior at runtime. Fragments permit the injection of resources, classes, and functionality into a bundle on the same ClassLoader as the host bundle. Fragments do not, however, let you remove functionality or override MANIFEST.MF values that are already established. Additionally, a fragment cannot contain its own Activator. The OSGi runtime knows a bundle is a fragment if it encounters a Fragment-Host header in the MANIFEST.MF file. The Fragment-Host attribute, in turn, is the symbolic name of another bundle. In this case, because we are interested in configuring the two bundles with the extenders, we will reference one of org.springframework.bundle.osgi.extender or org.springframework.bundle.osgi.web.extender.

Spring will check bundles that are configured this way and look for Spring XML application contexts inside the META-INF/spring/extender folder. These Spring XML application contexts are loaded and any beans with the same names as well known beans used by Spring will be given priority and used instead. Let's go through some examples of where this might be useful.

Making Spring Process OSGi Annotations on Beans

Spring provides the ability to inject OSGi services using annotations. This functionality is available as an extension and requires a little configuration to enable it. The annotation serves the same function as the reference element discussed earlier.

@ServiceReference
public void     setGreeterService(GreeterService greeterService) {
 // ...
}

To see this work, you need to enable it using a fragment. Let's first take a look at the Spring XML configuration. Here, we declare a properties bean that, in turn, contains our property key, process.annotations.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
Making Spring Process OSGi Annotations on Beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
Making Spring Process OSGi Annotations on Beans
http://www.springframework.org/schema/context
Making Spring Process OSGi Annotations on Beans
http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <bean name="extenderProperties" class="org.springframework.beans.factory.
Making Spring Process OSGi Annotations on Beans
config.PropertiesFactoryBean"> <property name="properties"> <props> <prop key="process.annotations">true</prop> </props> </property> </bean> </beans>

Changing the Default HTTP Server That Spring Uses When Deploying a .war

Spring Dynamic Modules provides the ability to install OSGi bundles as web applications. It uses an instance of org.springframework.osgi.web.deployer.WarDeployer to perform this feat. Currently, the default is org.springframework.osgi.web.deployer.tomcat.TomcatWarDeployer. You can change this to use Jetty:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
Changing the Default HTTP Server That Spring Uses When Deploying a .war
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
Changing the Default HTTP Server That Spring Uses When Deploying a .war
http://www.springframework.org/schema/context 
Changing the Default HTTP Server That Spring Uses When Deploying a .war
http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <bean name="warDeployer" class="org.springframework.osgi.web.deployer.jetty.JettyWarDeployer"/> </beans>

Using SpringSource dm Server

Problem

You're convinced of the potential of OSGi, but you feel that perhaps, even with Spring Dynamic Modules, the investment might be hard to justify without some serious upgrades to the tooling and a general smoothing out of the road. Such upgrades would enhance monitoring, provide better, more thoroughly baked support for deployment of traditional .war artifacts, enable use of some of the standard Java EE libraries, provide useful defaults for many de facto standard libraries, and provide fully integrated support for Spring Dynamic Modules.

Solution

Use Spring dm Server, SpringSource's tried and true OSGi–oriented server built on many technologies including Equinox and the Spring framework itself.

How It Works

OSGi is a framework, on top of which more sophisticated solutions are built. OSGi doesn't solve framework concerns, instead focusing on infrastructure requirements for Java applications. OSGi is a specification that is well-represented in implementations. Spring Dynamic Modules provides functionality that sits on top of those implementations, providing very powerful runtime sophistication for developers looking to produce and consume OSGi services in a Spring-friendly fashion.

Realizing that Spring Dynamic Modules was, while powerful for those already invested in an OSGi platform, not the most natural accommodations for those trying to migrate large code into the OSGi environment, SpringSource created SpringSource dm Server. SpringSource dm Server is a robust solution. There are several editions available. The community edition is licensed under the GPL 3.0. You may download the source code and build it yourself. SpringSource dm Server provides tooling via Eclipse to help design solutions designed for dm Server.

SpringSource dm Server's many advances focus on delivering a solution, and not just a framework, for delivering OSGi–based enterprise applications. The lack of support for core enterprise features stems from OSGi's suitability for any of a number of target environments, including embedded devices. While you are able to use OSGi–friendly HTTP servlet containers to deploy web applications, it's been up to you to build that solution. Imagine piecing together a proper Java EE server, component by component! Thus, SpringSource dm Server provides value above and beyond a regular OSGi solution because it's already well integrated.

SpringSource dm Server provides a number of features geared toward minimizing the hassle of deploying large applications in an OSGi environment. It reduces the number of redundant JARs on a server through the use of a shared library repository, where JARs shared among many other artifacts may be stored. Significantly, this reduces the need to redeploy bundles, because they are automatically loaded from this repository. Large enterprise packages tend to be composed of a tapestry of dependencies, each of which depends on any permutation of other dependencies. OSGi–enabling all of these interwoven dependencies via the granular use of the Import-Package header would be tedious. Spring dm Server provides the ability to wholesale import an entire library and all packages therein to expedite the process. Additionally, SpringSource dm Server can effect an even more flexible isolation of services in an OSGi environment, preventing collisions caused by deployment of the same service with the same name without a need to use a service attribute or other discriminator.

SpringSource dm Server also allows you to bend the rules where necessary. For example, consider the application of an aspect using Spring's AOP. This might require weaving of classes, which in the case of a pointcut that matches classes deployed across multiple bundles, would prove cumbersome. SpringSource dm Server can intervene on Spring's behalf, propagating such changes across multiple bundles where necessary.

SpringSource dm Server works with four types of deployment formats. The first is a bundle, which we've discussed, and that works as you'd expect. The second is a native Java EE .war file. This is revolutionary because it provides support for out-of-the-box deployment of legacy .war–based applications. However, this format should be viewed as an intermediary step, as it loses out on many of the advantages of OSGi. Hybrid approaches are supported; a shared-library .war lets you deploy a .war whose dependencies are satisfied by the shared library. The server supports an enhanced format called a web module, which is an enhanced shared-library .war. The format removes the need for XML configuration to describe your web application to the container, relying entirely on the OSGi manifest. It, like a shared-library .WAR, can use Spring to inject OSGi services. The final format is called a platform archive. A platform archive is the ultimate form of an application. It provides the ability to group bundles together and provides application isolation. Application isolation is critical because it allows you to solve the issue of reconciliation of two services whose interfaces collide. You can use a .PAR to isolate services within the deployment unit.

SpringSource dm Server provides the robustness needed to commoditize enterprise application development in an OSGi environment, and definitely deserves a look. For a really good reference, specifically on SpringSource dm Server, I (Josh Long) would humbly recommend you investigate my co-author's in-depth treatment of the subject, Pro SpringSource dm Server, by Gary Mak and Daniel Rubio (Apress, 2009).

SpringSource's Tooling

Problem

You want to begin with SpringSource dm Server but need a way to rapidly turnaround development.

Solution

Use the SpringSource dm Server tooling available as part of SpringSource Tool Suite (STS).

How it Works

One of the best parts about dealing with OSGi, and in particular SpringSource's implementation, is that the tooling is prolific and refined. SpringSource has provided solid tooling for Eclipse, called dm Server Tools, which facilitate executing applications directly in a development environment. These tools—part of the broader SpringSource Tool Suite—are available as either a plug-in or as a stand-alone environment.

The path of least resistance, especially if you're just starting or if you plan on doing a lot of Spring development, is to download the stand-alone installation and use it, as it contains built-in support for Spring applications. We prefer the first approach, as interfacing with OSGi rarely requires more than a few minutes and rarely distracts from primary Java application development. We'll explore both approaches in this recipe.

We'll walk through installing the SpringSource Tool Suite plug-ins into an existing installation and not the individual dm Server Tools or Spring IDE. Both of these products are folded into SpringSource Tool Suite, and SpringSource Tool Suite was just recently made available for free.

Assuming you have a compatible build of Eclipse (the Eclipse Java EE developer's package is a solid start on top of which to install the tooling because it contains WTP and a lot of other useful tooling). The simplest installation mechanism is to point the update manager inside of Eclipse to the SpringSource Eclipse update site. To do this, choose Software Updates from Eclipse's Help menu and then open the Available Software tab. You can add the SpringSource update site(s) by clicking the Add Site button, and enter the following URLs (one at a time, assuming Eclipse 3.5 Galileo):

  • http://www.springsource.com/update/e3.5

  • http://dist.springsource.com/release/TOOLS/update/dependencies/e3.5

Once you enter both URLs, the Eclipse update screen will present you with two SpringSource Update Site for Eclipse 3.4 options. By choosing the top-level box, all SpringSource-related Eclipse plug-ins will be selected for download, including the dm Server Tools plug-in. Next, click the Install button to begin the installation. The next screen will prompt you to confirm your selection. Ensure that the dm Server Tools for dm Server 2.x.x is selected. Then proceed. Be aware that the installation may take quite a while, because it'll download a copy of SpringSource tc Server (the enhanced Tomcat Server) as well as dm Server and all the required Spring IDE tooling.

Summary

In this chapter, you got an introduction to OSGi, the specification as well as the Equinox platform implementation, which guarantees that certain resources are made available to plug-ins. OSGi, a module system that can be layered on top of the JVM, is important for its simplicity and powerful problem-solving abilities. You learned how to write simple raw OSGi clients and services. Remember that anything used by something else is called a service in OSGi. You then deployed the same client and service using Spring Dynamic Modules, a framework that sits on top of OSGi and is a powerful API for integration with OSGi. Spring dm Server is the OSGi-based Java server that minimizes the hassles of deploying large applications in an OSGi environment. You learned about a number of its capabilities and the four types of deployment formats with which it works. Finally, you learned how to install powerful tooling from SpringSource to support your Spring dm Server and OSGi applications.

This is the last chapter of this book. Congratulations on having learned so much about the Spring framework and surrounding projects! We hope you find this a valuable resource for years to come!

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset