Spring Data MongoDB in OSGi Blueprint

[toc]

Abstract

Spring Data is yet another extremely useful Spring subproject which is so tightly coupled with the Spring-specific container features, that deploying it in Blueprint is a non-trivial task.

The alternative to an adaptation to Blueprint is (once again) mixing Spring DM and Blueprint bundles and importing Spring DM services into Blueprint contexts.

Spring Data MongoDB in Spring DM

Excluding the Compendium marker for loading the properties file, the Spring DM configuration for MongoDB does not deviate much:

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:osgi="http://www.springframework.org/schema/osgi"
	xmlns:osgix="http://www.springframework.org/schema/osgi-compendium"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:mongo="http://www.springframework.org/schema/data/mongo"
	xsi:schemaLocation="
	http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
	http://www.springframework.org/schema/osgi http://www.springframework.org/schema/osgi/spring-osgi.xsd
	http://www.springframework.org/schema/osgi-compendium http://www.springframework.org/schema/osgi-compendium/spring-osgi-compendium.xsd
	http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
	http://www.springframework.org/schema/data/mongo http://www.springframework.org/schema/data/mongo/spring-mongo.xsd">

	<osgix:cm-properties id="properties" persistent-id="io.modio.blog.osgi.spring.data.mongodb"/>
	<context:property-placeholder properties-ref="properties" />

	<!-- Mongo DB -->
	<mongo:mongo id="mongo" host="${io.modio.blog.osgi.spring.data.mongodb.host}" 
		port="${io.modio.blog.osgi.spring.data.mongodb.port}">
	</mongo:mongo>

	<mongo:db-factory id="mongoDbFactory" mongo-ref="mongo"
		dbname="${io.modio.blog.osgi.spring.data.mongodb.db}"/>

	<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
		<constructor-arg name="mongoDbFactory" ref="mongoDbFactory"/>
	</bean>

	<mongo:repositories mongo-template-ref="mongoTemplate"
		base-package="io.modio.blog.osgi.spring.data.mongodb.repository"/>

	<osgi:service interface="io.modio.blog.osgi.spring.data.mongodb.repository.TaskRepository" ref="taskRepository"/>
</beans>

The TaskRepository is minimal but all the standard Spring Data query method annotations are supported:

@Document
public class Task {
    @Id
    private String id;
    private String name;
 
    public String getId() { return id; }
    public void setId(String id) { this.id = id; }
 
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
}

public interface TaskRepository extends MongoRepository<Task,String>{
    Page<Task> findByName(String name, Pageable pageable);

    @Query("{ 'id': { $in : ?0 } }")
    List<Task> findByIds(List<String> ids);
}

In addition, custom repository implementations also work as expected:

    ...
    <bean id="taskRepositoryImpl"
        class="io.modio.blog.osgi.spring.data.mongodb.repository.TaskRepositoryImpl">
        <property name="mongoTemplate" ref="mongoTemplate"/>
    </bean>
    ...
public interface TaskRepositoryExt {
    Page<Task> findByNameSimilar(String query, Pageable pageable);
}

public class TaskRepositoryImpl implements TaskRepositoryExt {
    private MongoTemplate mongoTemplate;
    
    @Override
    public Page<Task> findByNameSimilar(String value, Pageable pageable) {
        Query query = new Query().with(pageable);
        
        if (!StringUtils.isEmpty(value)) {
            query.addCriteria(Criteria.where("name").regex(
                ".*"+value+".*", "i"));
        }
        
        long count = mongoTemplate.count(query, Task.class);
        List<Task> list = mongoTemplate.find(query, Task.class);
        Page<Task> page = new org.springframework.data.domain.PageImpl<Task>(
            list, pageable, count);
        
        return page;
    }

    public void setMongoTemplate(MongoTemplate mongoTemplate) {
        this.mongoTemplate = mongoTemplate;
    }
}

The Maven pom.xml file for building the repository bundle is more elaborate due to all the explicit Import-Package directives, since BND cannot pickup import dependencies from the context-osgi.xml file:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    
    <groupId>io.modio.blog</groupId>
    <artifactId>io.modio.blog.osgi.spring.data.mongodb.repository</artifactId>
    <packaging>bundle</packaging>
    
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.felix</groupId>
                <artifactId>maven-bundle-plugin</artifactId>
                <version>2.3.7</version>
                <configuration>
                    <instructions>
                        <Export-Package>
                            io.modio.blog.osgi.spring.data.mongodb.entity,
                            io.modio.blog.osgi.spring.data.mongodb.repository
                        </Export-Package>
                        <Import-Package>
                            com.mongodb,
                            org.aopalliance.aop,
                            org.springframework.aop,
                            org.springframework.aop.framework,                            
                            org.springframework.data.domain,
                            org.springframework.data.mongodb.config,                        
                            org.springframework.data.mongodb.repository.support,
                            org.springframework.data.repository,
                            org.springframework.data.repository.core.support,
                            *
                        </Import-Package>                        
                        <Private-Package>
                        </Private-Package>
                    </instructions>
                </configuration>
            </plugin>
        </plugins>
    </build>
    
    <dependencies>
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-mongodb</artifactId>
            <version>1.3.5.RELEASE</version>
         </dependency>
    </dependencies>
</project>
A note on the version of Spring Data MongoDB
Spring stopped releasing OSGi version of their projects from version 3.2.5.RELEASE onwards (see this mail discussion). Due to this limitation, we are restricted to Spring Data MongoDB version 1.3.5.RELEASE, instead of using the latest version.

This issue is expected to be resolved. The ServiceMix community has already released OSGi bundles for Spring 3.2.8.RELEASE, so these will probably be included in a future release of Apache Karaf too.

Spring Data Repository in Blueprint

Consuming the repository service from Blueprint is now simply a matter of importing the service into the Blueprint context:

<blueprint default-activation="eager"
    xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

    <reference id="taskRepository"
        interface="io.modio.blog.osgi.spring.data.mongodb.repository.TaskRepository"/>

    <bean id="taskQueue" class="io.modio.blog.osgi.spring.data.mongodb.TaskQueue">
        <property name="repository" ref="taskRepository"/>
    </bean>

</blueprint>

Features

Spring Data MongoDB carries non-trivial dependencies, so it useful to create a Karaf feature for this:

<features xmlns="http://karaf.apache.org/xmlns/features/v1.0.0" name="spring-data-${project.version}">
    <feature name="spring-data-mongodb" version="1.3.5.RELEASE" resolver='(obr)'>
        <feature version="[3.2.4.RELEASE,4)">spring</feature>
        <feature version="[3.2.4.RELEASE,4)">spring-tx</feature>
        <feature version="[3.2.4.RELEASE,4)">spring-web</feature>
		
        <bundle>mvn:org.mongodb/mongo-java-driver/2.12.0</bundle>
        <bundle>mvn:org.springframework.data/spring-data-commons/1.6.5.RELEASE</bundle>
        <bundle>mvn:org.springframework.data/spring-data-mongodb/1.3.5.RELEASE</bundle>
    </feature>
</features>

1 thought on “Spring Data MongoDB in OSGi Blueprint”

Leave a Reply

Your email address will not be published. Required fields are marked *