Spring parameterized instance factory-method

While the Spring framework provides a lot of great ways to instantiate managed beans, there is no clear way to instantiate multiple beans from a non-Spring factory where the type of those beans is determined by method parameters. In this post I show how this can be done using existing Spring bean-instantiation constructs.

Spring provides a lot of great ways to manage Java bean instantiation. While the most common method is singleton bean instantiation from a no-arg constructor, There are a variety of other ways. prototype scope allows a user to get a new instance of a bean every time getBean is called. constructor-arg allows arguments to be passed to constructors of a bean. factory-method allows a user to call a static method to return an instance of the static method’s declaring type. When combined with factory-bean, factory-method can be from an instance method (but then the type containing the method has to be a Spring managed factory). lookup-method allows an abstract class to be instantiated from the abstract lookup-method the same way one would create an anonymous class from an interface in Java. (Then the class and method have to be abstract however). What does one do however if even with all these options, it isn’t enough? What would one do if they wanted to have a singleton that returned instances whose type was based on a method parameter?

Last post I detailed the problem that led me down this path, but I will summarize here. I had set some basic criteria for any solution I came up with to solve my coding problem. To start, my Java code would not use any Spring specific interfaces or constructs. All Spring interfacing would happen in the Spring applicationContext, where the configuration had to be easy to understand. The reason for this is that I didn’t want to be dependent on a specific version of Spring if I didn’t have to. The specific problem was that I had a singleton bean CachingOsgiServiceGetter that would do the work of retrieving OSGi services. I had a method getServices that would retrieve a different type of Java Object instance (the OSGi service) based on parameters passed to that method. This class had to be configured once, preventing use of lookup-method. I didn’t want to use Spring libraries, so I couldn’t use factory-bean (org.springframework.beans.factory.FactoryBean). The method was an instance method, so I couldn’t use factory-method. The method needed a different parameter for each call to getService, so I couldn’t use constructor-arg on CachingOsgiServiceGetter, which would only allow me to configure it once. Finally, I couldn’t use prototype scope because I needed a different type for each call to getService, not the same type.

I solved this problem by combining my unchanged singleton bean CachingOsgiServiceGetter with factory-method, constructor-arg, and a helper static class. The keys here are that one, factory-method can return any type, not just the type of the method’s declaring class. two, constructor-arg can be used to pass any arguments to the factory-method. Three, While CachingOsgiServiceGetter.getService was an instance method that couldn’t be used as a factory-method, there was nothing preventing me from creating an adapter classs with static factory-method method that called my instance method!

The unchanged singleton bean:

public class CachingOsgiServiceGetter
...
public <s> S getService(Class<s> clazz)
...

The factory-method adapter class (with static adapter method):

public class OsgiService {

    public static <S> S getService(Class<S> clazz, CachingOsgiServiceGetter cachingOsgiServiceGetter) {
        return cachingOsgiServiceGetter.getService(clazz);
    }
}

The Spring applicationContext configuration:

<bean id="cachingOsgiServiceGetter" 
    class="com.github.mshin.sosa.CachingOsgiServiceGetter">
</bean>

<bean id="mySpringOsgiService"
    class="com.github.mshin.sosa.OsgiService"
    factory-method="getService">
  <constructor-arg value="com.example.MySpringOsgiService" />
  <constructor-arg ref="cachingOsgiServiceGetter" />
</bean>

<bean id="useServices"
    class="com.example.osgi.service.use.spring.UseServices">
  <property name="mySpringOsgiService" ref="mySpringOsgiService" />
</bean>

In the above example, getService is the instance method on my singleton bean (CachingOsgiServiceGetter) that returns the instances of Objects I want. OsgiService is my adapter class with a static adapter method for factory-method. I named the adapter OsgiService to represent the types getService could possibly return. UseServices is my singleton that needs to use the instance returned by getService.

So why not just declare the static factory-method in CachingOsgiServiceGetter? For one, it would be confusing to have CachingOsgiServiceGetter declared once as a singleton representing its actual type, then have it declared once for each time getService was called representing the OSGi Service type.
Don’t do this because it’s confusing!:

<bean id="cachingOsgiServiceGetter" 
    class="com.github.mshin.sosa.CachingOsgiServiceGetter">
