From f7ddde14a0b82678d603d86daf88dbd751f8d85b Mon Sep 17 00:00:00 2001 From: Michael Hunger Date: Wed, 23 Mar 2011 22:20:19 +0100 Subject: [PATCH] support for rest-server-addon --- spring-data-graph-parent/pom.xml | 12 ++- spring-data-neo4j/pom.xml | 10 +++ .../config/DataGraphBeanDefinitionParser.java | 23 ++++- ...gPropertyFieldAccessorListenerFactory.java | 2 +- .../graph/neo4j/finder/AbstractFinder.java | 1 - ...rovidedClassPathXmlApplicationContext.java | 29 +++++++ .../neo4j/server/SpringPluginInitializer.java | 84 +++++++++++++++++++ 7 files changed, 157 insertions(+), 4 deletions(-) create mode 100644 spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/server/ProvidedClassPathXmlApplicationContext.java create mode 100644 spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/server/SpringPluginInitializer.java diff --git a/spring-data-graph-parent/pom.xml b/spring-data-graph-parent/pom.xml index dbedc3d67..9d4a26f09 100644 --- a/spring-data-graph-parent/pom.xml +++ b/spring-data-graph-parent/pom.xml @@ -16,7 +16,7 @@ 1.5.10 3.0.5.RELEASE 1.0.0.BUILD-SNAPSHOT - 1.3.M04 + 1.3-SNAPSHOT 1.6.11.M2 @@ -229,6 +229,16 @@ tests test + + org.neo4j + server-api + ${neo4j.version} + + + commons-configuration + commons-configuration + 1.6 + org.ow2.jotm diff --git a/spring-data-neo4j/pom.xml b/spring-data-neo4j/pom.xml index 1bb7d7048..e7f147f48 100644 --- a/spring-data-neo4j/pom.xml +++ b/spring-data-neo4j/pom.xml @@ -132,6 +132,16 @@ test + + org.neo4j + server-api + + + + commons-configuration + commons-configuration + + org.hibernate.javax.persistence diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/config/DataGraphBeanDefinitionParser.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/config/DataGraphBeanDefinitionParser.java index eebb1bbf2..614ba28c5 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/config/DataGraphBeanDefinitionParser.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/config/DataGraphBeanDefinitionParser.java @@ -1,10 +1,14 @@ package org.springframework.data.graph.neo4j.config; import org.neo4j.kernel.EmbeddedGraphDatabase; +import org.springframework.beans.factory.annotation.Autowire; import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.beans.factory.support.BeanNameGenerator; import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser; import org.springframework.beans.factory.xml.ParserContext; +import org.springframework.context.annotation.ConfigurationClassPostProcessor; import org.w3c.dom.Element; import static org.springframework.util.StringUtils.hasText; @@ -15,12 +19,29 @@ public class DataGraphBeanDefinitionParser extends AbstractBeanDefinitionParser @Override protected AbstractBeanDefinition parseInternal(Element element, ParserContext context) { - BeanDefinitionBuilder configBuilder = BeanDefinitionBuilder.rootBeanDefinition(Neo4jConfiguration.class); + BeanDefinitionBuilder configBuilder = createConfigurationBeanDefinition(); setupGraphDatabase(element, context, configBuilder); setupEntityManagerFactory(element, configBuilder); + setupConfigurationClassPostProcessor(context); return getSourcedBeanDefinition(configBuilder, element, context); } + private BeanDefinitionBuilder createConfigurationBeanDefinition() { + BeanDefinitionBuilder configBuilder = BeanDefinitionBuilder.rootBeanDefinition(Neo4jConfiguration.class); + configBuilder.setAutowireMode(Autowire.BY_TYPE.value()); + return configBuilder; + } + + private void setupConfigurationClassPostProcessor(final ParserContext parserContext) { + BeanDefinitionRegistry beanDefinitionRegistry = parserContext.getRegistry(); + + BeanDefinitionBuilder configurationClassPostProcessor = BeanDefinitionBuilder.rootBeanDefinition(ConfigurationClassPostProcessor.class); + BeanNameGenerator beanNameGenerator = parserContext.getReaderContext().getReader().getBeanNameGenerator(); + AbstractBeanDefinition configurationClassPostProcessorBeanDefinition = configurationClassPostProcessor.getBeanDefinition(); + String beanName = beanNameGenerator.generateBeanName(configurationClassPostProcessorBeanDefinition, beanDefinitionRegistry); + beanDefinitionRegistry.registerBeanDefinition(beanName, configurationClassPostProcessorBeanDefinition); + } + @Override protected boolean shouldGenerateId() { return true; diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/IndexingPropertyFieldAccessorListenerFactory.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/IndexingPropertyFieldAccessorListenerFactory.java index 85e075b65..a13d689be 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/IndexingPropertyFieldAccessorListenerFactory.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/IndexingPropertyFieldAccessorListenerFactory.java @@ -20,7 +20,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.neo4j.graphdb.PropertyContainer; import org.neo4j.graphdb.index.Index; -import org.neo4j.index.impl.lucene.ValueContext; +import org.neo4j.index.lucene.ValueContext; import org.springframework.data.annotation.Indexed; import org.springframework.data.graph.annotation.NodeEntity; import org.springframework.data.graph.core.GraphBacked; diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/finder/AbstractFinder.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/finder/AbstractFinder.java index 924b351c7..90bd5fe9d 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/finder/AbstractFinder.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/finder/AbstractFinder.java @@ -6,7 +6,6 @@ import org.neo4j.graphdb.PropertyContainer; import org.neo4j.graphdb.index.Index; import org.neo4j.graphdb.index.IndexHits; import org.neo4j.helpers.collection.IterableWrapper; -import org.neo4j.index.impl.lucene.ValueContext; import org.springframework.data.graph.core.GraphBacked; import org.springframework.data.graph.neo4j.support.GraphDatabaseContext; diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/server/ProvidedClassPathXmlApplicationContext.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/server/ProvidedClassPathXmlApplicationContext.java new file mode 100644 index 000000000..e44496e98 --- /dev/null +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/server/ProvidedClassPathXmlApplicationContext.java @@ -0,0 +1,29 @@ +package org.springframework.data.graph.neo4j.server; + +import org.neo4j.graphdb.GraphDatabaseService; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.context.support.ClassPathXmlApplicationContext; + +/** + * Context that merges the provided graph database service with the given context locations, + * so that spring beans that consume a graph database are populated properly. + */ +public class ProvidedClassPathXmlApplicationContext extends ClassPathXmlApplicationContext { + + private final GraphDatabaseService database; + + public ProvidedClassPathXmlApplicationContext(GraphDatabaseService database, final String[] locations) + throws org.springframework.beans.BeansException { + super(); + setConfigLocations(locations); + this.database = database; + refresh(); + } + + @Override + protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) { + super.prepareBeanFactory(beanFactory); + beanFactory.registerResolvableDependency(GraphDatabaseService.class, database); + beanFactory.registerSingleton("graphDatabaseService", database); + } +} \ No newline at end of file diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/server/SpringPluginInitializer.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/server/SpringPluginInitializer.java new file mode 100644 index 000000000..c67195855 --- /dev/null +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/server/SpringPluginInitializer.java @@ -0,0 +1,84 @@ +package org.springframework.data.graph.neo4j.server; + +import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.beanutils.BeanFactory; +import org.neo4j.graphdb.GraphDatabaseService; +import org.neo4j.server.plugins.PluginLifecycle; +import org.neo4j.server.plugins.Injectable; +import org.springframework.context.ApplicationContext; + +import java.util.ArrayList; +import java.util.Collection; + +/** + * Initializer to run Spring Data Graph based Server Plugins in a Neo4j REST-server. It takes the list of + * config locations and a number of spring beans from those contexts that should be exposed + * as injectable dependencies with a Jersey @Context.
+ * For example:
+ *
+ * class MyInitializer extends SpringPluginInitializer {
+ *     public MyInitializer() {
+ *         super(new String[]{"myContext.xml"},"finderFactory","myRepository");
+ *     }
+ * }
+ * 
+ */ +public abstract class SpringPluginInitializer implements PluginLifecycle { + private String[] contextLocations; + private String[] exposedBeans; + protected ProvidedClassPathXmlApplicationContext ctx; + + public SpringPluginInitializer(String[] contextLocations, String... exposedBeans) { + this.contextLocations = contextLocations; + this.exposedBeans = exposedBeans; + } + + /** + * Binds the provided graph database to the spring contexts so that spring beans that consume a + * graph database can be populated.
+ * @param graphDatabaseService of the Neo4j server + * @param config of the Neo4j Server + * @return Exposes the requested Spring beans as @{see Injectable}s + */ + @Override + public Collection> start(GraphDatabaseService graphDatabaseService, Configuration config) { + ctx = new ProvidedClassPathXmlApplicationContext(graphDatabaseService, contextLocations); + Collection> result = new ArrayList>(exposedBeans.length); + for (final String exposedBean : exposedBeans) { + result.add(new SpringBeanInjectable(SpringPluginInitializer.this.ctx, exposedBean)); + } + return result; + } + + /** + * closes the spring context + */ + public void stop() { + if (ctx!=null) { + ctx.close(); + } + } + + /** + * provides access to the Spring bean, proxying the @{see Injectable} + * @param optional type of the bean + */ + private static class SpringBeanInjectable implements Injectable { + private final String exposedBean; + protected ApplicationContext ctx; + + public SpringBeanInjectable(final ApplicationContext ctx, String exposedBean) { + this.exposedBean = exposedBean; + this.ctx = ctx; + } + + public T getValue() { + return (T) ctx.getBean(exposedBean); + + } + + public Class getType() { + return (Class) ctx.getType(exposedBean); + } + } +}