`
switchlau
  • 浏览: 52800 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
最近访客 更多访客>>
社区版块
存档分类
最新评论

(转)Hello, OSGi, Part 1: Bundles for beginners

    博客分类:
  • Java
阅读更多

From JavaWorld:

This story appeared on JavaWorld at
http://www.javaworld.com/javaworld/jw-03-2008/jw-03-osgi1.html

 

 

<!-- -->

Hello, OSGi, Part 1: Bundles for beginners

Creating, executing, and managing bundles in an OSGi container

The Open Services Gateway Initiative (OSGi) defines an architecture for developing and deploying modular applications and libraries. In this first article in a three-part introduction to OSGi, Sunil Patil gets you started with OSGi development concepts and shows you how to build a simple Hello World application using the Eclipse OSGi container implementation, Equinox. He also touches briefly on building service-oriented applications using OSGi and introduces OSGi's ServiceFactory and ServiceTracker classes.

The Open Services Gateway Initiative (OSGi) , also known as the Dynamic Module System for Java , defines an architecture for modular application development. OSGi container implementations such as Knopflerfish , Equinox , and Apache Felix allow you to break your application into multiple modules and thus more easily manage cross-dependencies between them.

Similar to the Java Servlet and EJB specifications, the OSGi specification defines two things: a set of services that an OSGi container must implement and a contract between the container and your application. Developing on the OSGi platform means first building your application using OSGi APIs, then deploying it in an OSGi container. From a developer's perspective, OSGi offers the following advantages:

  • You can install, uninstall, start, and stop different modules of your application dynamically without restarting the container.
  • Your application can have more than one version of a particular module running at the same time.
  • OSGi provides very good infrastructure for developing service-oriented applications, as well as embedded, mobile, and rich internet apps.

Given that you use servlet containers for building Web applications and EJB containers for building transactional applications, you may be wondering why you need yet another type of container. The short answer is that OSGi containers are intended specifically for developing complex Java applications that you want to break up into modules. I'll expand on that short answer throughout this series.

OSGi in enterprise applications

Work on the OSGi specification was started by the OSGi Alliance in March 1999. Its main goal was to create an open specification for delivering managed services to local networks and devices. The basic idea is that once you add an OSGi Service Platform to a networked device (embedded as well as servers), you should be able to manage the lifecycle of software components in that device from anywhere in the network. Software components can be installed, updated, or removed on the fly without ever having to disrupt the operation of the device.

For years, OSGi technology has flourished in the embedded systems and network devices market. Now, thanks in part to Eclipse, OSGi is emerging as a viable and valuable technology for enterprise development.

Growing support for OSGi

In 2003, the Eclipse development team began looking for ways to make Eclipse a more dynamic rich client platform and increase the toolset's modularity. Eventually, the team settled on using the OSGi framework as a runtime component model. Eclipse 3.0, released in June of 2004, was the first version of Eclipse based on OSGi.

Almost all enterprise application servers support or plan to support OSGi . The Spring framework also supports OSGi, via the Spring Dynamic Modules for OSGi Service Platforms project, which provides an infrastructure layer to make it easier to use OSGi in Spring-based Java enterprise application development.

Open source OSGi containers

From an enterprise developer's point of view, the OSGi container has such a low footprint that you can easily embed it into an enterprise application. For example, let's say you're developing a complex Web application. You want to break the application into multiple modules: one module for the view layer, another for the DAO layer, and a third module for the data access layer. Using an embedded OSGi container to manage the cross-dependencies of these modules would enable you to update your DAO layer (say from slow DAO to fast DAO) without restarting your application.

As long as your application is compliant with the OSGi specification it should be able to run in any OSGi-compliant container. Currently, there are three popular open source OSGi containers:

  • Equinox is the reference implementation for the framework portion of the OSGi Service Platform Release 4. It is the modular Java runtime at the heart of the Eclipse IDE, and implements all of the mandatory and most of the optional features of the OSGi R4 specification.
  • Knopflerfish is an open source implementation of the OSGi R3 and OSGi R4 specifications. Knopflerfish 2 implements all the mandatory features and some of the optional features defined in the R4 specification.
  • Apache Felix is the open source OSGi container from the Apache Software Foundation. At the time of writing this container is not fully compliant with the OSGI R4 specification.

In this article we will use Equinox as our OSGi container. See the Resources section for more information about Apache Felix and Knopflerfish .

<!-- -->

Developing a Hello World bundle

In OSGi, software is distributed in the form of a bundle . A bundle consists of Java classes and other resources that deliver functions to device owners, as well as providing services and packages to other bundles. Eclipse offers excellent support for developing OSGi bundles. Not only does it provide wizards for creating OSGi bundles, it also has an embedded Equinox OSGi container that you can use to execute and debug OSGi plugins. Note that every Eclipse plug-in is essentially an OSGi bundle with some additional Eclipse-specific code. Eclipse also allows you to build standard-compliant OSGi bundles without code specific to Eclipse. In this section you'll learn how to develop a Hello World OSGi bundle using the Eclipse IDE.

Creating the bundle

Follow the steps below to create a Hello World bundle using OSGi and Eclipse.

  1. In Eclipse, click on File --> New --> Project . A New Project dialog will open.
  2. In the New Project dialog, select Plug-in Project and click Next. The Plug-in Project dialog will open.
  3. In the Plug-in Project dialog, enter the following values:
    • Project Name: com.javaworld.sample.HelloWorld
    • Target Platform: OSGi framework --> Standard
  4. Use default values for the remaining input and click Next. The Plug-in Context dialog will open.
  5. Select the default values for the Plug-in Context dialog and click Next.
  6. In the Templates dialog you'll find only one entry in Available Templates: Hello OSGi Bundle. Select it and click Finish.

Eclipse will take few seconds to generate template code for the Hello World bundle. It will create two files: Activator.java and MANIFEST.MF . We'll take a closer look at them both.

Activator.java

Your Activator.java file should look as shown in Listing 1.

Listing 1. Activator.java

package com.javaworld.sample.helloworld;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
public class Activator implements BundleActivator {
    public void start(BundleContext context) throws Exception {
        System.out.println("Hello world");
    }
    public void stop(BundleContext context) throws Exception {
        System.out.println("Goodbye World");
    }
}


If your bundle needs to be notified at the time of bundle startup or shutdown then you should create a class implementing the BundleActivator interface. Follow these rules when creating the class:

  • The BundleActivator class must have a public constructor that takes no parameters. The OSGi framework can create a BundleActivator object by calling Class.newInstance() .
  • The container will call the start() method of your Activator class to start the bundle. The bundle can take this opportunity to perform resource initialization such as getting a database connection for future use. The start() method takes one argument, the BundleContext object. This object allows bundles to interact with the framework by providing access to OSGi-container-related information. If an exception is thrown for a particular bundle the container will mark that bundle as stopped and will not put it into service.
  • The container will call the stop() method of your Activator class to report that it is shutting down a bundle. You can use this opportunity to perform cleanup tasks such as releasing the database connection.

Once your Activator class is ready you should relay its fully qualified name to the container using your MANIFEST.MF file.

MANIFEST.MF

The MANIFEST.MF file acts as deployment descriptor for your bundle. The format for this file is the same as that of a normal JAR file, so it consists of a set of headers with values. The OSGi specification defines a set of headers that you can use to describe your bundle to the OSGi container. The MANIFEST.MF file for your Hello World bundle should look as shown in Listing 2.

Listing 2. Manifest for the Hello World bundle

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: HelloWorld Plug-in
Bundle-SymbolicName: com.javaworld.sample.HelloWorld
Bundle-Version: 1.0.0
Bundle-Activator: com.javaworld.sample.helloworld.Activator
Bundle-Vendor: JAVAWORLD
Bundle-Localization: plugin
Import-Package: org.osgi.framework;version="1.3.0"


Let's take a closer look at what each of these headers is used for:

Bundle-ManifestVersion
The Bundle-ManifestVersion header tells the OSGi container that this bundle follows the rules of the OSGi specification. A value of 2 means that the bundle is compliant with OSGi specification Release 4; a value of 1 means that it is compliant with Release 3 or earlier.
Bundle-Name
The Bundle-Name header defines a short, human-readable name for the bundle.
Bundle-SymbolicName
The Bundle-SymbolicName header specifies a unique, non-localizable name for the bundle. This is the name you will use while referring a given bundle from other bundles.
Bundle-Version
The Bundle-Version header specifies the version of the bundle.
Bundle-Activator
The Bundle-Activator header specifies the name of the optional listener class to be notified of bundle start and stop events. In Listing 2 the value of this header is com.javaworld.sample.helloworld.Activator .
Bundle-Vendor
The Bundle-Vendor header contains a human-readable description of the bundle vendor.
Bundle-Localization
The Bundle-Localization header contains the location in the bundle where localization files can be found. The Hello World bundle doesn't contain any locale-specific files, but the eclipse IDE still generates this header.
Import-Package
The Import-Package header defines imported packages for the bundle. You'll learn more about this when I discuss dependency management, later in the article.

The Hello World bundle is ready, so let's execute it to see the output.

Executing a bundle

As I mentioned earlier, the Eclipse IDE has an embedded Equinox OSGi container that you can use to execute or debug OSGi bundles. Follow these steps to execute the Hello World bundle:

  1. Click on Run --> Run .
  2. Eclipse will open the dialog called "Create, manage and run configuration." In that dialog, double-click the Equinox OSGi Framework button and it will open a runtime configuration dialog box.
  3. In that dialog, change the value of the Name field to Hello World Bundle .
  4. You will notice that in the Plug-ins section under the Workspace plug-in there is an entry for the com.javaworld.sample.HelloWorld plugin, which is checked. Under Target Platform, make sure that the checkbox next to the org.eclipse.osgi plugin is also checked.Your Run dialog should look like the screenshot in Figure 1 (click to enlarge).
    A screenshot of the Equinox Run dialog in Eclipse.

    Figure 1. Create a configuration to launch the Equinox OSGi framework

  5. Now click the Run button. You should see a "Hello world" message in the IDE's console view. Note that Eclipse actually opens the OSGi console in its console view.

<!-- -->

The OSGi console

The OSGi console is a command-line interface to the OSGi container. It allows you to do things like start, stop, install bundles, and update or delete bundles. In your Eclipse IDE, click the console view to give focus to that view, then click Enter and you will get an OSGi prompt like the one shown in Figure 2 (click to enlarge).

A screenshot of the OSGi console.

Figure 2. HelloWorldActivator.java in the OSGi console

Here are some of the commonly used OSGi commands that you can use to interact with your OSGi container:

  • ss displays a list of installed bundles with the status of each bundle. It will display the bundle ID, short name, and status of the bundle.
  • start <bundleid> starts a bundle.
  • stop <bundleid> stops a bundle.
  • update <bundleid> updates a bundle with a new JAR file.
  • install <bundleURL> installs a new bundle into the OSGi container.
  • uninstall <bundleid> uninstalls already installed bundles from the OSGi container.

Note that these commands are defined in the OSGi specification so you can use them to interact with any of the OSGi containers.

Dependency management

The OSGi specification allows you to break your application into multiple modules and then manage their dependencies on each other. It does this by adding a bundle scope . By default, none of the classes in a bundle are visible from any other bundle; inside bundles they follow the normal rules of the Java language. So, what do you do if you want to access the classes of one bundle from another bundle? The solution is to export packages from the source bundle and then import them into the target bundle. In this section we'll walk through a sample application that demonstrates this concept.

First, we will create a com.javaworld.sample.HelloService bundle, which will export a package. Then we will import the package into our com.javaworld.sample.HelloWorld bundle.

Exporting a package

We'll start by creating the com.javaworld.sample.HelloService bundle and exporting a package from it. Follow these steps to create the bundle and export the package:

  1. Create the com.javaworld.sample.HelloService bundle by following the same steps used to create the com.javaworld.sample.HelloWorld bundle in the previous section.
  2. Inside the HelloService bundle, create a com.javaworld.sample.service.HelloService.java interface, as shown in Listing 3.

    Listing 3. HelloService.java

    public interface HelloService {
        public String sayHello();
    }
    
    
    
  3. Now create a com.javaworld.sample.service.impl.HelloServiceImpl.java class implementing the HelloService interface, as shown in Listing 4.

    Listing 4. HelloServiceImpl.java

    public class HelloServiceImpl implements HelloService{
        public String sayHello() {
            System.out.println("Inside HelloServiceImple.sayHello()");
            return "Say Hello";
        }
    }
    
    
    
  4. Open the MANIFEST.MF for the HelloService package in your Eclipse Manifest editor and go to the Runtime tab. In the Exported Packages section, click Add and select the com.javaworld.sample.service package. The MANIFEST.MF file for the HelloService bundle should look like the one in Listing 5.

    Listing 5. Manifest for HelloService bundle

    Manifest-Version: 1.0
     Bundle-ManifestVersion: 2
     Bundle-Name: HelloService Plug-in
     Bundle-SymbolicName: com.javaworld.sample.HelloService
     Bundle-Version: 1.0.0
     Bundle-Vendor: JAVAWORLD
     Bundle-Localization: plugin
     Export-Package: com.javaworld.sample.service
    
    
     Import-Package: org.osgi.framework;version="1.3.0"
    
    
    

As you can see, the MANIFEST.MF file for the HelloService bundle looks very similar to that of the HelloWorld bundle. The only difference is that this MANIFEST.MF file has one Export-Package manifest header, whose value is com.javaworld.simple.service .

The Export-Package manifest header informs the OSGi container that classes in the com.javaworld.sample.service package from the HelloService bundle can be accessed from outside. Note that in the sample code we have exposed a HelloService interface but not the HelloServiceImpl implementation class.

Importing a package

The next step is to update the HelloWorld bundle to import the com.javaworld.simple.service package. Here are the steps to import the package:

  1. In the com.javaworld.sample.HelloWorld bundle, open the MANIFEST.MF file in the Plug-in Manifest editor. Now go to the Dependencies tab, and then to Imported Packages . Add com.javaworld.sample.service as the value of Imported Packages. The MANIFEST.MF file for your HelloWorld bundle should look like the one in Listing 6.

    Listing 6. Manifest for the updated HelloWorld bundle

    Manifest-Version: 1.0
    Bundle-ManifestVersion: 2
    Bundle-Name: HelloWorld Plug-in
    Bundle-SymbolicName: com.javaworld.sample.HelloWorld
    Bundle-Version: 1.0.0
    Bundle-Activator: com.javaworld.sample.helloworld.Activator
    Bundle-Vendor: JAVAWORLD
    Bundle-Localization: plugin
    Import-Package: com.javaworld.sample.service,
     org.osgi.framework;version="1.3.0"
    
    
    
    
    
    

    As you can see, the value of the Import-Package header is a comma-separated list of packages that this bundle wants to import. In the sample code the HelloWorld bundle imports two packages: com.javaworld.sample.service and org.osgi.framework .

    The org.osgi.framework package contains OSGi framework classes such as BundleContext and BundleActivator , which are used by the Activator.java class of the HelloWorld bundle.
  2. Next, open com.javaworld.sample.helloworld.Activator.java in the Eclipse Java editor. You will notice that you are now able to access the HelloService interface but not the HelloServiceImpl class. This is because the HelloService package exports (and the HelloWorld package imports) the com.javaworld.sample.service package. HelloServiceImpl is an internal class for the HelloService bundle and no other bundle can access it.

<!-- -->

Class-level scope

If you try running the sample service package now it will print "Hello World" on your Eclipse console. If you try running Activator.java to access HelloServiceImpl.java and compile it with the normal javac complier, it will compile. If you try to execute this bundle in an OSGi container, however, it will throw an exception.

How is the OSGi container able to hide a few classes from the .jar file while others are visible? The answer is that the OSGi container uses the Java class loader to manage class visibility. The OSGi container creates a different class loader for every bundle. The bundle can therefore access classes from

  • Boot classpath : Contains the java.* packages.
  • Framework classpath : Usually has a separate class loader for the framework implementation classes as well as key service interface classes.
  • Bundle space : Consists of the JAR file that is associated with the bundle plus any additional JARs that are closely tied to the bundle, like fragments.
  • Imported packages : For instance, the HelloWorld bundle imports the com.javaworld.sample.service package so it can access classes from that package.

The bundle-level scope is a powerful feature allowing you (for instance) to safely change the HelloServiceImpl.java class without worrying that dependent code might break.

OSGi services

As previously mentioned, the OSGi architecture is a very good candidate for implementing service-oriented applications. It allows bundles to export services that can be consumed by other bundles without knowing anything about the exporting bundle. Taken with the ability to hide the actual service implementation class, OSGi provides a perfect combination for service-oriented applications.

In OSGi, a source bundle registers a POJO (you don't have to implement any interfaces or extend from any superclass) with the OSGi container as a service under one or more interfaces. The target bundle can then ask the OSGi container for services registered under a particular interface. Once the service is found, the target bundle binds with it and can start calling its methods. As with other OSGi concepts, a sample application will make all of this more clear.

Exporting services

In this section we will change the HelloService bundle so that it exports objects of the HelloServiceImpl.java class as a service. Here are the steps to set up the sample application:

  1. Change the MANIFEST.MF for com.javaworld.sample.HelloService to import the org.osgi.framework package.
  2. Create the com.javaworld.sample.service.impl.HelloServiceActivator.java as shown in Listing 7.

    Listing 7. Create HelloServiceActivator.java

    public class HelloServiceActivator implements BundleActivator  {
        ServiceRegistration helloServiceRegistration;
        public void start(BundleContext context) throws Exception {
            HelloService helloService = new HelloServiceImpl();
            helloServiceRegistration =context.registerService(HelloService.class.getName(), helloService, null);
        }
        public void stop(BundleContext context) throws Exception {
            helloServiceRegistration.unregister();
        }
    }
    
    
    

    Note that the source bundle should use the BundleContext.registerService() method to export the service. It takes three parameters:
    • The name of the interface under which you want to register the service. If you want to register the service under multiple interfaces then you should create a String array of interface names and pass it as your first argument. In the sample code we want to export the service under the name of HelloService interface.
    • The actual Java object that you want to register as a service. In our sample code we are exporting objects of the HelloServiceImpl class as the service.
    • Properties of the service, in this case a Dictionary object. If more than one bundle exports a service under the same interface name then the target object can use these properties to filter out the service that it is interested in.
  3. The last step is to change the MANIFEST.MF file of the HelloService bundle to declare HelloServiceActivator as the bundle's activator class. To do that, simply add com.javaworld.sample.service.impl.HelloServiceActivator as the value of the Bundle-Activator header in your MANIFEST.MF file.

Now the HelloService bundle is ready to export objects of the HelloServiceImpl class. When the OSGi container starts the HelloService bundle it will pass control to HelloServiceActivator.java , which will register an object of HelloServiceImpl as a service. The next step is to create the service consumer.

Importing the service

In this section we will change the HelloWorld bundle developed in the last section so that it acts as a consumer of the HelloService service. The main thing you need to do is change the Activator.java for the HelloWorld bundle as shown in Listing 8.

Listing 8. HelloWorldActivator.java

public class Activator implements BundleActivator {
    ServiceReference helloServiceReference;
    public void start(BundleContext context) throws Exception {
        System.out.println("Hello World!!");
        helloServiceReference= context.getServiceReference(HelloService.class.getName());
        HelloService helloService =(HelloService)context.getService(helloServiceReference);
        System.out.println(helloService.sayHello());

    }
    public void stop(BundleContext context) throws Exception {
        System.out.println("Goodbye World!!");
        context.ungetService(helloServiceReference);
    }
}


The BundleContext.getServiceReference() method returns a ServiceReference object for a service registered under the HelloService interface. If multiple such services exist, the service with the highest ranking (as specified in its Constants.SERVICE_RANKING property) is returned. Once you have the object of ServiceReference you can call its BundleContext.getService() method to get the actual service object.

You can run this sample the same way you would execute any bundle, by clicking Run --> Run Simply make sure that both the HelloWorld and HelloService bundles are checked in as plugins. When you start the HelloService bundle, you will see the message "Inside HelloServiceImple.sayHello() " printed from the HelloServiceImpl.sayHello() method.

<!-- -->

Creating a service factory

In the last section you learned how to use the OSGi framework to create a Java object and register it as service to be consumed by any other bundle. If you look at the HelloServiceActivator.start() method you will notice that we created an object of the HelloServiceImpl class in the start method and registered it under the name of HelloService interface. Thereafter, whenever any bundle asks for the HelloService service, the OSGi container will return the same object.

This implementation will work for most common use cases. But let's say you want to return a different object of the HelloServiceImpl class for every consumer bundle. Alternately, let's say your service object needs to open a connection to a database and you don't want to open the connection unless someone really needs the service.

In either case, the solution is to create a class implementing the ServiceFactory interface and register its object, instead of the actual service object, as a service. Once you do that, your ServiceFactory class will take control whenever any bundle requests the service. ServiceFactory will create a new object of Service for every bundle, and will also delay creation of the actual service until someone really needs it.

Follow these steps to change the implementation of the com.javaworld.sample.HelloService bundle developed in the last section to use a ServiceFactory :

  1. Create the factory classHelloServiceFactory.java , as shown in Listing 9.

    Listing 9. Create HelloServiceFactory.java

    public class HelloServiceFactory implements ServiceFactory{
        private int usageCounter = 0;
        public Object getService(Bundle bundle, ServiceRegistration registration) {
            System.out.println("Create object of HelloService for " + bundle.getSymbolicName());
            usageCounter++;
            System.out.println("Number of bundles using service " + usageCounter);
            HelloService helloService = new HelloServiceImpl();
            return helloService;
        }
        public void ungetService(Bundle bundle, ServiceRegistration registration, Object service) {
            System.out.println("Release object of HelloService for " + bundle.getSymbolicName());
            usageCounter--;
            System.out.println("Number of bundles using service " + usageCounter);
        }
    }
    
    
    

    The ServiceFactory interface defines two methods:
    • getService() : The OSGi framework invokes this method the first time the specified bundle requests a service object using the BundleContext.getService(ServiceReference) method. In Listing 9, we use this method to create a different object of HelloServiceImpl for every bundle, and we return that object. The OSGi framework caches the value returned (unless it is null), and will return the same service object on any future calls to BundleContext.getService() from the same bundle.
    • ungetService() : The OSGi container invokes this method when a service has been released by a bundle. The service object may then be destroyed. In Listing 9, we use this method to reduce the usageCount of the service and print the number of clients for the service.
  2. Change HelloServiceActivator.java and modify the start() method of your activator so that it will register objects of ServiceFactory instead of HelloService , as shown in Listing 10:

    Listing 10. Changes to HelloServiceActivator.java

    public class HelloServiceActivator implements BundleActivator  {
        ServiceRegistration helloServiceRegistration;
        public void start(BundleContext context) throws Exception {
            HelloServiceFactory helloServiceFactory = new HelloServiceFactory();
            helloServiceRegistration =context.registerService(HelloService.class.getName(), helloServiceFactory, null);
        }
        public void stop(BundleContext context) throws Exception {
            helloServiceRegistration.unregister();
        }
    }
    
    
    

Now try running this sample code. You should notice that it prints the service usage count as one (1) when HelloWorld bundle is started and zero (0) when the HelloWorld bundle is stopped.

Tracking services

In the "OSGi services" section you learned how to search for a service using its interface name. But what happens if more than one bundle registers a service under the same interface name? In that case the OSGi container will return the service with the highest ranking -- that is, the service that is registered with the highest valued SERVICE_RANKING property. If more than one service has an equally valued SERVICE_RANKING property, then the OSGi container will return the service with the lowest PID.

But let's say that you are creating a consumer that needs to know whenever an object is registered or unregistered under a particular interface. In this situation, you should use the ServiceTracker class. Let's see what happens when we change the sample code to utilize a service tracker, as described below.

  1. Change the MANIFEST.MF for your HelloWorld bundle to import the org.osgi.util.tracker package.
  2. Create HelloServiceTracker.java as shown in Listing 11.

    Listing 11. HelloServiceTracker.java

    public class HelloServiceTracker extends ServiceTracker {
        public HelloServiceTracker(BundleContext context) {
            super(context, HelloService.class.getName(),null);
        }
        public Object addingService(ServiceReference reference) {
            System.out.println("Inside HelloServiceTracker.addingService " + reference.getBundle());
            return super.addingService(reference);
        }
        public void removedService(ServiceReference reference, Object service) {
            System.out.println("Inside HelloServiceTracker.removedService " + reference.getBundle());
            super.removedService(reference, service);
        }
    }
    
    
    

    As you can see in the constructor of the HelloServiceTracker class, we are passing the name of the HelloService interface to its super class, which is the equivalent of saying that HelloServiceTracker should track services registered under the HelloService interface name. The HelloServiceTracker class extends the ServiceTracker class and implements two methods:
    • addingService() is called when a bundle registers a service under the given interface name.
    • removedService() is called when a bundle unregisters a service under the given interface name.
  3. Change Activator.java so that it starts using the HelloServiceTracker class to manage services instead of looking them up directly, as shown in Listing 12.

    Listing 12. Activator.java uses HelloServiceTracker

    public class Activator implements BundleActivator {
        HelloServiceTracker helloServiceTracker;
        public void start(BundleContext context) throws Exception {
            System.out.println("Hello World!!");
            helloServiceTracker= new HelloServiceTracker(context);
            helloServiceTracker.open();
            HelloService helloService = (HelloService)helloServiceTracker.getService();
            System.out.println(helloService.sayHello());
    
        }
        public void stop(BundleContext context) throws Exception {
            System.out.println("Goodbye World!!");
            helloServiceTracker.close();
        }
    }
    
    
    

    In the initial start() method we first create a HelloServiceTracker object, then we ask HelloServiceTracker to start tracking the underlying service. A call to getService() will now get the HelloService object.

If you try executing this sample you will notice that whenever you start or stop the HelloService bundle it will result in a call to either the addingService() or removedService() method of the HelloServiceTracker object.

In conclusion

In this first article in the three-part Hello, OSGi series, I've introduced you to the basic concepts of modular application development with OSGi. You've learned about the three currently available open source OSGi containers and walked through the steps to develop a simple component bundle using Equinox, the fully OSGi-compliant Eclipse container. You've also learned how bundles can interact by importing and exporting each other's packages and services.

In this article you may have noticed one of the challenges of developing OSGi bundles: that each of your bundles needs to be aware of OSGi AP. In some development scenarios this could mean writing a lot of infrastructure code. In the next article in the Hello, OSGi series I'll introduce you to the Spring Dynamic Modules for OSGi Service Platforms project, which simplifies development of Spring-based OSGi bundles. See the Resources section in the meantime, to learn more about OSGi .

About the author

Sunil Patil is a Java Enterprise/Portlet developer working for Ascendant Technology in San Francisco, California. He is the author of Java Portlets 101 (SourceBeat, April 2007) and has written numerous articles published by O'Reilly Media. Sunil was a member of IBM's WebSphere Portal Server development team for three years and is actively involved in the Pluto community. In addition to being an IBM Certified WebSphere Portal Server Application Developer for both v5.0 and v5.1, he is a Sun Microsystems Certified Java Programmer, a Web component developer, and a business component developer. You can view Sunil's blog at http://jroller.com/page/SunilPatil .

All contents copyright 1995-2008 Java World, Inc. http://www.javaworld.com

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics