Chapter 4. Spring Dynamic Modules for OSGi

Though you've already taken the Spring Dynamic Modules for OSGi (Spring-DM) for a test run in the last chapter, there is much more to be learned about the way this Spring subproject operates. In this chapter we will take the first big dive through the core parts that compromise Spring-DM.

You will likely come back here for future reference, since many of the remaining chapters that deal with more specific Spring-DM areas build on the concepts explained in the coming pages.

Extenders and Fragments in Spring-DM

Extenders and fragments are central pieces in Spring-DM. Though the terms sound somewhat esoteric, they really aren't, especially when you consider that you've already used one approach in the introductory Hello World Spring-DM application in Chapter 3.

The extender model[13] refers to the process of a bundle scanning another bundle's contents and performing an action on the scanned bundle's behalf. In the particular case of Spring-DM, the extender model signifies that when a certain extension is present in an OSGi manifest or a bundle's contents, Spring-DM should automatically trigger a chain of events.

The chain of events or action in Spring-DM is simple. In fact there is only one type of event: creating a Spring context, one that will serve a bundle throughout its life cycle for managing any Spring-related artifacts a bundle may possess, including a context that is designed around the special class type OsgiBundleXmlApplicationContext.

Any bundle deployed into an OSGi environment running Spring-DM will always be inspected for the presence of a Spring-DM trigger point. If such a trigger point is found, a bundle will automatically be assigned a Spring context of the OsgiBundleXmlApplicationContext class. If, on the other hand, no Spring-DM trigger point is found in the bundle, Spring-DM logging will show the message "No application context created for bundle <bundle_name>"; scanning is still performed, but since no trigger point is found, no Spring context is created for the bundle.

In Spring-DM there are two types of extenders, those applicable to bundles using standard Spring artifacts, and those having to do with bundles using Spring web artifacts. The differences are subtle, but nevertheless very important, since in the web-bound case it implies the underlying bundle needs to be deployed as a web application.

But let's not digress just yet on these subtleties; let's explore the actual extensions in Spring-DM. Table 4-1 lists Spring-DM's extensions and the default trigger points that invoke the creation of a Spring OsgiBundleXmlApplicationContext context for a bundle.

Table 4-1. Spring-DM Default Triggers for Creating Spring Context

Trigger Point[a]

Notes

[a]

Spring-DM Core Extender

 

