added jpa2.0 support

This commit is contained in:
Michael Hunger
2010-09-11 10:33:36 +02:00
parent 954196579e
commit c36191c62f
7 changed files with 397 additions and 51 deletions

26
pom.xml
View File

@@ -189,22 +189,28 @@
<groupId>org.springframework.data</groupId>
<artifactId>spring-datastore-cross-store</artifactId>
<version>1.0.0.M1-SNAPSHOT</version>
<exclusions>
<exclusion>
<groupId>javax.persistence</groupId>
<artifactId>persistence-api</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- JPA dependencies -->
<!--dependency>
<groupId>org.apache.geronimo.specs</groupId>
<artifactId>geronimo-jpa_2.0_spec</artifactId>
<version>1.1</version>
</dependency-->
<dependency>
<groupId>javax.persistence</groupId>
<artifactId>persistence-api</artifactId>
<version>1.0</version>
<groupId>org.hibernate.javax.persistence</groupId>
<artifactId>hibernate-jpa-2.0-api</artifactId>
<version>1.0.0.Final</version>
</dependency>
<!-- Test only dependencies -->
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<version>1.8.0.10</version>
</dependency>
</dependencies>
</dependencies>
<build>
<plugins>

View File

@@ -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<? extends NodeBacked> finder;
protected final Class<? extends NodeBacked> entityClass;
public class Neo4JQuery<T extends NodeBacked> implements TypedQuery<T> {
protected final Finder<T> finder;
protected final Class<T> 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<Parameter<?>, Tuple2<?,TemporalType>> parameters=new HashMap<Parameter<?>, Tuple2<?,TemporalType>>();
public Neo4JQuery(final String qlString, final FinderFactory finderFactory, final PersistenceUnitInfo info) {
public Neo4JQuery(final String qlString, final FinderFactory finderFactory, final PersistenceUnitInfo info, final Class<T> 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<Long>() {
@Override
protected Iterable<?> findList() {
return Collections.singleton(finder.count());
protected Long findObject() {
return finder.count();
}
};
return new QueryExectuor() {
return new QueryExectuor<T>() {
@Override
protected Iterable<?> findList() {
protected Iterable<T> findList() {
return finder.findAll();
}
};
}
abstract static class QueryExectuor {
protected abstract Iterable<?> findList();
abstract static class QueryExectuor<T> {
protected Iterable<T> findList() { return Collections.singleton(findObject()); }
protected T findObject() { return null; }
}
private Class<NodeBacked> getEntityClass(final String shortName) {
private Class<T> getEntityClass(final String shortName) {
try {
final String className = getFQN(shortName);
return (Class<NodeBacked>) Class.forName(className);
return (Class<T>) 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<Object> result = new ArrayList<Object>();
public List<T> getResultList() {
final List<T> result = new ArrayList<T>();
int count=0;
for (final Object nodeBacked : queryExectuor.findList()) {
for (final T nodeBacked : (Iterable<T>)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<T> setMaxResults(final int maxResult) {
this.maxResult = maxResult;
return this;
}
@Override
public Query setFirstResult(final int startPosition) {
public int getMaxResults() {
return maxResult;
}
@Override
public TypedQuery<T> 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<T> setHint(final String hintName, final Object value) {
return this;
}
@Override
public Query setParameter(final String name, final Object value) {
public Map<String, Object> getHints() {
return Collections.emptyMap();
}
@Override
public <P> TypedQuery<T> setParameter(final Parameter<P> parameter, final P value) {
this.parameters.put(parameter, value(value));
return this;
}
private static <P> Tuple2<P, TemporalType> value(final P value) {
return _(value,(TemporalType)null);
}
@Override
public TypedQuery<T> setParameter(final Parameter<Calendar> 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<T> setParameter(final Parameter<Date> 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<T> 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<T> 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<T> 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<T> 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<T> setParameter(final int position, final Date value, final TemporalType temporalType) {
this.parameters.put(param(position),value(value));
return this;
}
@Override
public Set<Parameter<?>> 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 <T> Parameter<T> getParameter(final String name, final Class<T> type) {
for (final Parameter<?> parameter : parameters.keySet()) {
if (nullSafeEquals(parameter.getName(),name) && nullSafeEquals(type,parameter.getParameterType())) return (Parameter<T>) 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 <T> Parameter<T> getParameter(final int index, final Class<T> type) {
for (final Parameter<?> parameter : parameters.keySet()) {
if (nullSafeEquals(parameter.getPosition(),index) && nullSafeEquals(type,parameter.getParameterType())) return (Parameter<T>) parameter;
}
return null;
}
@Override
public boolean isBound(final Parameter<?> parameter) {
return parameters.containsKey(parameter);
}
@Override
public <T> T getParameterValue(final Parameter<T> 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<T> setParameter(final int position, final Calendar value, final TemporalType temporalType) {
parameters.put(param(position),_(value,temporalType));
return this;
}
@Override
public TypedQuery<T> setFlushMode(final FlushModeType flushMode) {
return this;
}
@Override
public FlushModeType getFlushMode() {
return null;
}
@Override
public TypedQuery<T> setLockMode(final LockModeType lockModeType) {
return null;
}
@Override
public LockModeType getLockMode() {
return null;
}
@Override
public <T> T unwrap(final Class<T> tClass) {
return null;
}
}

View File

@@ -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<NodeBacked, Node> nodeInstantiator, PersistenceUnitInfo info, Map params, IndexService indexService) {
@Resource
private Neo4jEntityManagerFactory neo4jEntityManagerFactory;
public Neo4jEntityManager(final GraphDatabaseService graphDatabaseService, final EntityInstantiator<NodeBacked, Node> 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> 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<? extends NodeBacked>) entityClass);
}
@Override
public <T> T find(final Class<T> entityClass, final Object primaryKey, final Map<String, Object> params) {
return find(entityClass, primaryKey);
}
@Override
public <T> T find(final Class<T> entityClass, final Object primaryKey, final LockModeType lockModeType) {
return find(entityClass, primaryKey);
}
@Override
public <T> T find(final Class<T> entityClass, final Object primaryKey, final LockModeType lockModeType, final Map<String, Object> params) {
return find(entityClass, primaryKey);
}
@Override
public <T> T getReference(final Class<T> 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<String, Object> 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<String, Object> 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<String, Object> 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<String, Object> getProperties() {
return params;
}
/*
TODO Gremlin
*/
@Override
public Query createQuery(final String qlString) {
return createQuery(qlString,null);
}
@Override
public <T> TypedQuery<T> createQuery(final CriteriaQuery<T> query) {
return null;
}
@SuppressWarnings({"unchecked"})
@Override
public <T> TypedQuery<T> createQuery(final String qlString, final Class<T> entityClass) {
checkClosed();
return new Neo4JQuery(qlString, finderFactory,info);
return (TypedQuery<T>)createNeo4jQuery(qlString,(Class<? extends NodeBacked>)entityClass);
}
public <T extends NodeBacked> TypedQuery<T> createNeo4jQuery(final String qlString, final Class<T> entityClass) {
return new Neo4JQuery<T>(qlString, finderFactory,info,entityClass);
}
/*
@@ -163,6 +240,11 @@ public class Neo4jEntityManager implements EntityManager {
throw new UnsupportedOperationException();
}
@Override
public <T> TypedQuery<T> createNamedQuery(final String s, final Class<T> 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> T unwrap(final Class<T> 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;
}
}

View File

@@ -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<String, Object> getProperties() {
return Collections.emptyMap();
}
@Override
public Cache getCache() {
return null;
}
@Override
public PersistenceUnitUtil getPersistenceUnitUtil() {
return null;
}
@Override
public boolean isOpen() {
return true;

View File

@@ -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;
}
};
}
}

View File

@@ -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<T> implements Parameter<T> {
private final Class<T> type;
private final String name;
private final Integer position;
public Neo4jQueryParameter(Class<T> 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<T> getParameterType() {
return type;
}
public static Parameter<?> param(String name) { return new Neo4jQueryParameter<Object>(null,name,null);}
public static Parameter<?> param(Integer position) { return new Neo4jQueryParameter<Object>(null,null,position);}
public static <T> Parameter<T> param(Class<T> type, String name, Integer position) { return new Neo4jQueryParameter<T>(type,name,position);}
}

View File

@@ -0,0 +1,23 @@
package org.springframework.datastore.graph.neo4j.support;
/**
* @author Michael Hunger
* @since 11.09.2010
*/
public final class Tuple2<T1,T2> {
public final T1 _1;
public final T2 _2;
private Tuple2(T1 _1,T2 _2) {
this._1=_1;
this._2=_2;
}
public static <T1,T2> Tuple2<T1,T2> _(T1 _1, T2 _2) {
return new Tuple2<T1,T2>(_1,_2);
}
@Override
public String toString() {
return String.format("(%s,%s)",_1,_2);
}
}