From 6cfecbcba57cf65b41808321b9567404d681fb87 Mon Sep 17 00:00:00 2001 From: Michael Hunger Date: Tue, 24 Aug 2010 21:42:48 +0200 Subject: [PATCH] enititymanager persistenceprovider, EM-Factory --- pom.xml | 5 + .../graph/neo4j/Neo4jEntityManager.java | 19 ++- .../neo4j/Neo4jEntityManagerFactory.java | 50 ++++++ .../graph/neo4j/Neo4jJpaDialect.java | 70 ++++++++ .../graph/neo4j/Neo4jNodeBacking.aj | 3 - .../graph/neo4j/Neo4jPersistenceProvider.java | 34 ++++ .../graph/neo4j/Neo4jEntityManagerTest.java | 157 ++++++++++++++++++ src/test/resources/META-INF/persistence.xml | 10 ++ .../Neo4jGraphPersistenceTest-context.xml | 12 +- 9 files changed, 353 insertions(+), 7 deletions(-) create mode 100644 src/main/java/org/springframework/persistence/graph/neo4j/Neo4jEntityManagerFactory.java create mode 100644 src/main/java/org/springframework/persistence/graph/neo4j/Neo4jJpaDialect.java create mode 100644 src/main/java/org/springframework/persistence/graph/neo4j/Neo4jPersistenceProvider.java create mode 100644 src/test/java/org/springframework/persistence/graph/neo4j/Neo4jEntityManagerTest.java create mode 100644 src/test/resources/META-INF/persistence.xml diff --git a/pom.xml b/pom.xml index 027ad9e7e..da3f1da7e 100644 --- a/pom.xml +++ b/pom.xml @@ -134,6 +134,11 @@ spring-jdbc ${spring.version} + + org.springframework + spring-orm + ${spring.version} + org.springframework spring-tx diff --git a/src/main/java/org/springframework/persistence/graph/neo4j/Neo4jEntityManager.java b/src/main/java/org/springframework/persistence/graph/neo4j/Neo4jEntityManager.java index 2d9ad50bf..2b6db26a1 100644 --- a/src/main/java/org/springframework/persistence/graph/neo4j/Neo4jEntityManager.java +++ b/src/main/java/org/springframework/persistence/graph/neo4j/Neo4jEntityManager.java @@ -2,6 +2,7 @@ package org.springframework.persistence.graph.neo4j; import org.neo4j.graphdb.GraphDatabaseService; import org.neo4j.graphdb.Node; +import org.neo4j.graphdb.Relationship; import org.neo4j.kernel.EmbeddedGraphDatabase; import org.springframework.persistence.support.EntityInstantiator; import org.springframework.stereotype.Service; @@ -15,7 +16,7 @@ import javax.transaction.*; * @since 20.08.2010 * TODO Relationships */ -@Service +//@Service public class Neo4jEntityManager implements EntityManager { @Resource GraphDatabaseService graphDatabaseService; @@ -24,7 +25,15 @@ public class Neo4jEntityManager implements EntityManager { EntityInstantiator nodeInstantiator; private volatile boolean closed; - private Node nodeFor(Object entity) { + public Neo4jEntityManager(final GraphDatabaseService graphDatabaseService, final EntityInstantiator nodeInstantiator) { + this.graphDatabaseService = graphDatabaseService; + this.nodeInstantiator = nodeInstantiator; + } + + public Neo4jEntityManager() { + } + + private Node nodeFor(final Object entity) { checkClosed(); if (!(entity instanceof NodeBacked)) throw new IllegalArgumentException("Not a nodebacked entity " + entity); final Node node = ((NodeBacked) entity).getUnderlyingNode(); @@ -45,7 +54,11 @@ public class Neo4jEntityManager implements EntityManager { @Override public void remove(final Object entity) { - nodeFor(entity).delete(); + final Node node = nodeFor(entity); + for (final Relationship r : node.getRelationships()) { + r.delete(); + } + node.delete(); } @SuppressWarnings({"unchecked"}) diff --git a/src/main/java/org/springframework/persistence/graph/neo4j/Neo4jEntityManagerFactory.java b/src/main/java/org/springframework/persistence/graph/neo4j/Neo4jEntityManagerFactory.java new file mode 100644 index 000000000..19f7d1741 --- /dev/null +++ b/src/main/java/org/springframework/persistence/graph/neo4j/Neo4jEntityManagerFactory.java @@ -0,0 +1,50 @@ +package org.springframework.persistence.graph.neo4j; + +import org.neo4j.graphdb.GraphDatabaseService; +import org.neo4j.graphdb.Node; +import org.springframework.beans.factory.annotation.Configurable; +import org.springframework.persistence.support.EntityInstantiator; + +import javax.annotation.Resource; +import javax.persistence.EntityManager; +import javax.persistence.EntityManagerFactory; +import java.util.Map; + +/** + * @author Michael Hunger + * @since 23.08.2010 + */ +public class Neo4jEntityManagerFactory implements EntityManagerFactory { + @Resource + GraphDatabaseService graphDatabaseService; + @Resource + EntityInstantiator nodeInstantiator; + + public Neo4jEntityManagerFactory() { + } + + public Neo4jEntityManagerFactory(GraphDatabaseService graphDatabaseService, EntityInstantiator nodeInstantiator) { + this.graphDatabaseService = graphDatabaseService; + this.nodeInstantiator = nodeInstantiator; + } + + @Override + public EntityManager createEntityManager() { + return new Neo4jEntityManager(graphDatabaseService,nodeInstantiator); + } + + /* TODO handle different directories for target datastore */ + @Override + public EntityManager createEntityManager(Map map) { + return new Neo4jEntityManager(graphDatabaseService,nodeInstantiator); + } + + @Override + public void close() { + } + + @Override + public boolean isOpen() { + return true; + } +} diff --git a/src/main/java/org/springframework/persistence/graph/neo4j/Neo4jJpaDialect.java b/src/main/java/org/springframework/persistence/graph/neo4j/Neo4jJpaDialect.java new file mode 100644 index 000000000..04977cbba --- /dev/null +++ b/src/main/java/org/springframework/persistence/graph/neo4j/Neo4jJpaDialect.java @@ -0,0 +1,70 @@ +package org.springframework.persistence.graph.neo4j; + +import org.springframework.dao.DataAccessException; +import org.springframework.jdbc.datasource.ConnectionHandle; +import org.springframework.orm.jpa.EntityManagerFactoryPlusOperations; +import org.springframework.orm.jpa.EntityManagerPlusOperations; +import org.springframework.orm.jpa.JpaDialect; +import org.springframework.transaction.TransactionDefinition; +import org.springframework.transaction.TransactionException; + +import javax.persistence.EntityManager; +import javax.persistence.EntityManagerFactory; +import javax.persistence.PersistenceException; +import java.sql.SQLException; + +/** + * @author Michael Hunger + * @since 23.08.2010 + */ +public class Neo4jJpaDialect implements JpaDialect { + @Override + public boolean supportsEntityManagerFactoryPlusOperations() { + return false; + } + + @Override + public boolean supportsEntityManagerPlusOperations() { + return false; + } + + @Override + public EntityManagerFactoryPlusOperations getEntityManagerFactoryPlusOperations(final EntityManagerFactory entityManagerFactory) { + return null; + } + + @Override + public EntityManagerPlusOperations getEntityManagerPlusOperations(final EntityManager entityManager) { + return null; + } + + // todo + @Override + public Object beginTransaction(final EntityManager entityManager, final TransactionDefinition transactionDefinition) throws PersistenceException, SQLException, TransactionException { + return null; + } + + @Override + public Object prepareTransaction(final EntityManager entityManager, final boolean b, final String s) throws PersistenceException { + return null; + } + + @Override + public void cleanupTransaction(final Object o) { + } + + @Override + public ConnectionHandle getJdbcConnection(final EntityManager entityManager, final boolean b) throws PersistenceException, SQLException { + return null; + } + + @Override + public void releaseJdbcConnection(final ConnectionHandle connectionHandle, final EntityManager entityManager) throws PersistenceException, SQLException { + } + + // todo + @Override + public DataAccessException translateExceptionIfPossible(final RuntimeException e) { + return null; + } +} diff --git a/src/main/java/org/springframework/persistence/graph/neo4j/Neo4jNodeBacking.aj b/src/main/java/org/springframework/persistence/graph/neo4j/Neo4jNodeBacking.aj index bb4316b2f..610a0ccdf 100644 --- a/src/main/java/org/springframework/persistence/graph/neo4j/Neo4jNodeBacking.aj +++ b/src/main/java/org/springframework/persistence/graph/neo4j/Neo4jNodeBacking.aj @@ -62,9 +62,6 @@ public aspect Neo4jNodeBacking extends AbstractTypeAnnotatingMixinFields nodeInstantiator; + + @Override + public EntityManagerFactory createEntityManagerFactory(String emName, Map map) { + return new Neo4jEntityManagerFactory(graphDatabaseService,nodeInstantiator); + } + + @Override + public EntityManagerFactory createContainerEntityManagerFactory(PersistenceUnitInfo info, Map map) { + return new Neo4jEntityManagerFactory(graphDatabaseService,nodeInstantiator); + } +} diff --git a/src/test/java/org/springframework/persistence/graph/neo4j/Neo4jEntityManagerTest.java b/src/test/java/org/springframework/persistence/graph/neo4j/Neo4jEntityManagerTest.java new file mode 100644 index 000000000..2efd5053e --- /dev/null +++ b/src/test/java/org/springframework/persistence/graph/neo4j/Neo4jEntityManagerTest.java @@ -0,0 +1,157 @@ +package org.springframework.persistence.graph.neo4j; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import javax.annotation.Resource; +import javax.persistence.EntityManager; +import javax.persistence.EntityTransaction; +import javax.persistence.PersistenceContext; + +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.neo4j.graphdb.GraphDatabaseService; +import org.neo4j.graphdb.Node; +import org.springframework.dao.InvalidDataAccessApiUsageException; +import org.springframework.persistence.test.Person; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.transaction.annotation.Transactional; + +/** + * @author Michael Hunger + * @since 20.08.2010 + */ +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = {"classpath:org/springframework/persistence/test/graph/Neo4jGraphPersistenceTest-context.xml"}) +@Transactional +public class Neo4jEntityManagerTest { + @Resource + GraphDatabaseService graphDatabaseService; + @PersistenceContext(unitName="neo4j-persistence") + EntityManager entityManager; + + Person person; + private Node node; + + @Before + public void cleanDb() { + Neo4jHelper.cleanDb(graphDatabaseService); + node = graphDatabaseService.createNode(); + person = new Person(node); + } + + @Test + public void testPersist() throws Exception { + entityManager.persist(person); + } + + @Test + public void testMerge() throws Exception { + Person merged=entityManager.merge(person); + assertEquals(person,merged); + } + @Ignore + @Test + public void testRemove() throws Exception { + long nodeId=node.getId(); + entityManager.remove(person); + final Node foundNode = graphDatabaseService.getNodeById(nodeId); + assertNull(foundNode); + } + @Test + public void testFind() throws Exception { + final Person found = entityManager.find(Person.class, node.getId()); + assertEquals(person,found); + } + + @Test + public void testGetReference() throws Exception { + final Person found = entityManager.getReference(Person.class, node.getId()); + assertEquals(person,found); + } + + @Test + public void testFlush() throws Exception { + } + + @Test + public void testSetFlushMode() throws Exception { + } + + @Test + public void testGetFlushMode() throws Exception { + } + + @Test + public void testLock() throws Exception { + } + + @Test + public void testRefresh() throws Exception { + entityManager.refresh(person); + assertEquals(node, person.getUnderlyingNode()); + } + @Test + public void testClear() throws Exception { + } + + @Test(expected=InvalidDataAccessApiUsageException.class) + public void removeThrowsErrorForNonNodeBacked() throws Exception { + entityManager.remove(new Object()); + } + + @Test + public void testContains() throws Exception { + final Person p2 = new Person("Rod",39); + assertTrue(entityManager.contains(person)); + assertTrue(entityManager.contains(p2)); + assertFalse(entityManager.contains(new Object())); + } +/* + @Test + public void testCreateQuery() throws Exception { + } + + @Test + public void testCreateNamedQuery() throws Exception { + } + + @Test + public void testCreateNativeQuery() throws Exception { + } + + @Test + public void testJoinTransaction() throws Exception { + } +*/ + @Test + public void testGetDelegate() throws Exception { + assertTrue(entityManager.getDelegate() instanceof GraphDatabaseService); + } + + @Test(expected=InvalidDataAccessApiUsageException.class) + public void testClose() throws Exception { + entityManager.close(); + assertFalse(entityManager.isOpen()); + entityManager.refresh(person); + } + + @Test + public void testIsOpen() throws Exception { + assertTrue(entityManager.isOpen()); + } + + @Test + public void testGetTransaction() throws Exception { + final EntityTransaction transaction = entityManager.getTransaction(); + assertFalse(transaction.getRollbackOnly()); + person.setName("Michael"); + entityManager.persist(person); + transaction.setRollbackOnly(); + } +} diff --git a/src/test/resources/META-INF/persistence.xml b/src/test/resources/META-INF/persistence.xml new file mode 100644 index 000000000..3c50f0d48 --- /dev/null +++ b/src/test/resources/META-INF/persistence.xml @@ -0,0 +1,10 @@ + + + + + org.springframework.persistence.graph.neo4j.Neo4jPersistenceProvider + + + + + diff --git a/src/test/resources/org/springframework/persistence/test/graph/Neo4jGraphPersistenceTest-context.xml b/src/test/resources/org/springframework/persistence/test/graph/Neo4jGraphPersistenceTest-context.xml index 559adff73..682ba9340 100644 --- a/src/test/resources/org/springframework/persistence/test/graph/Neo4jGraphPersistenceTest-context.xml +++ b/src/test/resources/org/springframework/persistence/test/graph/Neo4jGraphPersistenceTest-context.xml @@ -125,5 +125,15 @@ - + + + + + + + + + + +