diff --git a/spring-data-mongodb/pom.xml b/spring-data-mongodb/pom.xml index 3ea924b53..ad546153e 100644 --- a/spring-data-mongodb/pom.xml +++ b/spring-data-mongodb/pom.xml @@ -14,6 +14,8 @@ 2.7.1 2.3.2 + 1.0 + 1.1.3 @@ -97,6 +99,36 @@ 1.0 true + + + + javax.enterprise + cdi-api + ${cdi.version} + provided + true + + + + javax.el + el-api + ${cdi.version} + test + + + + org.apache.openwebbeans.test + cditest-owb + ${webbeans.version} + test + + + + javax.servlet + servlet-api + 2.5 + test + diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/cdi/MongoRepositoryBean.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/cdi/MongoRepositoryBean.java new file mode 100644 index 000000000..28cd6f118 --- /dev/null +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/cdi/MongoRepositoryBean.java @@ -0,0 +1,76 @@ +/* + * Copyright 2012 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.mongodb.repository.cdi; + +import java.lang.annotation.Annotation; +import java.util.Set; + +import javax.enterprise.context.spi.CreationalContext; +import javax.enterprise.inject.spi.Bean; +import javax.enterprise.inject.spi.BeanManager; + +import org.springframework.data.mongodb.core.MongoOperations; +import org.springframework.data.mongodb.repository.support.MongoRepositoryFactory; +import org.springframework.data.repository.cdi.CdiRepositoryBean; +import org.springframework.util.Assert; + +/** + * {@link CdiRepositoryBean} to create Mongo repository instances. + * + * @author Oliver Gierke + */ +public class MongoRepositoryBean extends CdiRepositoryBean { + + private final Bean operations; + + /** + * Creates a new {@link MongoRepositoryBean}. + * + * @param operations must not be {@literal null}. + * @param qualifiers must not be {@literal null}. + * @param repositoryType must not be {@literal null}. + * @param beanManager must not be {@literal null}. + */ + public MongoRepositoryBean(Bean operations, Set qualifiers, Class repositoryType, + BeanManager beanManager) { + + super(qualifiers, repositoryType, beanManager); + + Assert.notNull(operations); + this.operations = operations; + } + + /* + * (non-Javadoc) + * @see javax.enterprise.inject.spi.Bean#getScope() + */ + public Class getScope() { + return operations.getScope(); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.repository.cdi.CdiRepositoryBean#create(javax.enterprise.context.spi.CreationalContext, java.lang.Class) + */ + @Override + protected T create(CreationalContext creationalContext, Class repositoryType) { + + MongoOperations mongoOperations = getDependencyInstance(operations, MongoOperations.class); + MongoRepositoryFactory factory = new MongoRepositoryFactory(mongoOperations); + + return factory.getRepository(repositoryType); + } +} diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/cdi/MongoRepositoryExtension.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/cdi/MongoRepositoryExtension.java new file mode 100644 index 000000000..37bbdab51 --- /dev/null +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/cdi/MongoRepositoryExtension.java @@ -0,0 +1,111 @@ +/* + * Copyright 2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.mongodb.repository.cdi; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Type; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import javax.enterprise.event.Observes; +import javax.enterprise.inject.UnsatisfiedResolutionException; +import javax.enterprise.inject.spi.AfterBeanDiscovery; +import javax.enterprise.inject.spi.Bean; +import javax.enterprise.inject.spi.BeanManager; +import javax.enterprise.inject.spi.ProcessBean; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.data.mongodb.core.MongoOperations; +import org.springframework.data.repository.cdi.CdiRepositoryExtensionSupport; + +/** + * CDI extension to export Mongo repositories. + * + * @author Oliver Gierke + */ +public class MongoRepositoryExtension extends CdiRepositoryExtensionSupport { + + private static final Logger LOG = LoggerFactory.getLogger(MongoRepositoryExtension.class); + + private final Map, Bean> mongoOperations = new HashMap, Bean>(); + + public MongoRepositoryExtension() { + LOG.info("Activating CDI extension for Spring Data MongoDB repositories."); + } + + @SuppressWarnings("unchecked") + void processBean(@Observes ProcessBean processBean) { + + Bean bean = processBean.getBean(); + + for (Type type : bean.getTypes()) { + if (type instanceof Class && MongoOperations.class.isAssignableFrom((Class) type)) { + if (LOG.isDebugEnabled()) { + LOG.debug(String.format("Discovered %s with qualifiers %s.", MongoOperations.class.getName(), + bean.getQualifiers())); + } + + // Store the EntityManager bean using its qualifiers. + mongoOperations.put(new HashSet(bean.getQualifiers()), (Bean) bean); + } + } + } + + void afterBeanDiscovery(@Observes AfterBeanDiscovery afterBeanDiscovery, BeanManager beanManager) { + + for (Entry, Set> entry : getRepositoryTypes()) { + + Class repositoryType = entry.getKey(); + Set qualifiers = entry.getValue(); + + // Create the bean representing the repository. + Bean repositoryBean = createRepositoryBean(repositoryType, qualifiers, beanManager); + + if (LOG.isInfoEnabled()) { + LOG.info(String.format("Registering bean for %s with qualifiers %s.", repositoryType.getName(), qualifiers)); + } + + // Register the bean to the container. + afterBeanDiscovery.addBean(repositoryBean); + } + } + + /** + * Creates a {@link Bean}. + * + * @param The type of the repository. + * @param repositoryType The class representing the repository. + * @param beanManager The BeanManager instance. + * @return The bean. + */ + private Bean createRepositoryBean(Class repositoryType, Set qualifiers, BeanManager beanManager) { + + // Determine the MongoOperations bean which matches the qualifiers of the repository. + Bean mongoOperations = this.mongoOperations.get(qualifiers); + + if (mongoOperations == null) { + throw new UnsatisfiedResolutionException(String.format("Unable to resolve a bean for '%s' with qualifiers %s.", + MongoOperations.class.getName(), qualifiers)); + } + + // Construct and return the repository bean. + return new MongoRepositoryBean(mongoOperations, qualifiers, repositoryType, beanManager); + } +} diff --git a/spring-data-mongodb/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension b/spring-data-mongodb/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension new file mode 100644 index 000000000..e65289d84 --- /dev/null +++ b/spring-data-mongodb/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension @@ -0,0 +1 @@ +org.springframework.data.mongodb.repository.cdi.MongoRepositoryExtension \ No newline at end of file diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/cdi/CdiExtensionIntegrationTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/cdi/CdiExtensionIntegrationTests.java new file mode 100644 index 000000000..fd7270464 --- /dev/null +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/cdi/CdiExtensionIntegrationTests.java @@ -0,0 +1,58 @@ +/* + * Copyright 2012 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.mongodb.repository.cdi; + +import static org.hamcrest.CoreMatchers.*; +import static org.junit.Assert.*; + +import org.apache.webbeans.cditest.CdiTestContainer; +import org.apache.webbeans.cditest.CdiTestContainerLoader; +import org.junit.BeforeClass; +import org.junit.Test; +import org.springframework.data.mongodb.repository.Person; + +/** + * Integration tests for {@link MongoRepositoryExtension}. + * + * @author Oliver Gierke + */ +public class CdiExtensionIntegrationTests { + + static CdiTestContainer container; + + @BeforeClass + public static void setUp() throws Exception { + container = CdiTestContainerLoader.getCdiContainer(); + container.bootContainer(); + } + + @Test + public void bootstrapsRepositoryCorrectly() { + + RepositoryClient client = container.getInstance(RepositoryClient.class); + PersonRepository repository = client.getRepository(); + + assertThat(repository, is(notNullValue())); + + repository.deleteAll(); + + Person person = new Person("Dave", "Matthews"); + Person result = repository.save(person); + + assertThat(result, is(notNullValue())); + assertThat(repository.findOne(person.getId()).getId(), is(result.getId())); + } +} diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/cdi/MongoTemplateProducer.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/cdi/MongoTemplateProducer.java new file mode 100644 index 000000000..805e02729 --- /dev/null +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/cdi/MongoTemplateProducer.java @@ -0,0 +1,45 @@ +/* + * Copyright 2012 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.mongodb.repository.cdi; + +import java.net.UnknownHostException; + +import javax.enterprise.context.ApplicationScoped; +import javax.enterprise.inject.Produces; + +import org.springframework.data.mongodb.MongoDbFactory; +import org.springframework.data.mongodb.core.MongoOperations; +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.SimpleMongoDbFactory; + +import com.mongodb.Mongo; +import com.mongodb.MongoException; + +/** + * Simple component exposing a {@link MongoOperations} instance as CDI bean. + * + * @author Oliver Gierke + */ +class MongoTemplateProducer { + + @Produces + @ApplicationScoped + public MongoOperations createMongoTemplate() throws UnknownHostException, MongoException { + + MongoDbFactory factory = new SimpleMongoDbFactory(new Mongo(), "database"); + return new MongoTemplate(factory); + } +} diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/cdi/PersonRepository.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/cdi/PersonRepository.java new file mode 100644 index 000000000..f86c06397 --- /dev/null +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/cdi/PersonRepository.java @@ -0,0 +1,28 @@ +/* + * Copyright 2012 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.mongodb.repository.cdi; + +import org.springframework.data.mongodb.repository.Person; +import org.springframework.data.repository.Repository; + +public interface PersonRepository extends Repository { + + void deleteAll(); + + Person save(Person person); + + Person findOne(String id); +} diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/cdi/RepositoryClient.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/cdi/RepositoryClient.java new file mode 100644 index 000000000..34d681bcb --- /dev/null +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/cdi/RepositoryClient.java @@ -0,0 +1,35 @@ +/* + * Copyright 2012 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.mongodb.repository.cdi; + +import javax.inject.Inject; + +/** + * + * @author Oliver Gierke + */ +class RepositoryClient { + + @Inject + PersonRepository repository; + + /** + * @return the repository + */ + public PersonRepository getRepository() { + return repository; + } +} diff --git a/spring-data-mongodb/src/test/resources/META-INF/beans.xml b/spring-data-mongodb/src/test/resources/META-INF/beans.xml new file mode 100644 index 000000000..73ae3a251 --- /dev/null +++ b/spring-data-mongodb/src/test/resources/META-INF/beans.xml @@ -0,0 +1,6 @@ + + + + diff --git a/spring-data-mongodb/template.mf b/spring-data-mongodb/template.mf index 2d8e9e162..ae1431b31 100644 --- a/spring-data-mongodb/template.mf +++ b/spring-data-mongodb/template.mf @@ -10,6 +10,7 @@ Import-Template: com.mongodb.*;version="0", com.mysema.query.*;version="[2.1.1, 3.0.0)";resolution:=optional, javax.annotation.processing.*;version="0", + javax.enterprise.*;version="${cdi.version:[=.=.=,+1.0.0)}";resolution:=optional, javax.tools.*;version="0", org.aopalliance.*;version="[1.0.0, 2.0.0)";resolution:=optional, org.apache.commons.collections15.*;version="[4.0.0,5.0.0)";resolution:=optional,