</bean>

<bean id="mySpringOsgiService"
    class="com.github.mshin.sosa.CachingOsgiServiceGetter"
    factory-method="getService">
  <constructor-arg value="com.example.MySpringOsgiService" />
  <constructor-arg ref="cachingOsgiServiceGetter" />
</bean>

<bean id="useServices"
    class="com.example.osgi.service.use.spring.UseServices">
  <property name="mySpringOsgiService" ref="mySpringOsgiService" />
</bean>

Second, one doesn’t always have the ability to change the code of the singletons one’s trying to use. One does however always have the ability to create a static utility adapter class.

The code examples used in this post are simplified versions of deployable code that can be found in my code repository. Here are links to the application context, singleton bean that makes instances, and adapter class.

OSGi services and Spring after the Spring-DM sunset

Red Hat Fuse supports Spring, but Spring/OSGi service integration doesn’t come out of the box. This post details a library I wrote to provide that functionality, how to use it, and links to the library and deployable example code.

Tech stack:
Fuse 6.x, OSGi Services, Spring 3.x – 4.x, Java 7/8

Links:
Spring-DM pom
spring-osgi-service-adapter
example code
download Fuse

Spring-DM is the common name for the Spring Framework jars responsible for Spring/OSGi integration. Their most recent update according to Maven Central was in December 2009 with update version 1.2.1. Spring-DM is implemented with Spring version 2.5.6.SEC01 and is supposed to be compliant with Spring versions up to 3.x.

As of August 2016 Red Hat Fuse on Karaf/Felix (OSGi container) is still being packaged with the full compliment of Spring jars and the most recent version of Spring-DM. What’s going on? Why is a modern product still relying on software that was last updated more than 6 years ago? To answer this question, 1st a brief history of the products is in order.

Spring offloaded Spring-DM to Eclipse around 2010 due to disagreements between the OSGi and Spring Source developers. When this happened, the project was officially renamed the Eclipse Gemini Blueprint project. In effect, Spring-DM support was killed and the OSGi developers created a competing dependency injection framework similar to Spring. These two frameworks (Spring and Blueprint) are incompatible. The primary drawback of this is that beans managed by Spring cannot be referenced from a Blueprint context and vice versa.

One of the main uses of Spring-DM was that it made exposing and using OSGi services very easy. Blueprint enables this functionality with the same ease of use as Spring-DM. If at all possible, it is recommended that one uses Blueprint to expose and consume OSGi services. However, this is not always possible. Often an organization will be locked into Spring because all their applications use that framework. Also, Spring provides a lot of functionality that Blueprint does not, such as prototypes and managed bean inheritance.

Fuse supports both Spring and Blueprint as dependency injection frameworks, however developers will find trying to use OSGi services with the Spring framework difficult if not impossible without Spring-DM, or writing a lot of OSGi code in their application classes (not recommended). What is one to do?

My personal experience with this dilemma was that it was unavoidable to end up writing some OSGi specific code. I couldn’t expose an OSGi service just from the context, and I definitely couldn’t consume an OSGi service without writing some sort of OSGi code in the Spring bean that needed the OSGi service instance. Often, a BundleActivator class needed to be used. This was unacceptable to me. OSGi is a platform specific framework and should not require writing special code in the application classes.

I set out to solve this problem under the following criteria:

  1. The new Spring/OSGi service integration pattern had to be simplistic and simple.
  2. The new method had to expose and consume services solely from the Spring applicationContext configuration.
  3. No java code should be written to expose or consume services.
  4. The new method had to be independent of any Spring libraries so it could be used with any newer version of Spring.
  5. The configuration in the applicationContext had to be simple and intuitive.

What I came up with was a new library I titled spring-osgi-service-adapter. The library meets all the criteria I set out for it. Now, this library isn’t perfect and doesn’t meet all situations, but I think it will satisfy most use cases and the pattern used can be customized to fit one’s particular application needs. There are links above for example code and the library itself. There are verbose Javadocs in the source files as well which should explain in greater detail what’s going on and how to use the library.

To expose a service:

<bean id="osgiServiceRegistrator" class="com.github.mshin.sosa.OsgiServiceRegistrator"
init-method="init" destroy-method="destroy">
  <property name="serviceInstance">
    <bean class="com.example.osgi.service.spring.MyNoInterfaceSpringOsgiService" />
  </property>
