diff --git a/pom.xml b/pom.xml index a7ca98279..733c5fca0 100644 --- a/pom.xml +++ b/pom.xml @@ -189,22 +189,28 @@ org.springframework.data spring-datastore-cross-store 1.0.0.M1-SNAPSHOT + + + javax.persistence + persistence-api + + + + - javax.persistence - persistence-api - 1.0 + org.hibernate.javax.persistence + hibernate-jpa-2.0-api + 1.0.0.Final - - - org.hsqldb - hsqldb - 1.8.0.10 - - + diff --git a/src/main/java/org/springframework/datastore/graph/neo4j/jpa/Neo4JQuery.java b/src/main/java/org/springframework/datastore/graph/neo4j/jpa/Neo4JQuery.java index 01a7d25f5..f986b3715 100644 --- a/src/main/java/org/springframework/datastore/graph/neo4j/jpa/Neo4JQuery.java +++ b/src/main/java/org/springframework/datastore/graph/neo4j/jpa/Neo4JQuery.java @@ -3,67 +3,73 @@ package org.springframework.datastore.graph.neo4j.jpa; import org.springframework.datastore.graph.api.NodeBacked; import org.springframework.datastore.graph.neo4j.finder.Finder; import org.springframework.datastore.graph.neo4j.finder.FinderFactory; +import org.springframework.datastore.graph.neo4j.support.Tuple2; -import javax.persistence.FlushModeType; -import javax.persistence.Query; -import javax.persistence.TemporalType; +import javax.persistence.*; import javax.persistence.spi.PersistenceUnitInfo; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; +import static org.springframework.datastore.graph.neo4j.jpa.Neo4jQueryParameter.param; +import static org.springframework.datastore.graph.neo4j.support.Tuple2._; +import static org.springframework.util.ObjectUtils.nullSafeEquals; + /** * @author Michael Hunger * @since 29.08.2010 */ -public class Neo4JQuery implements Query { - protected final Finder finder; - protected final Class entityClass; +public class Neo4JQuery implements TypedQuery { + protected final Finder finder; + protected final Class entityClass; protected final String qlString; private final PersistenceUnitInfo info; private final Pattern fromPattern = Pattern.compile("^.*\\bfrom\\s+([A-Z][A-Za-z0-9]+)\\b.*"); private int startPosition=0; private int maxResult=-1; - private QueryExectuor queryExectuor; + private QueryExectuor queryExectuor; + private Map, Tuple2> parameters=new HashMap, Tuple2>(); - public Neo4JQuery(final String qlString, final FinderFactory finderFactory, final PersistenceUnitInfo info) { + public Neo4JQuery(final String qlString, final FinderFactory finderFactory, final PersistenceUnitInfo info, final Class entityClass) { this.qlString = qlString; this.info = info; final Matcher matcher = fromPattern.matcher(qlString); if (matcher.matches()) { final String shortName = matcher.group(1); - entityClass=getEntityClass(shortName); - finder = finderFactory.getFinderForClass(entityClass); + if (entityClass!=null) this.entityClass= entityClass; + else this.entityClass=getEntityClass(shortName); + finder = finderFactory.getFinderForClass(this.entityClass); queryExectuor = createExecutor(qlString); } else { throw new IllegalAccessError("Unable to parse query "+qlString); } } - private QueryExectuor createExecutor(String qlString) { - if (qlString.contains(" count(")) return new QueryExectuor() { + private QueryExectuor createExecutor(final String qlString) { + if (qlString.contains(" count(")) return new QueryExectuor() { @Override - protected Iterable findList() { - return Collections.singleton(finder.count()); + protected Long findObject() { + return finder.count(); } }; - return new QueryExectuor() { + return new QueryExectuor() { @Override - protected Iterable findList() { + protected Iterable findList() { return finder.findAll(); } }; } - abstract static class QueryExectuor { - protected abstract Iterable findList(); + abstract static class QueryExectuor { + protected Iterable findList() { return Collections.singleton(findObject()); } + protected T findObject() { return null; } } - private Class getEntityClass(final String shortName) { + private Class getEntityClass(final String shortName) { try { final String className = getFQN(shortName); - return (Class) Class.forName(className); + return (Class) Class.forName(className); } catch (ClassNotFoundException e) { throw new IllegalStateException("Error resolving class "+shortName,e); } @@ -77,10 +83,10 @@ public class Neo4JQuery implements Query { } @Override - public List getResultList() { - final List result = new ArrayList(); + public List getResultList() { + final List result = new ArrayList(); int count=0; - for (final Object nodeBacked : queryExectuor.findList()) { + for (final T nodeBacked : (Iterable)queryExectuor.findList()) { if (maxResult>=0 && count==startPosition+maxResult) break; if (count>=startPosition) { result.add(nodeBacked); @@ -91,9 +97,9 @@ public class Neo4JQuery implements Query { } @Override - public Object getSingleResult() { + public T getSingleResult() { final Iterator found = queryExectuor.findList().iterator(); - return found.hasNext() ? found.next() : null; // todo errors when none or too many ? + return found.hasNext() ? (T) found.next() : null; // todo errors when none or too many ? } @Override @@ -102,54 +108,174 @@ public class Neo4JQuery implements Query { } @Override - public Query setMaxResults(final int maxResult) { + public TypedQuery setMaxResults(final int maxResult) { this.maxResult = maxResult; return this; } @Override - public Query setFirstResult(final int startPosition) { + public int getMaxResults() { + return maxResult; + } + + @Override + public TypedQuery setFirstResult(final int startPosition) { this.startPosition = startPosition; return this; } @Override - public Query setHint(final String hintName, final Object value) { + public int getFirstResult() { + return startPosition; + } + + @Override + public TypedQuery setHint(final String hintName, final Object value) { return this; } @Override - public Query setParameter(final String name, final Object value) { + public Map getHints() { + return Collections.emptyMap(); + } + + @Override + public

TypedQuery setParameter(final Parameter

parameter, final P value) { + this.parameters.put(parameter, value(value)); + return this; + } + + private static

Tuple2 value(final P value) { + return _(value,(TemporalType)null); + } + + @Override + public TypedQuery setParameter(final Parameter parameter, final Calendar calendar, final TemporalType temporalType) { + this.parameters.put(parameter,_(calendar,temporalType)); return this; } @Override - public Query setParameter(final String name, final Date value, final TemporalType temporalType) { + public TypedQuery setParameter(final Parameter parameter, final Date date, final TemporalType temporalType) { + this.parameters.put(parameter,_(date,temporalType)); return this; } @Override - public Query setParameter(final String name, final Calendar value, final TemporalType temporalType) { + public TypedQuery setParameter(final String name, final Object value) { + this.parameters.put(param(name),value(value)); return this; } @Override - public Query setParameter(final int position, final Object value) { + public TypedQuery setParameter(final String name, final Date value, final TemporalType temporalType) { + this.parameters.put(param(name),_(value,temporalType)); return this; } @Override - public Query setParameter(final int position, final Date value, final TemporalType temporalType) { + public TypedQuery setParameter(final String name, final Calendar value, final TemporalType temporalType) { + this.parameters.put(param(name),_(value,temporalType)); return this; } @Override - public Query setParameter(final int position, final Calendar value, final TemporalType temporalType) { + public TypedQuery setParameter(final int position, final Object value) { + this.parameters.put(param(position),value(value)); return this; } @Override - public Query setFlushMode(final FlushModeType flushMode) { + public TypedQuery setParameter(final int position, final Date value, final TemporalType temporalType) { + this.parameters.put(param(position),value(value)); return this; } + + @Override + public Set> getParameters() { + return parameters.keySet(); + } + + @Override + public Parameter getParameter(final String name) { + for (final Parameter parameter : parameters.keySet()) { + if (nullSafeEquals(parameter.getName(),name)) return parameter; + } + return null; + } + + @Override + public Parameter getParameter(final String name, final Class type) { + for (final Parameter parameter : parameters.keySet()) { + if (nullSafeEquals(parameter.getName(),name) && nullSafeEquals(type,parameter.getParameterType())) return (Parameter) parameter; + } + return null; + } + + @Override + public Parameter getParameter(final int index) { + for (final Parameter parameter : parameters.keySet()) { + if (nullSafeEquals(parameter.getPosition(),index)) return parameter; + } + return null; + } + + @Override + public Parameter getParameter(final int index, final Class type) { + for (final Parameter parameter : parameters.keySet()) { + if (nullSafeEquals(parameter.getPosition(),index) && nullSafeEquals(type,parameter.getParameterType())) return (Parameter) parameter; + } + return null; + } + + @Override + public boolean isBound(final Parameter parameter) { + return parameters.containsKey(parameter); + } + + @Override + public T getParameterValue(final Parameter parameter) { + return (T) parameters.get(parameter)._1; + } + + @Override + public Object getParameterValue(final String name) { + return getParameterValue(getParameter(name)); + } + + @Override + public Object getParameterValue(final int index) { + return getParameterValue(getParameter(index)); + } + + @Override + public TypedQuery setParameter(final int position, final Calendar value, final TemporalType temporalType) { + parameters.put(param(position),_(value,temporalType)); + return this; + } + + @Override + public TypedQuery setFlushMode(final FlushModeType flushMode) { + return this; + } + + @Override + public FlushModeType getFlushMode() { + return null; + } + + @Override + public TypedQuery setLockMode(final LockModeType lockModeType) { + return null; + } + + @Override + public LockModeType getLockMode() { + return null; + } + + @Override + public T unwrap(final Class tClass) { + return null; + } } diff --git a/src/main/java/org/springframework/datastore/graph/neo4j/jpa/Neo4jEntityManager.java b/src/main/java/org/springframework/datastore/graph/neo4j/jpa/Neo4jEntityManager.java index 33a9d9020..a1bd65228 100644 --- a/src/main/java/org/springframework/datastore/graph/neo4j/jpa/Neo4jEntityManager.java +++ b/src/main/java/org/springframework/datastore/graph/neo4j/jpa/Neo4jEntityManager.java @@ -10,7 +10,11 @@ import org.springframework.datastore.graph.neo4j.finder.FinderFactory; import org.springframework.persistence.support.EntityInstantiator; import org.springframework.transaction.annotation.Transactional; +import javax.annotation.Resource; import javax.persistence.*; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.metamodel.Metamodel; import javax.persistence.spi.PersistenceUnitInfo; import javax.transaction.*; import java.util.Map; @@ -33,7 +37,10 @@ public class Neo4jEntityManager implements EntityManager { private volatile boolean closed; private final FinderFactory finderFactory; - public Neo4jEntityManager(final GraphDatabaseService graphDatabaseService, final EntityInstantiator nodeInstantiator, PersistenceUnitInfo info, Map params, IndexService indexService) { + @Resource + private Neo4jEntityManagerFactory neo4jEntityManagerFactory; + + public Neo4jEntityManager(final GraphDatabaseService graphDatabaseService, final EntityInstantiator nodeInstantiator, final PersistenceUnitInfo info, final Map params, final IndexService indexService) { this.graphDatabaseService = graphDatabaseService; this.nodeInstantiator = nodeInstantiator; this.info = info; @@ -59,7 +66,7 @@ public class Neo4jEntityManager implements EntityManager { checkClosed(); final Transaction tx = graphDatabaseService.beginTx(); try { - + //todo nodebacked justwriteback, no check tx.success(); } finally { tx.finish(); @@ -68,6 +75,7 @@ public class Neo4jEntityManager implements EntityManager { @Override public T merge(final T entity) { + // todo nodebacked merge checkClosed(); return entity; } @@ -93,6 +101,21 @@ public class Neo4jEntityManager implements EntityManager { return (T) nodeInstantiator.createEntityFromState(node, (Class) entityClass); } + @Override + public T find(final Class entityClass, final Object primaryKey, final Map params) { + return find(entityClass, primaryKey); + } + + @Override + public T find(final Class entityClass, final Object primaryKey, final LockModeType lockModeType) { + return find(entityClass, primaryKey); + } + + @Override + public T find(final Class entityClass, final Object primaryKey, final LockModeType lockModeType, final Map params) { + return find(entityClass, primaryKey); + } + @Override public T getReference(final Class entityClass, final Object primaryKey) { return find(entityClass, primaryKey); @@ -115,14 +138,34 @@ public class Neo4jEntityManager implements EntityManager { } @Override - public void lock(final Object entity, final LockModeType lockMode) { + public void lock(final Object entity, final LockModeType lockModeType) { nodeFor(entity); } + @Override + public void lock(final Object entity, final LockModeType lockModeType, final Map params) { + lock(entity,lockModeType); + } + @Override public void refresh(final Object entity) { + // todo nodebacked.refresh, throw away dirty nodeFor(entity); - // todo NodeBacked.refresh -> discard dirty + } + + @Override + public void refresh(final Object entity, final Map params) { + refresh(entity); + } + + @Override + public void refresh(final Object entity, final LockModeType lockModeType) { + refresh(entity); + } + + @Override + public void refresh(final Object entity, final LockModeType lockModeType, final Map params) { + refresh(entity); } /** @@ -133,6 +176,10 @@ public class Neo4jEntityManager implements EntityManager { checkClosed(); } + @Override + public void detach(final Object entity) { + } + @Override public boolean contains(final Object entity) { checkClosed(); @@ -143,14 +190,44 @@ public class Neo4jEntityManager implements EntityManager { } } + @Override + public LockModeType getLockMode(final Object entity) { + return LockModeType.NONE; // todo use neo4j locks? + } + + @Override + public void setProperty(final String name, final Object value) { + params.put(name,value); + } + + @Override + public Map getProperties() { + return params; + } + /* TODO Gremlin */ @Override public Query createQuery(final String qlString) { + return createQuery(qlString,null); + } + + @Override + public TypedQuery createQuery(final CriteriaQuery query) { + return null; + } + + @SuppressWarnings({"unchecked"}) + @Override + public TypedQuery createQuery(final String qlString, final Class entityClass) { checkClosed(); - return new Neo4JQuery(qlString, finderFactory,info); + return (TypedQuery)createNeo4jQuery(qlString,(Class)entityClass); + } + + public TypedQuery createNeo4jQuery(final String qlString, final Class entityClass) { + return new Neo4JQuery(qlString, finderFactory,info,entityClass); } /* @@ -163,6 +240,11 @@ public class Neo4jEntityManager implements EntityManager { throw new UnsupportedOperationException(); } + @Override + public TypedQuery createNamedQuery(final String s, final Class entityClass) { + return null; + } + /* TODO Gremlin */ @@ -178,7 +260,7 @@ public class Neo4jEntityManager implements EntityManager { */ @Override - public Query createNativeQuery(final String sqlString, final Class resultClass) { + public Query createNativeQuery(final String sqlString, final Class resulentityClass) { checkClosed(); throw new UnsupportedOperationException(); } @@ -203,6 +285,11 @@ public class Neo4jEntityManager implements EntityManager { throw new UnsupportedOperationException(); } + @Override + public T unwrap(final Class entityClass) { + return null; + } + @Override public Object getDelegate() { checkClosed(); @@ -230,5 +317,20 @@ public class Neo4jEntityManager implements EntityManager { return new Neo4jEntityTransaction(transactionManager); } + @Override + public EntityManagerFactory getEntityManagerFactory() { + return neo4jEntityManagerFactory; + } + + @Override + public CriteriaBuilder getCriteriaBuilder() { + return null; + } + + @Override + public Metamodel getMetamodel() { + return null; + } + } diff --git a/src/main/java/org/springframework/datastore/graph/neo4j/jpa/Neo4jEntityManagerFactory.java b/src/main/java/org/springframework/datastore/graph/neo4j/jpa/Neo4jEntityManagerFactory.java index 9ec48aae2..40f92bb9e 100644 --- a/src/main/java/org/springframework/datastore/graph/neo4j/jpa/Neo4jEntityManagerFactory.java +++ b/src/main/java/org/springframework/datastore/graph/neo4j/jpa/Neo4jEntityManagerFactory.java @@ -6,9 +6,14 @@ import org.neo4j.index.IndexService; import org.springframework.datastore.graph.api.NodeBacked; import org.springframework.persistence.support.EntityInstantiator; +import javax.persistence.Cache; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; +import javax.persistence.PersistenceUnitUtil; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.metamodel.Metamodel; import javax.persistence.spi.PersistenceUnitInfo; +import java.util.Collections; import java.util.Map; /** @@ -41,10 +46,35 @@ public class Neo4jEntityManagerFactory implements EntityManagerFactory { return new Neo4jEntityManager(graphDatabaseService,nodeInstantiator,info,params, indexService); } + @Override + public CriteriaBuilder getCriteriaBuilder() { + return null; + } + + @Override + public Metamodel getMetamodel() { + return null; + } + @Override public void close() { } + @Override + public Map getProperties() { + return Collections.emptyMap(); + } + + @Override + public Cache getCache() { + return null; + } + + @Override + public PersistenceUnitUtil getPersistenceUnitUtil() { + return null; + } + @Override public boolean isOpen() { return true; diff --git a/src/main/java/org/springframework/datastore/graph/neo4j/jpa/Neo4jPersistenceProvider.java b/src/main/java/org/springframework/datastore/graph/neo4j/jpa/Neo4jPersistenceProvider.java index 14367f5e7..87d8bc56c 100644 --- a/src/main/java/org/springframework/datastore/graph/neo4j/jpa/Neo4jPersistenceProvider.java +++ b/src/main/java/org/springframework/datastore/graph/neo4j/jpa/Neo4jPersistenceProvider.java @@ -9,8 +9,10 @@ import org.springframework.persistence.support.EntityInstantiator; import javax.annotation.Resource; import javax.persistence.EntityManagerFactory; +import javax.persistence.spi.LoadState; import javax.persistence.spi.PersistenceProvider; import javax.persistence.spi.PersistenceUnitInfo; +import javax.persistence.spi.ProviderUtil; import java.util.Map; /** @@ -46,4 +48,24 @@ public class Neo4jPersistenceProvider implements PersistenceProvider { System.out.println("params = " + params); return new Neo4jEntityManagerFactory(graphDatabaseService,graphEntityInstantiator, indexService, info,params); } + + @Override + public ProviderUtil getProviderUtil() { + return new ProviderUtil(){ + @Override + public LoadState isLoadedWithoutReference(Object o, String s) { + return LoadState.UNKNOWN; + } + + @Override + public LoadState isLoadedWithReference(Object o, String s) { + return LoadState.UNKNOWN; + } + + @Override + public LoadState isLoaded(Object o) { + return LoadState.UNKNOWN; + } + }; + } } diff --git a/src/main/java/org/springframework/datastore/graph/neo4j/jpa/Neo4jQueryParameter.java b/src/main/java/org/springframework/datastore/graph/neo4j/jpa/Neo4jQueryParameter.java new file mode 100644 index 000000000..ef6c079ce --- /dev/null +++ b/src/main/java/org/springframework/datastore/graph/neo4j/jpa/Neo4jQueryParameter.java @@ -0,0 +1,37 @@ +package org.springframework.datastore.graph.neo4j.jpa; + +import javax.persistence.Parameter; +/** + * @author Michael Hunger + * @since 11.09.2010 + */ +public class Neo4jQueryParameter implements Parameter { + private final Class type; + private final String name; + private final Integer position; + + public Neo4jQueryParameter(Class type, String name, Integer position) { + this.type = type; + this.name = name; + this.position = position; + } + + @Override + public String getName() { + return name; + } + + @Override + public Integer getPosition() { + return position; + } + + @Override + public Class getParameterType() { + return type; + } + + public static Parameter param(String name) { return new Neo4jQueryParameter(null,name,null);} + public static Parameter param(Integer position) { return new Neo4jQueryParameter(null,null,position);} + public static Parameter param(Class type, String name, Integer position) { return new Neo4jQueryParameter(type,name,position);} +} diff --git a/src/main/java/org/springframework/datastore/graph/neo4j/support/Tuple2.java b/src/main/java/org/springframework/datastore/graph/neo4j/support/Tuple2.java new file mode 100644 index 000000000..ad888f263 --- /dev/null +++ b/src/main/java/org/springframework/datastore/graph/neo4j/support/Tuple2.java @@ -0,0 +1,23 @@ +package org.springframework.datastore.graph.neo4j.support; + +/** + * @author Michael Hunger + * @since 11.09.2010 + */ +public final class Tuple2 { + public final T1 _1; + public final T2 _2; + + private Tuple2(T1 _1,T2 _2) { + this._1=_1; + this._2=_2; + } + public static Tuple2 _(T1 _1, T2 _2) { + return new Tuple2(_1,_2); + } + + @Override + public String toString() { + return String.format("(%s,%s)",_1,_2); + } +} \ No newline at end of file