Author: epbernard
Date: 2007-06-24 14:00:46 -0400 (Sun, 24 Jun 2007)
New Revision: 11714
Added:
trunk/HibernateExt/search/src/java/org/hibernate/search/jpa/Search.java
trunk/HibernateExt/search/src/java/org/hibernate/search/jpa/impl/FullTextQueryImpl.java
trunk/HibernateExt/search/src/test/org/hibernate/search/test/jpa/
trunk/HibernateExt/search/src/test/org/hibernate/search/test/jpa/Bretzel.java
trunk/HibernateExt/search/src/test/org/hibernate/search/test/jpa/EntityManagerTest.java
trunk/HibernateExt/search/src/test/org/hibernate/search/test/jpa/JPATestCase.java
Log:
HSEARCH-89 JPA wrappers implementation
Added: trunk/HibernateExt/search/src/java/org/hibernate/search/jpa/Search.java
===================================================================
--- trunk/HibernateExt/search/src/java/org/hibernate/search/jpa/Search.java
(rev 0)
+++ trunk/HibernateExt/search/src/java/org/hibernate/search/jpa/Search.java 2007-06-24
18:00:46 UTC (rev 11714)
@@ -0,0 +1,24 @@
+//$Id$
+package org.hibernate.search.jpa;
+
+import javax.persistence.EntityManager;
+
+import org.hibernate.search.jpa.impl.FullTextEntityManagerImpl;
+
+/**
+ * Helper class that should be used when building a FullTextEntityManager
+ *
+ * @author Emmanuel Bernard
+ */
+public final class Search {
+ private Search() {
+ }
+
+ /**
+ * Build a full text capable EntityManager
+ * The underlying EM implementation has to be Hibernate EntityManager
+ */
+ public static FullTextEntityManager createFullTextEntityManager(EntityManager em) {
+ return new FullTextEntityManagerImpl(em);
+ }
+}
\ No newline at end of file
Added:
trunk/HibernateExt/search/src/java/org/hibernate/search/jpa/impl/FullTextQueryImpl.java
===================================================================
---
trunk/HibernateExt/search/src/java/org/hibernate/search/jpa/impl/FullTextQueryImpl.java
(rev 0)
+++
trunk/HibernateExt/search/src/java/org/hibernate/search/jpa/impl/FullTextQueryImpl.java 2007-06-24
18:00:46 UTC (rev 11714)
@@ -0,0 +1,247 @@
+//$Id$
+package org.hibernate.search.jpa.impl;
+
+import java.util.List;
+import java.util.Date;
+import java.util.Calendar;
+import java.util.Set;
+import java.util.HashSet;
+import java.io.Serializable;
+import javax.persistence.Query;
+import javax.persistence.TemporalType;
+import javax.persistence.FlushModeType;
+import javax.persistence.NoResultException;
+import javax.persistence.NonUniqueResultException;
+import javax.persistence.PersistenceException;
+import javax.persistence.EntityExistsException;
+import javax.persistence.EntityNotFoundException;
+import javax.persistence.OptimisticLockException;
+
+import org.hibernate.search.jpa.FullTextQuery;
+import org.hibernate.search.SearchException;
+import org.hibernate.Criteria;
+import org.hibernate.TypeMismatchException;
+import org.hibernate.HibernateException;
+import org.hibernate.StaleStateException;
+import org.hibernate.ObjectNotFoundException;
+import org.hibernate.UnresolvableObjectException;
+import org.hibernate.QueryException;
+import org.hibernate.TransientObjectException;
+import org.hibernate.StaleObjectStateException;
+import org.hibernate.Session;
+import org.hibernate.FlushMode;
+import org.hibernate.exception.ConstraintViolationException;
+import org.hibernate.hql.QueryExecutionRequestException;
+import org.apache.lucene.search.Sort;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class FullTextQueryImpl implements FullTextQuery {
+ private final org.hibernate.search.FullTextQuery query;
+ private Session session;
+
+ public FullTextQueryImpl(org.hibernate.search.FullTextQuery query, Session session) {
+ this.query = query;
+ this.session = session;
+ }
+
+ public FullTextQuery setSort(Sort sort) {
+ query.setSort( sort );
+ return this;
+ }
+
+ public int getResultSize() {
+ return query.getResultSize();
+ }
+
+ public FullTextQuery setCriteriaQuery(Criteria criteria) {
+ query.setCriteriaQuery( criteria );
+ return this;
+ }
+
+ public FullTextQuery setIndexProjection(String... fields) {
+ query.setIndexProjection( fields );
+ return this;
+ }
+
+ public List getResultList() {
+ try {
+ return query.list();
+ }
+ catch (QueryExecutionRequestException he) {
+ //TODO when an illegal state exceptio should be raised?
+ throw new IllegalStateException(he);
+ }
+ catch( TypeMismatchException e ) {
+ //TODO when an illegal arg exceptio should be raised?
+ throw new IllegalArgumentException(e);
+ }
+ catch (SearchException he) {
+ throwPersistenceException( he );
+ throw he;
+ }
+ }
+
+ //TODO mutualize this code with the EM this will fix the rollback issues
+ private void throwPersistenceException(Exception e) {
+ if ( e instanceof StaleStateException ) {
+ PersistenceException pe = wrapStaleStateException( (StaleStateException) e );
+ throwPersistenceException( pe );
+ }
+ else if ( e instanceof ConstraintViolationException ) {
+ //FIXME this is bad cause ConstraintViolationException happens in other circumstances
+ throwPersistenceException( new EntityExistsException( e ) );
+ }
+ else if ( e instanceof ObjectNotFoundException ) {
+ throwPersistenceException( new EntityNotFoundException( e.getMessage() ) );
+ }
+ else if ( e instanceof org.hibernate.NonUniqueResultException ) {
+ throwPersistenceException( new NonUniqueResultException( e.getMessage() ) );
+ }
+ else if ( e instanceof UnresolvableObjectException ) {
+ throwPersistenceException( new EntityNotFoundException( e.getMessage() ) );
+ }
+ else if ( e instanceof QueryException ) {
+ throw new IllegalArgumentException( e );
+ }
+ else if ( e instanceof TransientObjectException ) {
+ //FIXME rollback
+ throw new IllegalStateException( e ); //Spec 3.2.3 Synchronization rules
+ }
+ else {
+ throwPersistenceException( new PersistenceException( e ) );
+ }
+ }
+
+ public void throwPersistenceException(PersistenceException e) {
+ if ( ! ( e instanceof NoResultException || e instanceof NonUniqueResultException ) ) {
+ //FIXME rollback
+ }
+ throw e;
+ }
+
+ public PersistenceException wrapStaleStateException(StaleStateException e) {
+ PersistenceException pe;
+ if ( e instanceof StaleObjectStateException ) {
+ StaleObjectStateException sose = (StaleObjectStateException) e;
+ Serializable identifier = sose.getIdentifier();
+ if (identifier != null) {
+ Object entity = session.load( sose.getEntityName(), identifier );
+ if ( entity instanceof Serializable ) {
+ //avoid some user errors regarding boundary crossing
+ pe = new OptimisticLockException( null, e, entity );
+ }
+ else {
+ pe = new OptimisticLockException( e );
+ }
+ }
+ else {
+ pe = new OptimisticLockException( e );
+ }
+ }
+ else {
+ pe = new OptimisticLockException( e );
+ }
+ return pe;
+ }
+
+ public Object getSingleResult() {
+ try {
+ List result = query.list();
+ if ( result.size() == 0 ) {
+ throwPersistenceException( new NoResultException( "No entity found for
query" ) );
+ }
+ else if ( result.size() > 1 ) {
+ Set uniqueResult = new HashSet(result);
+ if ( uniqueResult.size() > 1 ) {
+ throwPersistenceException( new NonUniqueResultException( "result returns "
+ uniqueResult.size() + " elements") );
+ }
+ else {
+ return uniqueResult.iterator().next();
+ }
+
+ }
+ else {
+ return result.get(0);
+ }
+ return null; //should never happen
+ }
+ catch (QueryExecutionRequestException he) {
+ throw new IllegalStateException(he);
+ }
+ catch( TypeMismatchException e ) {
+ throw new IllegalArgumentException(e);
+ }
+ catch (HibernateException he) {
+ throwPersistenceException( he );
+ return null;
+ }
+ }
+
+ public Query setMaxResults(int maxResult) {
+ if ( maxResult < 0 ) {
+ throw new IllegalArgumentException(
+ "Negative ("
+ + maxResult
+ + ") parameter passed in to setMaxResults"
+ );
+ }
+ query.setMaxResults( maxResult );
+ return this;
+ }
+
+ public Query setFirstResult(int firstResult) {
+ if ( firstResult < 0 ) {
+ throw new IllegalArgumentException(
+ "Negative ("
+ + firstResult
+ + ") parameter passed in to setFirstResult"
+ );
+ }
+ query.setFirstResult( firstResult );
+ return this;
+ }
+
+ public int executeUpdate() {
+ throw new IllegalStateException( "Update not allowed in FullTextQueries" );
+ }
+
+ public Query setHint(String hintName, Object value) {
+ return this;
+ }
+
+ public Query setParameter(String name, Object value) {
+ throw new UnsupportedOperationException( "parameters not supported in fullText
queries");
+ }
+
+ public Query setParameter(String name, Date value, TemporalType temporalType) {
+ throw new UnsupportedOperationException( "parameters not supported in fullText
queries");
+ }
+
+ public Query setParameter(String name, Calendar value, TemporalType temporalType) {
+ throw new UnsupportedOperationException( "parameters not supported in fullText
queries");
+ }
+
+ public Query setParameter(int position, Object value) {
+ throw new UnsupportedOperationException( "parameters not supported in fullText
queries");
+ }
+
+ public Query setParameter(int position, Date value, TemporalType temporalType) {
+ throw new UnsupportedOperationException( "parameters not supported in fullText
queries");
+ }
+
+ public Query setParameter(int position, Calendar value, TemporalType temporalType) {
+ throw new UnsupportedOperationException( "parameters not supported in fullText
queries");
+ }
+
+ public Query setFlushMode(FlushModeType flushMode) {
+ if ( flushMode == FlushModeType.AUTO ) {
+ query.setFlushMode( FlushMode.AUTO );
+ }
+ else if ( flushMode == FlushModeType.COMMIT ) {
+ query.setFlushMode( FlushMode.COMMIT );
+ }
+ return this;
+ }
+}
Added: trunk/HibernateExt/search/src/test/org/hibernate/search/test/jpa/Bretzel.java
===================================================================
--- trunk/HibernateExt/search/src/test/org/hibernate/search/test/jpa/Bretzel.java
(rev 0)
+++
trunk/HibernateExt/search/src/test/org/hibernate/search/test/jpa/Bretzel.java 2007-06-24
18:00:46 UTC (rev 11714)
@@ -0,0 +1,63 @@
+//$Id$
+package org.hibernate.search.test.jpa;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.GeneratedValue;
+
+import org.hibernate.search.annotations.Indexed;
+import org.hibernate.search.annotations.DocumentId;
+import org.hibernate.search.annotations.Field;
+import org.hibernate.search.annotations.Index;
+
+/**
+ * @author Emmanuel Bernard
+ */
+@Entity
+@Indexed
+public class Bretzel {
+ @Id
+ @GeneratedValue
+ @DocumentId
+ private Integer id;
+
+ @Field(index = Index.UN_TOKENIZED)
+ private float saltQty;
+
+ @Field(index = Index.UN_TOKENIZED)
+ private float weight;
+
+
+ public Bretzel() {
+ }
+
+ public Bretzel(float saltQty, float weight) {
+ this.saltQty = saltQty;
+ this.weight = weight;
+ }
+
+
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public float getSaltQty() {
+ return saltQty;
+ }
+
+ public void setSaltQty(float saltQty) {
+ this.saltQty = saltQty;
+ }
+
+ public float getWeight() {
+ return weight;
+ }
+
+ public void setWeight(float weight) {
+ this.weight = weight;
+ }
+}
Added:
trunk/HibernateExt/search/src/test/org/hibernate/search/test/jpa/EntityManagerTest.java
===================================================================
---
trunk/HibernateExt/search/src/test/org/hibernate/search/test/jpa/EntityManagerTest.java
(rev 0)
+++
trunk/HibernateExt/search/src/test/org/hibernate/search/test/jpa/EntityManagerTest.java 2007-06-24
18:00:46 UTC (rev 11714)
@@ -0,0 +1,70 @@
+//$Id$
+package org.hibernate.search.test.jpa;
+
+import javax.persistence.EntityManager;
+
+import org.hibernate.search.jpa.Search;
+import org.hibernate.search.jpa.FullTextEntityManager;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.search.TermQuery;
+import org.apache.lucene.queryParser.QueryParser;
+import org.apache.lucene.analysis.StopAnalyzer;
+import org.apache.lucene.index.Term;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class EntityManagerTest extends JPATestCase {
+
+ public void testQuery() throws Exception {
+ FullTextEntityManager em = Search.createFullTextEntityManager(
factory.createEntityManager() );
+ em.getTransaction().begin();
+ Bretzel bretzel = new Bretzel( 23, 34 );
+ em.persist( bretzel );
+ em.getTransaction().commit();
+ em.clear();
+ em.getTransaction().begin();
+ QueryParser parser = new QueryParser( "title", new StopAnalyzer() );
+ Query query = parser.parse( "saltQty:noword" );
+ assertEquals( 0, em.createFullTextQuery( query ).getResultList().size() );
+ query = new TermQuery( new Term("saltQty", "23.0") );
+ assertEquals( "getResultList", 1, em.createFullTextQuery( query
).getResultList().size() );
+ assertEquals( "getSingleResult and object retrieval", 23f,
+ ( (Bretzel) em.createFullTextQuery( query ).getSingleResult() ).getSaltQty() );
+ assertEquals( 1, em.createFullTextQuery( query ).getResultSize() );
+ em.getTransaction().commit();
+
+ em.clear();
+
+ em.getTransaction().begin();
+ em.remove( em.find( Bretzel.class, bretzel.getId() ) );
+ em.getTransaction().commit();
+ em.close();
+ }
+
+ public void testIndex() throws Exception {
+ FullTextEntityManager em = Search.createFullTextEntityManager(
factory.createEntityManager() );
+ em.getTransaction().begin();
+ Bretzel bretzel = new Bretzel( 23, 34 );
+ em.persist( bretzel );
+ em.getTransaction().commit();
+ em.clear();
+
+ //Not really a unit test but a test that shows the method call wiouth failing
+ //FIXME port the index test
+ em.getTransaction().begin();
+ em.index( em.find( Bretzel.class, bretzel.getId() ) );
+ em.getTransaction().commit();
+
+ em.getTransaction().begin();
+ em.remove( em.find( Bretzel.class, bretzel.getId() ) );
+ em.getTransaction().commit();
+ em.close();
+ }
+
+ public Class[] getAnnotatedClasses() {
+ return new Class[] {
+ Bretzel.class
+ };
+ }
+}
Added: trunk/HibernateExt/search/src/test/org/hibernate/search/test/jpa/JPATestCase.java
===================================================================
--- trunk/HibernateExt/search/src/test/org/hibernate/search/test/jpa/JPATestCase.java
(rev 0)
+++
trunk/HibernateExt/search/src/test/org/hibernate/search/test/jpa/JPATestCase.java 2007-06-24
18:00:46 UTC (rev 11714)
@@ -0,0 +1,111 @@
+//$Id$
+package org.hibernate.search.test.jpa;
+
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Properties;
+import java.util.ArrayList;
+import java.io.InputStream;
+import java.io.IOException;
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.Persistence;
+
+import org.hibernate.cfg.Environment;
+import org.hibernate.ejb.HibernatePersistence;
+import org.hibernate.search.store.RAMDirectoryProvider;
+import org.apache.lucene.analysis.StopAnalyzer;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public abstract class JPATestCase extends junit.framework.TestCase {
+ protected EntityManagerFactory factory;
+
+ public JPATestCase() {
+ super();
+ }
+
+ public JPATestCase(String name) {
+ super( name );
+ }
+
+ public void setUp() {
+ factory = new HibernatePersistence().createEntityManagerFactory( getConfig() );
+ }
+
+ public void tearDown() {
+ factory.close();
+ }
+
+ public abstract Class[] getAnnotatedClasses();
+
+ public String[] getEjb3DD() {
+ return new String[]{};
+ }
+
+ public Map<Class, String> getCachedClasses() {
+ return new HashMap<Class, String>();
+ }
+
+ public Map<String, String> getCachedCollections() {
+ return new HashMap<String, String>();
+ }
+
+ public static Properties loadProperties() {
+ Properties props = new Properties();
+ InputStream stream = Persistence.class.getResourceAsStream(
"/hibernate.properties" );
+ if ( stream != null ) {
+ try {
+ props.load( stream );
+ }
+ catch (Exception e) {
+ throw new RuntimeException( "could not load hibernate.properties" );
+ }
+ finally {
+ try {
+ stream.close();
+ }
+ catch (IOException ioe) {
+ }
+ }
+ }
+ props.setProperty( Environment.HBM2DDL_AUTO, "create-drop" );
+ return props;
+ }
+
+ public Map getConfig() {
+ Map config = loadProperties();
+ ArrayList<Class> classes = new ArrayList<Class>();
+
+ for ( Class clazz : getAnnotatedClasses() ) {
+ classes.add( clazz );
+ }
+ config.put( HibernatePersistence.LOADED_CLASSES, classes );
+ for ( Map.Entry<Class, String> entry : getCachedClasses().entrySet() ) {
+ config.put(
+ HibernatePersistence.CLASS_CACHE_PREFIX + "." + entry.getKey().getName(),
+ entry.getValue()
+ );
+ }
+ for ( Map.Entry<String, String> entry : getCachedCollections().entrySet() ) {
+ config.put(
+ HibernatePersistence.COLLECTION_CACHE_PREFIX + "." + entry.getKey(),
+ entry.getValue()
+ );
+ }
+ if ( getEjb3DD().length > 0 ) {
+ ArrayList<String> dds = new ArrayList<String>();
+ for ( String dd : getEjb3DD() ) {
+ dds.add( dd );
+ }
+ config.put( HibernatePersistence.XML_FILE_NAMES, dds );
+ }
+
+ //Search config
+ config.put( "hibernate.search.default.directory_provider",
RAMDirectoryProvider.class.getName() );
+ config.put( org.hibernate.search.Environment.ANALYZER_CLASS,
StopAnalyzer.class.getName() );
+
+ return config;
+ }
+}
+