</bean>

(If no properties, and serviceInstance will be retrieved using its same class).

or:

<bean id="osgiServiceRegistrator" class="com.github.mshin.sosa.OsgiServiceRegistrator"
init-method="init" destroy-method="destroy">
  <property name="bundleClass">
    <value type="java.lang.Class">com.example.osgi.service.spring.impl.ClassInOsgiServiceSpringBundle
    </value>
  </property>
  <property name="osgiServiceDefinitionList">
    <list>
      <bean class="com.github.mshin.sosa.OsgiServiceDefinition">
        <property name="classList">
          <list>
            <value>com.example.osgi.service.spring.MySpringOsgiService</value>
          </list>
        </property>
        <property name="serviceInstance">
          <bean class="com.example.osgi.service.spring.impl.MySpringOsgiServiceImpl" />
        </property>
        <property name="properties">
          <map>
            <entry key="property1" value="value1" />
            <entry key="property2" value="value2" />
          </map>
        </property>
      </bean>
    </list>
  </property>
</bean>

Where bundleClass is a class in the bundle, the OSGi service is registered under classList index 0, serviceInstance is the exposed object, and properties are properties associated with the service.

To consume the two services exposed above:

<bean id="cachingOsgiServiceGetter" class="com.github.mshin.sosa.CachingOsgiServiceGetter"
init-method="init" destroy-method="destroy">
  <property name="bundleClass">
    <value type="java.lang.Class">com.example.osgi.service.use.spring.UseServices</value>
  </property>
  <property name="findOsgiServiceTimeout" value="10000" />
</bean>

<bean id="mySpringOsgiService" class="com.github.mshin.sosa.OsgiService" factory-method="getService">
  <constructor-arg index="0" value="com.example.osgi.service.spring.MySpringOsgiService" />
  <constructor-arg index="1" value="(&(objectclass=com.example.osgi.service.spring.MySpringOsgiService)(property1=value1))" />
  <constructor-arg index="2" ref="cachingOsgiServiceGetter" />
</bean>

<bean id="myNoInterfaceSpringOsgiService" class="com.github.mshin.sosa.OsgiService" factory-method="getService">
  <constructor-arg value="com.example.osgi.service.spring.MyNoInterfaceSpringOsgiService" />
  <constructor-arg ref="cachingOsgiServiceGetter" />
</bean>

<bean id="useServices" class="com.example.osgi.service.use.spring.UseServices">
  <property name="mySpringOsgiService" ref="mySpringOsgiService" />
  <property name="myNoInterfaceSpringOsgiService" ref="myNoInterfaceSpringOsgiService" />
</bean>

Where bundleClass is a class in the bundle, userServices is a class in the bundle that needs the OSGi services injected, myNoInterfaceSpringOsgiService is an OSGi service that is found using it’s class name, and mySpringOsgiService is a bundle found using an LDAP style filter. If the filter was not present, it would be found using its interface, MySpringOsgiService.

The hardest part of coming up with this strategy was coming up with an intuitive way to extract the OSGi service from the CachingOsgiServiceGetter. What I needed was a Spring parameterized instance factory-method. the getService method cannot be static and requires parameters to return different types of OSGi services. (factory-method can only be non-static if a factory-bean is used). These services must be injectable into Spring managed application beans. The method I came up with is a bit tricky. I will go into it in more detail in a later blog post, but I took advantage of the fact that factory-method doesn’t necessarily return the type in which the method is declared.

I was always annoyed that Spring was supported on Fuse except for OSGi services. Thankfully, there is now a solution (if imperfect) that doesn’t require rewriting Spring-DM. One should be able to save a lot of time and frustration by using the spring-osgi-service-adapter library, or at least be able to use some of the ideas in it for one’s own Spring/OSGi services solution.

Referenced Jars:
com.github.mshin/spring-osgi-service-adapter/1.0

org.springframework.osgi/spring-osgi-io/1.2.1
org.springframework.osgi/spring-osgi-core/1.2.1
org.springframework.osgi/spring-osgi-extender/1.2.1
org.springframework.osgi/spring-osgi-annotation/1.2.1