/META-INF/spring/*.xml

One or more XML files inside a bundle's META-INF/spring directory initiate the creation of a Spring context.

Spring-Context manifest value

This allows more granular control over the properties assigned to a Spring context. Table 4-2 contains such values.

Spring-DM Web Extender

 

.war bundle extension

The presence of the .war extension to package a bundle indicates that it will be deployed as a web application.

[a] CAUTION: It's critical to note that the corresponding Spring-DM extender bundlesspring-osgiextender. jar and spring-osgi-web-extender.jarneed to be running in a system in order for these triggers to be detected.

As you can now appreciate, you've already made use of the first and third type of Spring-DM trigger points when you placed Spring application descriptors inside the /META-INF/spring directory and made use of a .war extension in the introductory Spring-DM application in Chapter 3.

There is, however, a more powerful Spring-DM extender trigger point, one that allows you to override the default behaviors used to create a Spring application context and indicate alternative locations in which to locate Spring application descriptors. This trigger point comes in the form of a special OSGi manifest value named Spring-Context, which has the highest precedence of any Spring-DM trigger.

Table 4-2 describes the values available for the Spring-Context header, which has a syntax in the form Spring-Context:<alternate_spring_context_configuration_files><configuration_properties>.

Table 4-2. Spring-Context OSGi Header Values

Value

Description

Default Value

Example

<alternate_
spring_context_
configuration_
files><alternate_
spring_context_
configuration_
files>

Indicates a comma-separated list of bundle locations or files in which Spring-DM should attempt to locate Spring configuration files to build its context

Bundle-Context:*; Spring-Context:*; (meaning inspect the default Spring-DM location— /META-INF/spring/—for Spring configuration files)

Spring-Context:config/mycontext.xml; (meaning build a context from the Spring configuration file located in config/mycontext.xml)

create-
asynchronously

Indicates the creation pattern—asynchronous or synchronous—for initializing Spring's context

Spring-Context:*; create-asynchronously: = true; (meaning create a context asynchronously with configuration files in the default location)

Spring-Context:*; create-asynchronously:=false; (meaning create a context synchronously with configuration files in the default location)

wait-for-
dependencies

Specifies whether to wait for any service dependencies to be fulfilled before a Spring context is created

Spring-Context:*;wait-for-dependencies:=true; (meaning create a Spring context until all service dependencies have been fulfilled)

Spring-Context: config/*.xml; wait-for-dependencies:=false; (meaning create the context from files located under a bundle's config directory, without waiting for service dependencies to be fulfilled)

timeout

Indicates the time to wait (in seconds) for dependencies to be fulfilled, prior to giving up on the creation of a Spring context (Note: If wait-for-dependencies is false, this value is ignored.)

Spring-Context:*; timeout:=300; (meaning wait 5 minutes before giving up on locating dependencies and building the Spring context)

Spring-Context:*;timeout:=60; (meaning wait 1 minute before giving up on locating dependencies and building the Spring context)

publish-
context

Specifies whether to publish the Spring context to the OSGi registry

Spring-Context:*; publish-context:=true; (meaning publish the actual Spring context as a service in the OSGi registry)

Spring-Context:config/*.xml;publish-context:= false; (meaning create the context from files located under a bundle's config directory, and don't publish the Spring context as a service in the OSGi registry)

While Table 4-2 presents the various values that can be overridden for creating a bundle's Spring context, you should be aware of certain design implications these values have. The following list contains a more exhaustive look at each option:

  • Alternative context configuration files: If you're not keen on placing configuration files for Spring's context inside a bundle's /META-INF/spring directory, you are allowed to define alternative bundle locations from which a Spring context should take its configuration values. Note: If you define alternative configuration locations through Spring-Context, the default /META-INF/spring directory is ignored, unless explicitly specified.

  • Asynchronous vs. synchronous behavior: By default, asynchronous behavior is used to instantiate a Spring context, allowing the generation to take place without blocking OSGi's event thread. Specifying synchronous behavior blocks OSGi's event thread until the creation of a bundle's Spring context is terminated. Though this behavior is often merited if a bundle has many Spring artifacts needed by other bundles, it's discouraged given its potential for deadlocks with bundles having interdependencies.

  • Dependency waiting: This refers to whether the creation of a Spring context should await the resolution of OSGi services specified in Spring configuration context files. By default, Spring-DM always awaits dependency resolution. Further note that since asynchronous behavior is used by default when creating a Spring context, waiting for dependent services never locks a system.

  • Timeout: The timeout value is used to set the timeout period before Spring-DM gives up on the localization of mandatory OSGi services and reports a failure creating a Spring context. In cases where Spring-DM bundles depend on services that are deployed in the same batch of bundles, or are services that take considerable time to be bootstrapped and registered, it's recommended to increment Spring-DM's default timeout.

  • Context publication: Though a bundle's Spring context is always published as a service in OSGi's central registry, you may opt to avoid this process, thereby requiring context values to always be accessed through individually published services and not through the context itself.

With this I conclude describing the subject of Spring-DM extenders used to create Spring contexts. The remainder of this chapter will focus on the Spring configuration files associated with a bundle's context, which are primarily used for registering and locating services in OSGi's central registry. But before doing so, there is one more high-level OSGi concept worth elaboratingon: fragments.

A fragment's purpose in OSGi was originally to support internationalization (i18n) by allowing a bundle to introduce different country locales at deployment time, and thus avoiding the need to have multiple localized versions of the same bundle. In essence, a fragment is a bundle that is attached to a host bundle and is treated as part of the host, including any permitted headers.

This makes fragments an ideal solution for situations when a bundle's internal logic can't be modified or when a complete bundle upgrade is not an option. However, while a fragment is itself a bundle, there are certain limitations to using them in an OSGi environment.

For starters, a fragment can only add configuration information, classes, or resources to a host bundle; it cannot, however, have its own activator class or class loader like any standard bundle, giving fragments a second-class-citizen nature in OSGi. Nevertheless, they do provide an important function in Spring-DM, as will be illustrated at the end of this chapter in the section "OSGi fragments with Spring-DM" and in other sections of the book.

The way in which a fragment bundle is attached to a bundle is by means of an OSGi manifest header: Fragment-Host. If an OSGi environment encounters such a value at deployment time, it will immediately recognize it is dealing with a fragment bundle, and will attempt to attach the fragment in question to a host bundle, all based on matching the value specified in Fragment-Host to a host bundle's symbolic name.

In this manner, say you wanted to attach a fragment bundle to a bundle with a symbolic name com.apress.osgi.ch4.service. The way you would go about this process is by creating an OSGi bundle in the regular fashion and adding the OSGi manifest value Fragment-Host:com.apress.osgi.ch4.service; in this way the bundle would automatically become a fragment of the former bundle at deployment time. Note that a bundle's symbolic name is specified using the OSGi manifest header Bundle-SymbolicName.

Next, we will move on to exploring Spring-DM's process for registering services in OSGi's central registry, services that are made up of Spring artifacts created once a bundle's context is instantiated, and which will be made available to other OSGi bundles running in a system.

Registering OSGi Services Through Spring-DM

You can forget about the programmatic process of registering OSGi services illustrated in Chapter 1. Though programmatic registration is still an option in Spring-DM, the preferred process is using Spring context definitions, which are executed at the time a bundle's Spring context is created and are taken from Spring-DM's predefined or default trigger point locations.

In the last section, you learned that Spring-DM automatically processes any XML file located under a bundle's /META-INF/spring/ directory. It turns out that located here are not only standard Spring configuration files containing beans and other artifacts that are eventually placed in a bundle's context, but also specific Spring-DM configuration files needed to register these same Spring artifacts as OSGi services.

Much like other Spring descriptors containing bean definitions, the process for registering OSGi services relies on the use of a specific namespace declared in the root element of an XML configuration file, which is illustrated in Listing 4-1.

Example 4-1. Spring-DM osgi Namespace Used in Spring Configuration Files

<beans:beans
      xmlns="http://www.springframework.org/schema/osgi"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns:beans="http://www.springframework.org/schema/beans"
      xsi:schemaLocation="http://www.springframework.org/schema/osgi http://www.s
Spring-DM osgi Namespace Used in Spring Configuration Files
pringframework.org/schema/osgi/spring-osgi.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema
Spring-DM osgi Namespace Used in Spring Configuration Files
/beans/spring-beans.xsd"> <!-- OSGi service registration statements --> </beans:beans>

Listing 4-1 demonstrates the use of Spring-DM's osgi namespace as a default namespace within a Spring configuration file, with the top-level beans namespace being further qualified through the beans prefix. Though you could easily add any other Spring namespace to support many more Spring artifacts in the same configuration file, it's a recommended practice to create separate configuration files for values pertaining to Spring and those for Spring-DM.

Given these conventions, having the Spring configuration files module-context.xml and osgi-context.xml inside a bundle's /META-INF/spring directory is standard practice. This process works because Spring-DM's extender automatically processes every file present in this last directory. Note that the naming convention used in these configuration files is open-ended, with each and every file with an .xml extension independent of its name being processed if it's present in a bundle's /META-INF/spring directory. See Table 4-2 on the use of Spring-Context to override this location.

Now that you are aware of the primary OSGi namespace used in Spring-DM configuration files, let's take a look at one of its first elements. Listing 4-2 contains an example of the service element used to register services.

Example 4-2. Basic Registration of an OSGi Service in Spring-DM

<service ref="serviceBean" interface="com.apress.springosgi.FlightService"/>

This is the simplest declaration for registering a service in OSGi's central registry using Spring-DM. This statement registers a Spring bean with the ID serviceBean and associates its access through the com.apress.springosgi.FlightService interface.

In this case, it should be evident that in order for this process to take place, a bean with an ID value of serviceBean should be created using the traditional Spring approach and available in a bundle's Spring context. Additionally, the corresponding interface should also be available either in the bundle itself or for import from another bundle running in the system.

Even though this last service declaration implies the use of an interface to register a Spring bean's logic in an OSGi registry, you can also use an actual class representing a bean inside the interface attribute. However, be advised that this requires the use of CGLIB (Code Generation Library)[14] in a bundle in order to generate the corresponding interfaces at runtime—a process that may not work under certain circumstances, so it's best to use explicit interfaces whenever possible.

Under the hood, this Spring-DM registration process also has a few characteristics worth mentioning: a service is always registered with the property org.springframework.osgi.bean.name set to the value corresponding to the reference bean value, ref, and the defined bean itself is a ServiceRegistration object of the type org.osgi.framework.ServiceRegistration.

These are of course the basics behind the <service> element. Other variations allow more finer-grained registration processes to take place. Listing 4-3 illustrates one such variation used to register a multiple-interface service in Spring-DM.

Example 4-3. Multiple-Interface Registration of an OSGi Service in Spring-DM

<service ref="serviceBean">
  <interfaces>
      <value>com.apress.springosgi.FlightService</value>
      <value>com.apress.springosgi.InFlightOperations</value>
      <value>com.apress.springosgi.GroundCrewOperations</value>
   </interfaces>
</service>

Since OSGi operates on the premise of interfaces, and Spring-DM creates a proxy via a ServiceRegistration object, which in turn delegates to the Spring bean itself. Some actions in a Spring bean may be inaccessible using a single interface. A multiple interface registration allows a service to expose operations contained in various interfaces that may belong to a backing Spring bean; though for the moment multiple interface registration may not seem significant, it will become so once you learn the lookup process for registered services. Figure 4-1 illustrates this concept.

Spring-DM proxy exposing service interface(s) for backing a Spring bean

Figure 4-1. Spring-DM proxy exposing service interface(s) for backing a Spring bean

Additionally, on the same subject of published interfaces, Spring-DM also provides autodetection of interfaces through the use of the auto-export attribute. Table 4-3 contains the various values available for this <service> element attribute.

Table 4-3. Spring-DM auto-export Attribute Values for the <service> Element

auto-export Value

Behavior

disabled

(Default value) Indicates that no interface auto-detection will take place. Instead Spring-DM will rely on the use of an interface or interfaces declaration.

interfaces

Registers a service using the interfaces implemented by a bean.

class-hierarchy

Registers a service using its class and supertypes (if any).

all-classes

Registers a service using its class, supertypes (if any), plus all implemented interfaces by a bean.

Table 4-4 shows a grid with the different auto-export values and the service registration behaviors these values produce on a series of interface/class hierarchies.

While the use of auto-export facilitates the registration of services, you should be aware that there is a reason why this attribute is disabled by default. The main drawback to using autodetection is that it may unintentionally expose operations not intended to be registered or lack the proper registration of operations if the correct level is not chosen.

Table 4-4. Spring-DM auto-export Registration Behaviors for Different Interface/Class Hierarchies

Interface/Class Hierarchy

Disabled

Interfaces

class-hierarchy

all-classes

Stand-alone Interface A

None

Registers Interface A

None

Registers Interface A

Interface B extends Interface A

None

Registers Interface A and Interface B

None

Registers Interface A and Interface B

Stand-alone Class A

None

None

Registers Class A

Registers Class A

Class B extends Class A

None

None

Registers Class A and Class B

Registers Class A and Class B

Class C implements Interface B and extends Class B

None

Registers Interface A and Interface B

Registers Class C, Class B, and Class A

Registers Class C, Class B, Class A, and Interface A and Interface B

If you look at the grid illustrated in Table 4-4, you will note that the use of different auto-export values produces varying registration results depending on the underlying interface/class hierarchy used by a bean. For this reason, using explicit interface declarations is the preferred method since it provides much tighter control over what is exposed via OSGi's central registry.

Moving along to another <service> element variation, Spring-DM also supports the use of multiple service properties, this in addition to the default property assigned to a service via its reference name. Service properties, of course, become essential once a service needs to be located in an OSGi registry; nonetheless, they need to be declared at the moment a service is registered. Listing 4-4 illustrates how to associate additional service properties in Spring-DM.

Example 4-4. Additional Service Properties Used in the Registration of an OSGi service in Spring-DM

<service ref="serviceBean" interface="com.apress.springosgi.FlightService">
 <service-properties>
    <beans:entry key="flight" value="ACMEAirlines"/>
    <beans:entry key="aports" value-ref="airportsBean"/>
 </service-properties>
</service>

In this listing, besides including the default serviceBean property created by Spring-DM, two more properties are declared using Spring's <entry> bean—notice the beans: prefix indicating these properties are not the default Spring-DM namespace used by <service>. The first is a service property in the form of a string using the value attribute, and the second a service property in the form of a Spring bean using the value-ref attribute, with both properties possessing a corresponding key for later reference.

It should be noted that the statements inside <service-properties> are not performing Dependency Injection (DI) like most nested declarations inside Spring declarations. The use of Spring's <entry> statements inside <service-properties> are just that, properties used to filter a service at the time it's looked up. The use of filtering and service lookup is addressed in the next section of the chapter.

On certain occasions, besides adding properties to a service that will be used in other bundles, you may need to reference a service locally for the purpose of DI. This allows the service to be used in some other Spring artifact declared in the same configuration file or Spring-DM context. Under these circumstances, you would go with the standard Spring practice of using an id attribute. Listing 4-5 shows this scenario.

Example 4-5. Registration of OSGi Service in Spring-DM with ID for Further Reference

<service ref="serviceBean" id="flightServiceDM" interface="com.apress.springosgi.F
Registration of OSGi Service in Spring-DM with ID for Further Reference
lightService"/>

This statement will make the service bound to the reference serviceBean Spring bean available under a value of flightServiceDM, making it further available for injection in other Spring constructs used in the same application context or configuration file; note that the id in this case will correspond to a ServiceRegistration object of the type org.osgi.framework.ServiceRegistration.

Using a reference for a service exported by the same bundle can cause application context creation to fail, due to either deadlock or timeout. Such behaviors—if presented—can be solved by overriding Spring-DM's default context characteristics using Spring-DM's directive Spring-Context presented earlier in Table 4-2.

The <service> element also allows a service to be registered using an anonymous bean. Instead of using the ref attribute as in all the previous listings to associate a backing Spring bean to an OSGi service, you could use an anonymous bean as illustrated in Listing 4-6.

Example 4-6. Registration of an OSGi Service in Spring-DM Using an Anonymous Bean

<service interface="com.apress.springosgi.FlightService">
   <bean:bean class="com.apress.springosgi.FlightServiceDAO">
   </bean>
</service>

As you can see, anonymous beans simply provide a shortcut for linking a bean to a service, and this is the preferred approach when a bean instance will be of use to one and only one service.

Another variation to the <service> element, which given the asynchronous nature of Spring-DM can prove to be essential, is the depends-on attribute. As its name implies, depends-on is used to indicate prerequisite elements needed before registering a service, ensuring that any explicit bean dependencies required by a service are fully constructed prior to registering a service. Listing 4-7 shows the use of this attribute.

Example 4-7. Spring-DM depends-on Attribute Used in Registration of an OSGi Service

<service ref="serviceBean" interface="com.apress.springosgi.FlightService"
Spring-DM depends-on Attribute Used in Registration of an OSGi Service
depends-on="groundCrewBean"/>

Further adding to the <service> element's attributes we find ranking, whose value is used to indicate a priority grade among OSGi services. The ranking attribute, which takes an integer value, is used as a qualifier when two or more services possessing the same interfaces are looked up in OSGi's central registry. Under such circumstances, an OSGi registry will return whatever service was registered with the highest ranking value.

The ranking attribute is fully supported according to the OSGi specification. But generally speaking, when it's known that two or more services will be registered using the same interface, a more robust approach would be to use service properties—as outlined in Listing 4-4.

Continuing to explore the <service> element, you'll find the context-class-loader attribute, which is used to define the visibility available through a class loader. By default, the context-class-loader attribute in a <service> element has a value of unmanaged, indicating that only those resources available in a class loader will be utilized.

The relevance to altering context-class-loader's default value to that of service-provider—which is the other available value—arises when a service makes special use of resources that may become invisible to a consuming bundle given OSGi's more stringent class-loading approach. By using the service-provider value, Spring-DM ensures that the consuming bundle has full access to all the resources available in the host bundle—the one providing the service—without the consuming bundle requiring extra provisions.

Finally, on the matter of registering services in Spring-DM, we will discuss two more subjects, one related to the way backing Spring beans are created in Spring-DM, and the other to the actual registration and unregistration phases undergone by a Spring-DM service.

By default, all backing Spring beans supporting an OSGi service are created with a global scope, global in the sense that there is only one bean instance for all clients making use of a service. In order to support a more granular approach though, Spring-DM also provides access to the widely known Factory pattern used in enterprise software.

In essence, what the Factory pattern in Spring-DM provides is a way to associate an individual Spring bean instance to each client bundle accessing an underlying service. In order to use this technique, a Spring bean needs to be scoped within a bundle, as illustrated in Listing 4-8.

Example 4-8. Spring-DM Bundle-Scoped Bean Used in Registration of an OSGi Service

<bean:bean id="serviceBean" scope="bundle" class="com.apress.springosgi.Flight
Spring-DM Bundle-Scoped Bean Used in Registration of an OSGi Service
ServiceImpl"/> <service ref="serviceBean" interface="com.apress.springosgi.FlightService"/>

Notice how the underlying Spring bean used within the <service> statement employs the attribute scope="bundle". Under this scenario, a Spring bean instance would be created for each client bundle accessing a service, with the same bean being destroyed once a client bundle is stopped.

While we're on the subject of creating and destroying artifacts, Spring-DM also offers hooks into the standard OSGi listeners used to execute instructions when a service is registered and unregistered. Registration and unregistration of services is linked to the activation and stoppage of bundles, which are two of the life-cycle states an OSGi bundle goes through; OSGi's bundle life cycle is described in Chapter 1 and illustrated in that chapter's Figure 1-2.

Providing such support is the <registration-listener> element, which needs to be nested within a <service> element itself.

The <registration-listener> specifies the execution of certain Spring bean methods through the attributes registration-method and unregistration-method, with the values for each attribute corresponding to methods contained in either a referenced or anonymous bean within a Spring-DM configuration file. Listing 4-9 demonstrates the former approach, while Listing 4-10 shows the latter.

Example 4-9. Spring-DM Listener Used in the Registration of an OSGi Service

<service ref="serviceBean" interface="com.apress.springosgi.FlightService">
<registration-listener ref="runwayBean"
registration-method="preTakeoff"
unregistration-method="postTakeoff">
</service>

Example 4-10. Spring-DM Listener with an Anonymous Bean Used in the Registration of an OSGi Service

<service ref="serviceBean" interface="com.apress.springosgi.FlightService">
<registration-listener
registration-method="preTakeoff"
unregistration-method="postTakeoff">
 <bean class="com.apress.springosgi.FlightServiceRunway"/>
</registration-listener>
</service>

Notice how each <service> element nests a <registration-listener> element with a corresponding method to be executed once a service is registered and unregistered. These methods, in order to preserve OSGi compatibility, need to possess a signature like either one presented in Listing 4-11.

Example 4-11. Spring-DM Signatures for Listeners in the Registration of an OSGi Service

public void methodName(ServiceType serviceInstance, Map serviceProperties);
public void methodName(ServiceType serviceInstance, Dictionary serviceProperties);

In this last listing, ServiceType represents a compatible element with the interface belonging to the service being registered or unregistered, and Map and Dictionary represent basic Java constructs containing properties used inside the registration/unregistration method.

This concludes coverage of all the service registration issues related to Spring-DM. Up next, we will explore the complementary process of locating registered services using Spring-DM.

Locating OSGi Services Through Spring-DM

Much like the registration process for OSGi services in Spring-DM, the localization process for OSGi services can be done programmatically; nevertheless, the preferred method in Spring-DM is to use application descriptor elements.

While Spring-DM registration relies on the use of a single element named <service>, Spring-DM localization makes use of three elements: <reference>, <list>, and <set>. Let's start by exploring the most basic lookup sequence available in Spring-DM, the one illustrated in Listing 4-12.

Example 4-12. Spring-DM Lookup of an OSGi Service

<reference id="serviceBean" interface="com.apress.springosgi.FlightService"/>

This sequence looks up a service backed by an interface with the value defined in the corresponding attribute, and instantiates a backing Spring bean in a bundle's context with an ID value of serviceBean. Note that this is an exact reversal of the registration sequence presented in Listings 4-2 and 4-1.

Similarly, the <reference> element also supports the use of multiple interfaces for locating and importing a service into another bundle. Listing 4-13 shows the use of multiple interfaces for locating an OSGi service using Spring-DM.

Example 4-13. Spring-DM Lookup of an OSGi Service with Multiple Interfaces

<reference id="serviceBean">
  <interfaces>
      <value>com.apress.springosgi.FlightService</value>
      <value>com.apress.springosgi.InFlightOperations</value>
      <value>com.apress.springosgi.GroundCrewOperations</value>
   </interfaces>
</service>

In this scenario, a Spring bean named serviceBean is created within a bundle's context supporting the declared interfaces, which of course need to be found as registered OSGi services. It's important to note that communication between a bundle looking up a Spring bean—the consumer—and a bundle providing such a backing bean—the provider—is always done via proxy, which then delegates to the actual Spring bean. This proxy concept was illustrated earlier in Figure 4-1.

On a related note, the same use of interface statements in a <service> element apply to those in a <reference> element. The <interfaces> tag cannot be used in conjunction with the interface attribute, and in case the imported service is bound to an actual class, the presence of CGLIB is required within a bundle so the interfaces can be generated at runtime.

If you prefer a finer-grained approach to querying an OSGi service by its interfaces, you can rely on the use of the actual name employed by a backing bean, as well as any other properties assigned to a service upon registration.

Recall that Spring-DM automatically registers a service with a property type org.springframework.osgi.bean.name set to the value corresponding to the reference bean, making such a value a valid lookup property. Listing 4-14 illustrates this process via the bean-name attribute.

Example 4-14. Spring-DM Lookup of an OSGi Service Using bean-name

<reference id="lookedUpserviceBean" interface="com.apress.springosgi.Flight
Spring-DM Lookup of an OSGi Service Using bean-name
Service" bean-name="serviceBean"/>

This declaration will create a proxy to a Spring bean backed by a service with the FlightService interface, having been created with a bean named serviceBean. However, don't be misled by what is a shortcut notation in Spring-DM: bean-name is simply an abbreviated version for looking up a specific service property in the form of a bean's name.

Using the bean-name property is often discouraged, since it introduces tight coupling between the bundles. The preferred method is to use a service's explicit properties, like those illustrated and assigned previously in Listing 4-4. In order to look up such properties, you require a more general approach offered by the filter attribute, which is presented in Listing 4-15.

Example 4-15. Spring-DM Lookup of an OSGi Service Using filter Based on Properties

<reference id="serviceBean" interface="com.apress.springosgi.FlightService">
 filter="(flight=ACMEAirlines)"/>

This statement will instantiate a Spring bean backed by a service reference possessing the FlightService interface that has a property named flight with a value named ACMEAirlines.

Having explored the use of interfaces and filters in the <reference> element, you may have one obvious question regarding Spring-DM's lookup process: what happens if the OSGi registry has more than one registered service matching the specified query?

According to the OSGi specification, Spring-DM returns the service with the highest ranking attribute value matching a lookup, and if more than two services possess the same interface as well as ranking value, then the one with the lowest service ID, which will likely always be the first registered service, in the OSGi registry is returned. Although using a unique service property for each registered service is sufficient to guarantee that one and only one service is returned on a Spring-DM lookup, the Spring-DM elements <list> and <set> are used precisely for circumstances in which a lookup sequence will knowingly return and require two or more matching services. However, before delving into the use of <list> and <set>, let's finish looking at the available attributes in the <reference> element.

Like its registration counterpart, the <reference> element also has depends-on and context-class-loader attributes. The depends-on attribute functions in pretty much the same way, guaranteeing that a certain Spring bean is already present in a bundle's context prior to performing a service lookup; however, the context-class-loader attribute has a small variation from how it's used in a <service> element.

When used in the context of looking up a service, the context-class-loader attribute can take any one of the values client, service-provider and unmanaged, with the default value being client. This is in contrast to the Spring-DM service registration process, where the same attribute has a default value of unmanaged and only one alternative value of service-provider.

The addition of the client attribute value for this particular instance is required because a service lookup entails the coordination of resources that may be present in both a consuming bundle and a providing bundle. Thus the client attribute guarantees that the context class loader is able to see types on the class path of the invoking bundle during the service invocation

Rounding off the attributes available in the <reference> element, we come to the cardinality attribute. If you're not too familiar with the term "cardinality," in Spring-DM it has a very simple meaning: cardinality indicates either a service is mandatory or optional.

By default, a <reference> element has a cardinality value of 1..1, indicating a service lookup must be successful prior to creating a Spring bean with the associated service. On the other hand, a cardinality value of 0..1 indicates that a service reference is optional and that a Spring bean may be created immediately without fulfilling its service dependencies.

Complementing the cardinality attribute, you will find the timeout attribute, which is used to indicate the time in seconds that Spring-DM should wait before giving up on resolving a service reference for creating a Spring bean. By default this timeout is set to 300 seconds (5 minutes).

A few of the attributes just described can be configured globally for every statement pertaining to Spring-DM lookup elements. Listing 4-16 illustrates how this process works in a Spring-DM configuration file.

Example 4-16. Spring-DM Global Default Values for Lookup of an OSGi Service

<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"
          osgi:default-timeout="5000"
          osgi:default-cardinality="0..X">

  <reference id="flightService" interface="com.apress.springosgi.FlightService"/>

  <reference id="nightlyFlightService" interface="com.apress.springosgi.Nightly
Spring-DM Global Default Values for Lookup of an OSGi Service
FlightService" timeout="1000"/> <list id="cargoFlightServices" interface="com.apress.springosgi.CargoFlight
Spring-DM Global Default Values for Lookup of an OSGi Service
Service" cardinality="1..N"/> </beans:beans>

Note

Default cardinality for all OSGi references (singular or collection) elements that do not explicitly specify one, are the following: The default value is 1..X (resolved to 1..1 for osgi:reference and 1..N for osgi:list/set), which means that a backing service must exist (this is a mandatory service reference). A value of 0..X (resolved to 0..1 for osgi:reference and 0..N for osgi:list/set) indicates that it is acceptable to have no backing service (an optional service reference).

This listing declares Spring-DM's lookup properties using the osgi namespace inside the configuration file's root element, overriding the default timeout value to 5000 seconds and changing the default cardinality to an optional service value of 0..X. By using such statements, these values will take effect for every Spring-DM lookup statement made in the configuration file, unless further overridden by their in-line attributes, in which case the attribute values take precedence.

Moving along through Spring-DM's element arsenal, you will find the <list> and <set> elements, both of which are closely related to the <reference> element. Whereas all three elements are used to locate OSGi services using Spring-DM, it's the <list> and <set> elements that are designed to retrieve more than one service matching a predetermined interface or filter.

<list> and <set> support the same attributes used by the <reference> element, which include interface, filter, bean-name, cardinality, and context-class-loader. Each of these attributes behaves in exactly the same manner as its single service matching counterpart; however, the dynamics to using <list> and <set> are somewhat different, and I'll elaborate why.

Let's start off by exploring the differences between <list> and <set>—after all, if both support the retrieval of multiple services, when should you use one rather than the other? The semantics behind the <list> and <set> elements are rooted in the Java Collections Framework interfaces of the same names, which makes the selection process in tune with the same behavior of the former framework.

In very simplified terms, the <set> element should be used when a group of retrieved services needs to be pruned of elements possessing object equality, a characteristic of the Set interface in the Java Collections Framework, in which no two equal objects can form part of the same Set. On the other hand, the <list> element should be used under circumstances in which all retrieved services need to be accounted for, whether they possess object equality or not. (See the sidebar "<list>, <set>, and the Java Collections Framework" for more background on the Java Collections Framework.)

The Spring beans generated by both the <list> and <set> elements are different from those instantiated by the unitary <reference> element, with one bean having a java.util.List type and the other a java.util.Set type. Additionally, both rely on the use of other Java Collections constructs like Iterator to access specific services within a collection, with this latter manipulation taking place inside the Java Beans that will make use of such services.

Still, without resorting to Java code and within the confines of Spring-DM's configuration file, it's possible to apply a sorting strategy for a collection of services using the <comparator> element. Listing 4-17 illustrates the first case scenario for this element.

Example 4-17. Spring-DM Sorting Services in Natural Order for Lookup of OSGi Services

<list id="flightServices" interface"com.apress.springosgi.FlightService">
  <comparator><natural-ordering basis="services"/></comparator>
</list>

<set id="nightlyFlightServices" interface="com.apress.springosgi.FlightService">
  <comparator><natural-ordering basis="service-references"/></comparator>
</set>

The first-case scenario for the <comparator> element makes further use of the <natural-ordering> element, which as its name implies uses the natural ordering algorithm employed by the Java Collections Framework. Further, notice that Spring-DM can perform the natural ordering of services based on two values, one on service-references and the other on the services themselves.

The second-case scenario for the <comparator> element relies on the creation of a special class of the type java.util.Comparator, which is used as the basis for sorting a collection of services. Though you will need to refer to the Java Collections Framework for building such a class, Listing 4-18 illustrates how to use the <comparator> element through this approach.

Example 4-18. Spring-DM Sorting Services Based on the Comparator Class for Lookup of OSGi Services

<set id="flightServices" interface="com.apress.springosgi.FlightService"
  comparator-ref="flightComparator"/>

<list id="nightlyFlightServices"
  interface="com.apress.springosgi.NightlyFlightService">
  <comparator>
     <beans:bean class="nightlyFlightComparator"/>
  </comparator>
</list>

Much like the natural ordering mechanism, which has two variations, using a custom-made comparator class also has two alternatives: one in which a comparator class is instantiated as a Spring bean and associated through the comparator-ref attribute directly inside a <set> or <list> element, and a second option in which the comparator is instantiated anonymously inside the <comparator> element.

The benefit to using the <comparator> element in any capacity is that the desired sorting strategy for a group of services is performed without the need to do so with in-line code inside a POJO.

Additionally, both the <set> and <list> elements provide another special Spring-DM attribute named greedy-proxying, one that grants access to all the underlying classes and interfaces used by a group of services; this is specially important in the context of a collection of services, given the various interfaces that may be supported.

Take for example Listing 4-19, which illustrates the use of the greedy-proxying attribute.

Example 4-19. Spring-DM Greedy Proxying for Lookup of OSGi Services

<set id="flightServices" interface="com.apress.springosgi.FlightService"
  greedy-proxying="true"/>

At first sight, the use of greedy-proxying might seem inconsequential, but take a look at Listing 4-20, which illustrates what can be done inside a POJO using such a collection of service-backed beans.

Example 4-20. Spring-DM Greedy Proxying Consuming a POJO Iterator

for (Iterator iterator = services.iterator(); iterator.hasNext();) {
        FlightService service = (FlightService) iterator.next();
        service.runwayOperation();
        // If the service implements additional type, execute more logic
        if (service instanceof ACMEFlight) {
                ((ACMEFlight)service).sendRunwayClearance();
        }

}

Were it not for the use of the greedy-proxying attribute, the iterator over the set of services would have no knowledge of any other service interface, hence the utility of such an attribute when looking up multiple services via Spring-DM.

With this, I've practically covered all the variations used in the primary elements for looking up services in Spring-DM; however, I have yet to cover one important aspect specifically linked to OSGi, the event listeners related to services referenced via <reference>, <set>, and <list>.

Similar to the <registration-listener> element used to execute instructions once an OSGi service is registered or unregistered, Spring-DM offers the same capability when a service is bound or unbound through any of its lookup elements.

A binding operation in Spring-DM takes place when a Spring bean reference is initially bound to a backing service, as well as when such a backing service is replaced by a new service. Similarly, in the context of service collections— <set> or <list>—a binding operation takes place each time a service is added to a group.

On the other hand, an unbinding operation in Spring-DM takes place each time a backing service is unregistered and no replacement service is available. Similarly, in the context of service collections— <set> or <list>—an unbinding operation takes place each time a service is unregistered and removed from the group.

In order to respond to such events in Spring-DM, a special bean needs to be created and associated through the <listener> element, which then has to be nested in either a <reference>, <set>, or <list> element. Listing 4-21 shows this process.

Example 4-21. Spring-DM Event Listener for Binding and Unbinding of a Service

<reference id="flightService" interface="com.apress.springosgi.FlightService">
  <listener ref="flightListenerBean"/>
</reference>

In this last listing the bean flightListenerBean represents a bean implementing the Spring-DM interface org.springframework.osgi.service.importer.OsgiServiceLifecycleListener, which by doing so will contain the methods bind and unbind. These methods will be invoked when a backing Spring bean is bound to and unbound from its underlying service, respectively.

Additionally, Spring-DM also supports the use of custom bind and unbind methods as an alternative mechanism to this last interface; under these circumstances, the listener methods need to be declared through attributes inside the <listener> element, with the associated bean nested inside this latter element. Listing 4-22 shows this process.

Example 4-22. Spring-DM Custom Event Listener Methods for Binding and Unbinding of a Service

<reference id="flightService" interface="com.apress.springosgi.FlightService">
  <listener bind-method="onBind" unbind-method="onUnbind">
   <beans:bean class="flightListenerBean"/>
  </listner>
</reference>

In this case, the bind-method and unbind-method attributes point toward the method names that will be invoked once the binding and unbinding process take place, methods that are contained in the bean referenced within the nested <bean> statement. It should also be pointed out that such custom method listeners need to conform to certain signatures set forth by OSGi, signatures that are illustrated in Listing 4-23.

Example 4-23. Spring-DM Signatures for Listeners in Lookup of OSGi Services

public void methodName(ServiceType serviceInstance, Map serviceProperties);
public void methodName(ServiceType serviceInstance, Dictionary serviceProperties);
public void methodName(ServiceType serviceInstance);

Like the listener signatures described for Spring-DM's service registration process, the ServiceType class represents an interface for a matching service interface, while the Map and Dictionary instances are used to pass properties to the underlying method's logic.

Finally, there is one more technique that needs to be addressed while on the subject of accessing a registered service in OSGi via Spring-DM: annotations.

Instead of instantiating a Spring bean through the use of a <reference>, <list>, or <set> element inside a Spring configuration file and later injecting it into a <bean> statement, a Spring-DM-backed OSGi service can be instantiated and injected directly inside a POJO using annotations, Listing 4-24 presents this approach.

Example 4-24. Injecting a Spring-DM Service Reference Using Annotations

import org.springframework.osgi.extensions.annotation.ServiceReference

public class AirportBeanClass {

  @ServiceReference
  public void setFlightService(FlightService airService) {

  }

}

When Spring-DM encounters the annotation @ServiceReference in a bundle class, it automatically attempts to locate a service with an interface corresponding to the setter method decorated with the annotation. In the case of Listing 4-24, it will attempt to locate a service with the FlightService interface and inject it directly into the Java class representing a Spring bean.

If required, the @ServiceReference annotation also supports the same attributes as its XML counterparts used to alter the default lookup process; values like cardinality, contextClassLoader, filter, serviceBeanName, serviceTypes, and timeout can all be specified as parameters inside parentheses alongside the annotation.

This concludes the subject of locating services in OSGi using Spring-DM. The next section will discuss one more area related to Spring-DM: the management of bundles themselves.

OSGi Bundle Activities with Spring-DM

Just as you explored the registration and lookup of services in OSGi, Spring-DM also has support for interacting directly with the higher-level units in the OSGi framework: bundles. Through Spring-DM statements, you can also perform all the standard OSGi actions available to bundles, such as installing or updating them at any given time.

Supporting the interaction of bundles in Spring-DM configuration files is the <bundle> element. Listing 4-25 shows the most basic statement making use of this element.

Example 4-25. Spring-DM Bundle Reference

<bundle id="acmeBundle" symbolic-name="com.apress.springosgi.ACMEAirlines"/>

This statement will instantiate a Spring bean of the type org.osgi.framework.Bundle, taken from a system bundle having a symbolic name com.apress.springosgi.ACMEAirlines (recall that a bundle's symbolic name is defined in its OSGi manifest).

By itself, the declaration in Listing 4-25 only serves to inject a given bundle into another Spring statement in the configuration file; however, the <bundle> element also supports other attributes.

One such attribute is action, which is used to change a bundle's state when a host bundle's Spring context is created. In Spring-DM the same bundle actions as employed in any other OSGi environment are supported: start, update, stop, and uninstall.

Additionally, Spring-DM also supports an attribute named destroy-action, which takes the same values as its action counterpart; however, destroy-action's changes in state are processed once a host bundle's Spring context is destroyed.

And last but not least, the <bundle> element makes use of the location attribute, whose value is used to indicate the physical location of a bundle and which is necessary to perform both installation and update actions on a bundle. Listing 4-26 shows a more comprehensive example of Spring-DM's <bundle> element.

Example 4-26. Spring-DM Bundle Installation

<bundle id="acmeBundle"
location="http://www.apress.com/springosgi/bundles/ACMEAirlines.jar"
symbolic-name="com.apress.springosgi.ACMEAirlines"
action="start"/>

This statement installs and starts the bundle located in the corresponding location value, and assigns it an ID of acmeBundle for further reference within the Spring configuration file.

Next, we will explore another concept related to Spring-DM that has close ties to the management of bundle: fragments.

OSGi Fragments with Spring-DM

At the start of the chapter, you learned about OSGi fragments and how they are used to add information to a bundle without disturbing its preexisting structure. Additionally, at the outset you also learned about OSGi extenders, which are patterns used to automatically fire off a chain of events and on which Spring-DM relies to process a bundle's Spring-DM configuration files.

As it turns out, the two bundles that provide Spring-DM with its extender capabilities— spring-osgi-extender.jar and spring-osgi-web-extender.jar—can easily be modified using fragments.

Using OSGi fragments to modify Spring-DM's extender bundles requires that a fragment bundle follow certain rules. However, before exploring such rules, it's important to know the actual Spring-DM values that can be modified through fragments.

Spring-DM's extenders make use of beans to expose values that can be modified via fragments, and since there are two Spring-DM extenders, you need to familiarize yourself with two sets of bean values. Table 4-5 presents the first set corresponding to the core spring-osgi-extender.jar.

Table 4-5. spring-osgi-extender.jar Bean Values Exposed for Fragments

Bean Name

Type

Function

Default Value

task-executor

org.springframework.core.task.
TaskExecutor

Creates and runs the Spring application contexts associated with each bundle. The task executor is responsible for managing its own pool of threads used by the application contexts.

org.springframework.
core.task.Simple
AsyncTaskExecutor

shutdownTaskExecutor

org.springframework.
core.task.TaskExecutor

Destroys managed Spring application contexts associated with each bundle. The task executor is responsible for managing its own pool of threads used by the application contexts.

org.springframework.sc
heduling.timer.
TimerTaskExecutor
applicationEvent
Multicaster
org.springframework.
context.event.
ApplicationEventMulticaster

Propagates Spring-DM events to third parties.

org.springframework.
context.event.
SimpleApplication
EventMulticaster
applicationContext
Creator
org.springframework.
osgi.extender.
OsgiApplicationContextCreator

Allows customization of the application context created by the extender. This includes changing the application context class type or additional processing. (See info on OsgiBeanFactory PostProcessor in the next entry.)

The extender default behavior applies.

N/A

org.springframework.
osgi.extender.
OsgiBeanFactoryPostProcessor

Similar to Spring's BeanFactoryPost-Processor interface, beans of type OsgiBean-FactoryPostProcessor are automatically detected and applied to all contexts created by the extender (whether user defined or not). This type of post processor is useful as it allows customization of the bean factory such as adding/removing/changing existing bean definitions or adding new bean instances.

The extender default behavior applies.

extenderProperties

java.util.Properties

Defines simple properties.

See the following property names.

Property Name for extenderProperties

Type

Function

Default Value

shutdown.wait.time

java.lang.Number

The amount of time the extender will wait for each application context to shut down gracefully. Expressed in milliseconds.

10000 ms (10 seconds)

process.annotations

java.lang.Boolean

Flag indicating whether or not the extender will process Spring-DM annotations.

false

Additionally, the spring-osgi-web-extender.jar extender has its own set of beans, presented in Table 4-6.

Knowing what bean values can be modified in both Spring-DM's extender bundles using fragments, let's explore the actual structure a bundle fragment needs to adhere to in order to modify these bean values.

Upon deployment of a bundle fragment, Spring-DM will automatically inspect a bundle's /META-INF/spring/extender/ folder for the presence of a descriptor containing any declaration with the beans outlined in Table 4-5 or Table 4-6. And upon processing such a configuration file, Spring-DM will automatically use the new bean values for its extenders.

Table 4-6. spring-osgi-web-extender.jar Bean Values Exposed for Fragments

Bean Name

Type

Function

Default Value

warDeployer

org.springframework.
osgi.web.deployer.
WarDeployer

Installs OSGi bundles as web applications. The deployer takes care of locating the required web container and installing and uninstalling web applications.

org.springframework.
osgi.web.deployer.
tomcat.
TomcatWarDeployer

contextPathStrategy

org.springframework.
osgi.web.deployer.
ContextPathStrategy

Determines the context path associated with an OSGi bundle/WAR. The returned path is used by the war deployer to install the war application.

org.springframework.
osgi.web.deployer.
support.DefaultContext
PathStrategy

To illustrate this concept further, let's create two fragments to modify Spring-DM's extender bundles, one to activate the processing of Spring-DM annotations and another to modify the default target web container used by Spring-DM.

Listing 4-24 illustrated that Spring-DM could make use of annotations to inject service references into POJOs; however, by default this behavior is disabled in Spring-DM's extender, spring-osgi-extender.jar, to avoid the scanning overhead. In order to modify this behavior, a fragment or inclusively a dedicated bean post processor could be used. Next I will illustrate the fragment approach.

The first thing that needs to be created is a MANIFEST.MF file that will accompany the bundle fragment. Listing 4-27 illustrates the syntax for a MANIFEST.MF file used to create a fragment targeting Spring-DM's core extender.

Example 4-27. OSGi Manifest for a Fragment Used on Spring-DM's spring-osgi-extender.jar

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Fragment-Host: org.springframework.bundle.osgi.extender
Bundle-SymbolicName: com.apress.springosgi.ch4.fragment
Bundle-Name: HelloWorld Spring-OSGi Fragment
Bundle-Description: Spring-DM Fragment for activating OSGi annotation scanning

The most important part of this MANIFEST.MF file is the Fragment-Host directive, which tells the OSGi environment it's dealing with bundle fragment. The value org.springframework.bundle.osgi.extender indicates the fragment is targeted at a bundle with that symbolic name, which in this case corresponds to Spring-DM's spring-osgi-extender.jar bundle.

This same MANIFEST.MF file would be used for any fragment attempting to modify the bean values presented in Table 4-5. But what about the bean values? Where are they located? Listing 4-28 shows the descriptor used in a fragment to activate Spring-DM's annotation processing.

Example 4-28. Spring-DM Descriptor for Activating Annotation Processing

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

    <bean id="extenderProperties">
       <property name="process.annotations" value="true"/>
    </bean>
</beans>

Notice this last listing is a standard Spring descriptor using the bean namespace to define the extenderProperties bean and assign it a property named process.annotations with a value of true. Such values are Spring-DM's exposed bean values, which were presented previously in Table 4-5. The only thing special about this descriptor is where it needs to be placed, which is under a bundle's /META-INF/spring/extender/ directory.

Listing 4-29 illustrates the final layout for the bundle fragment targeting Spring-DM's spring-osgi-extender.jar bundle.

Example 4-29. Spring-DM Extender Layout

+META-INF+
         |--MANIFEST.MF
         |
         +-spring-+
                  |
                  +-extender-+

                             |--annotation-activator.xml

The bundle's layout simply contains the MANIFEST.MF file (Listing 4-27) and the corresponding descriptor used to modify Spring-DM's core extender bundle (Listing 4-28). Once this bundle fragment is deployed, Spring-DM will be capable of performing annotation scanning for service references.

Warning

Apache Felix, used in Chapters 1 and 3, does not support fragments. If your Spring-DM projects require fragments as outlined here or in other parts of this book, you will need to use another OSGi environment like Eclipse Equinox or Knopflerfish. Progress on support for fragments in Apache Felix can be found at https://issues.apache.org/jira/browse/FELIX-29.

Using a fragment to modify Spring-DM's other extender, spring-osgi-web-extender.jar, is very similar. Listing 4-30 illustrates the MANIFEST.MF file used in fragments targeting this last extender.

Example 4-30. OSGi Manifest for Fragments Used on Spring-DM's spring-osgi-web-extender.jar

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Fragment-Host: org.springframework.bundle.osgi.web.extender
Bundle-SymbolicName: com.apress.springosgi.ch4.fragment
Bundle-Name: HelloWorld Spring-OSGi Fragment
Bundle-Description: Spring-DM Fragment for activating OSGi annotation scanning

Similar to the earlier extender MANIFEST.MF file, the Fragment-Host directive is the most important part. However, note that the value in this last listing points toward org.springframework.bundle.osgi.web.extender, which is the symbolic name corresponding to Spring-DM's spring-osgi-web-extender.jar bundle.

This same MANIFEST.MF file would be used for any fragment attempting to modify the bean values presented in Table 4-6. Listing 4-31 shows the descriptor used in a fragment to modify the underlying OSGi'fied application server used by Spring-DM to deploy WAR files.

Example 4-31. Spring-DM Descriptor for Using the Jetty Web Container As Spring-DM's OSGi'fied Application Server

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

   <bean id="warDeployer">
          class="org.springframework.osgi.web.deployer.jetty.JettyWarDeployer" />
   </bean>
</beans>

Notice the same use of Spring's standard bean namespace to define the warDeployer bean and assign it a class named org.springframework.osgi.web.deployer.jetty.JettyWarDeployer. This bean value is taken from Table 4-6, which contains Spring-DM's web extender bean values. Identical to the earlier fragment, this descriptor needs to be placed inside a bundle's /META-INF/spring/extender/ directory.

Listing 4-32 illustrates the final layout for a bundle fragment targeting Spring-DM's org.springframework.bundle.osgi.web.extender bundle.

Example 4-32. Spring-DM Extender Layout

+META-INF+
         |--MANIFEST.MF
         |
         +-spring-+
                  |
                  +-extender-+

                             |--jetty-deployer.xml

The bundle's layout simply contains the MANIFEST.MF file (Listing 4-30) and the corresponding descriptor used to modify Spring-DM's web extender bundle (Listing 4-31). Once this fragment bundle is deployed, Spring-DM will use the Jetty web container as the underlying OSGi'fied application server to deploy its WAR files.

Summary

In this chapter you learned the core concepts behind Spring-DM, starting off with the meaning and functionality offered by extenders and fragments, with the former allowing the inspection and processing of Spring configuration files inside OSGi bundles and the latter providing the necessary mechanisms to add extra logic to preexisting bundles.

You also explored how each Spring-DM-powered bundle makes use of a special context throughout its life cycle, in which it manages all its related Spring artifacts, which can range from a bundle's own local Spring beans, to any Spring beans instantiated from OSGi services imported via Spring-DM.

Additionally, you also learned all the valid Spring-DM statements that can be used inside Spring configuration files, including how a Spring bean can be registered as an OSGi service for consumption by other bundles, how these same services can be reincarnated as Spring beans inside bundles, as well as statements related to the management of bundles themselves via Spring-DM.

Finally, you learned how to use fragments targeting both Spring-DM extender bundles, creating fragments to activate the use Spring-DM annotation processing and to override the default web container used by Spring-DM to process WAR files.



[13] Peter Kriens, OSGi blog, "The OSGi Extender Model," http://www.osgi.org/blog/2007/02/osgi-extender-model.html

[14] CGLIB home page, http://cglib.sourceforge.net/.CGLIBOSGibundle, http://www.springsource.com/repository/app/search?query=cglib

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

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