/*
* Hibernate Search, full-text search for your domain model
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.search.test.bridge;
import java.net.URI;
import java.net.URL;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.List;
import java.util.TimeZone;
import java.util.UUID;
import org.apache.lucene.analysis.core.SimpleAnalyzer;
import org.apache.lucene.index.Term;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.BooleanClause;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.TermQuery;
import org.hibernate.HibernateException;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.search.cfg.Environment;
import org.hibernate.search.FullTextQuery;
import org.hibernate.search.FullTextSession;
import org.hibernate.search.Search;
import org.hibernate.search.annotations.Resolution;
import org.hibernate.search.bridge.BridgeException;
import org.hibernate.search.bridge.builtin.CalendarBridge;
import org.hibernate.search.query.dsl.QueryBuilder;
import org.hibernate.search.test.SearchTestBase;
import org.hibernate.search.testsupport.TestConstants;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
/**
* @author Emmanuel Bernard
*/
public class BridgeTest extends SearchTestBase {
@Test
public void testDefaultAndNullBridges() throws Exception {
Cloud cloud = new Cloud();
cloud.setMyDate( null );
cloud.setDouble1( null );
cloud.setDouble2( 2.1d );
cloud.setIntegerv1( null );
cloud.setIntegerv2( 2 );
cloud.setFloat1( null );
cloud.setFloat2( 2.1f );
cloud.setLong1( null );
cloud.setLong2( 2l );
cloud.setString( null );
cloud.setType( CloudType.DOG );
cloud.setChar1( null );
cloud.setChar2( 'P' );
cloud.setStorm( false );
cloud.setClazz( Cloud.class );
cloud.setUri( new URI( "http://www.hibernate.org" ) );
cloud.setUrl( new URL( "http://www.hibernate.org" ) );
cloud.setUuid( UUID.fromString( "f49c6ba8-8d7f-417a-a255-d594dddf729f" ) );
org.hibernate.Session s = openSession();
Transaction tx = s.beginTransaction();
s.persist( cloud );
s.flush();
tx.commit();
tx = s.beginTransaction();
FullTextSession session = Search.getFullTextSession( s );
QueryParser parser = new QueryParser( TestConstants.getTargetLuceneVersion(), "id", TestConstants.standardAnalyzer );
Query query;
List result;
query = parser.parse(
"double2:[2.1 TO 2.1] AND float2:[2.1 TO 2.1] " +
"AND integerv2:[2 TO 2.1] AND long2:[2 TO 2.1] AND type:\"dog\" AND storm:false"
);
result = session.createFullTextQuery( query ).list();
assertEquals( "find primitives and do not fail on null", 1, result.size() );
query = parser.parse( "double1:[2.1 TO 2.1] OR float1:[2.1 TO 2.1] OR integerv1:[2 TO 2.1] OR long1:[2 TO 2.1]" );
result = session.createFullTextQuery( query ).list();
assertEquals( "null elements should not be stored", 0, result.size() ); //the query is dumb because restrictive
query = parser.parse( "type:dog" );
result = session.createFullTextQuery( query ).setProjection( "type" ).list();
assertEquals( "Enum projection works", 1, result.size() ); //the query is dumb because restrictive
query = new TermQuery( new Term( "clazz", Cloud.class.getName() ) );
result = session.createFullTextQuery( query ).setProjection( "clazz" ).list();
assertEquals( "Clazz projection works", 1, result.size() );
assertEquals(
"Clazz projection works",
Cloud.class.getName(),
( (Class) ( (Object[]) result.get( 0 ) )[0] ).getName()
);
BooleanQuery bQuery = new BooleanQuery();
bQuery.add( new TermQuery( new Term( "uri", "http://www.hibernate.org" ) ), BooleanClause.Occur.MUST );
bQuery.add( new TermQuery( new Term( "url", "http://www.hibernate.org" ) ), BooleanClause.Occur.MUST );
result = session.createFullTextQuery( bQuery ).setProjection( "clazz" ).list();
assertEquals( "Clazz projection works", 1, result.size() );
bQuery = new BooleanQuery();
bQuery.add( new TermQuery( new Term( "uuid", "f49c6ba8-8d7f-417a-a255-d594dddf729f" ) ), BooleanClause.Occur.MUST );
result = session.createFullTextQuery( bQuery ).setProjection( "clazz" ).list();
assertEquals( "Clazz projection works", 1, result.size() );
query = parser.parse( "char1:[" + String.valueOf( Character.MIN_VALUE ) + " TO " + String.valueOf( Character.MAX_VALUE ) + "]" );
result = session.createFullTextQuery( query ).setProjection( "char1" ).list();
assertEquals( "Null elements should not be stored, CharacterBridge is not working", 0, result.size() );
query = parser.parse( "char2:P" );
result = session.createFullTextQuery( query ).setProjection( "char2" ).list();
assertEquals( "Wrong results number, CharacterBridge is not working", 1, result.size() );
assertEquals( "Wrong result, CharacterBridge is not working", 'P', ( (Object[]) result.get( 0 ) )[0] );
s.delete( s.get( Cloud.class, cloud.getId() ) );
tx.commit();
s.close();
}
@Test
public void testCustomBridges() throws Exception {
Cloud cloud = new Cloud();
cloud.setCustomFieldBridge( "This is divided by 2" );
cloud.setCustomStringBridge( "This is div by 4" );
cloud.setChar2( 's' );
org.hibernate.Session s = openSession();
Transaction tx = s.beginTransaction();
s.persist( cloud );
s.flush();
tx.commit();
tx = s.beginTransaction();
FullTextSession session = Search.getFullTextSession( s );
QueryParser parser = new QueryParser( TestConstants.getTargetLuceneVersion(), "id", TestConstants.simpleAnalyzer );
Query query;
List result;
query = parser.parse( "customFieldBridge:This AND customStringBridge:This" );
result = session.createFullTextQuery( query ).list();
assertEquals( "Properties not mapped", 1, result.size() );
query = parser.parse( "customFieldBridge:by AND customStringBridge:is" );
result = session.createFullTextQuery( query ).list();
assertEquals( "Custom types not taken into account", 0, result.size() );
s.delete( s.get( Cloud.class, cloud.getId() ) );
tx.commit();
s.close();
}
@Test
public void testDateBridge() throws Exception {
Cloud cloud = new Cloud();
Calendar c = GregorianCalendar.getInstance();
c.setTimeZone( TimeZone.getTimeZone( "GMT" ) ); //for the sake of tests
c.set( 2000, 11, 15, 3, 43, 2 );
c.set( Calendar.MILLISECOND, 5 );
Date date = new Date( c.getTimeInMillis() );
cloud.setMyDate( date ); //5 millisecond
cloud.setDateDay( date );
cloud.setDateHour( date );
cloud.setDateMillisecond( date );
cloud.setDateMinute( date );
cloud.setDateMonth( date );
cloud.setDateSecond( date );
cloud.setDateYear( date );
cloud.setChar2( 's' );
org.hibernate.Session s = openSession();
Transaction tx = s.beginTransaction();
s.persist( cloud );
s.flush();
tx.commit();
tx = s.beginTransaction();
FullTextSession session = Search.getFullTextSession( s );
QueryParser parser = new QueryParser( TestConstants.getTargetLuceneVersion(), "id", TestConstants.standardAnalyzer );
Query query;
List result;
query = parser.parse(
"myDate:[19900101 TO 20060101]"
+ " AND dateDay:[20001214 TO 2000121501]"
+ " AND dateMonth:[200012 TO 20001201]"
+ " AND dateYear:[2000 TO 200001]"
+ " AND dateHour:[20001214 TO 2000121503]"
+ " AND dateMinute:[20001214 TO 200012150343]"
+ " AND dateSecond:[20001214 TO 20001215034302]"
+ " AND dateMillisecond:[20001214 TO 20001215034302005]"
);
result = session.createFullTextQuery( query ).list();
assertEquals( "Date not found or not property truncated", 1, result.size() );
s.delete( s.get( Cloud.class, cloud.getId() ) );
tx.commit();
s.close();
}
@Test
public void testCalendarBridge() throws Exception {
Cloud cloud = new Cloud();
Calendar c = GregorianCalendar.getInstance();
c.setTimeZone( TimeZone.getTimeZone( "GMT" ) ); //for the sake of tests
c.set( 2000, 11, 15, 3, 43, 2 );
c.set( Calendar.MILLISECOND, 5 );
cloud.setMyCalendar( c ); // 5 millisecond
cloud.setCalendarDay( c );
cloud.setCalendarHour( c );
cloud.setCalendarMillisecond( c );
cloud.setCalendarMinute( c );
cloud.setCalendarMonth( c );
cloud.setCalendarSecond( c );
cloud.setCalendarYear( c );
cloud.setChar2( 's' );
org.hibernate.Session s = openSession();
Transaction tx = s.beginTransaction();
s.persist( cloud );
s.flush();
tx.commit();
tx = s.beginTransaction();
FullTextSession session = Search.getFullTextSession( s );
QueryParser parser = new QueryParser( TestConstants.getTargetLuceneVersion(), "id", TestConstants.standardAnalyzer );
Query query;
List result;
query = parser.parse(
"myCalendar:[19900101 TO 20060101]"
+ " AND calendarDay:[20001214 TO 2000121501]"
+ " AND calendarMonth:[200012 TO 20001201]"
+ " AND calendarYear:[2000 TO 200001]"
+ " AND calendarHour:[20001214 TO 2000121503]"
+ " AND calendarMinute:[20001214 TO 200012150343]"
+ " AND calendarSecond:[20001214 TO 20001215034302]"
+ " AND calendarMillisecond:[20001214 TO 20001215034302005]"
);
result = session.createFullTextQuery( query ).list();
assertEquals( "Calendar not found or not property truncated", 1, result.size() );
s.delete( s.get( Cloud.class, cloud.getId() ) );
tx.commit();
s.close();
//now unit-test the bridge directly:
CalendarBridge bridge = new CalendarBridge();
HashMap<String, String> bridgeParams = new HashMap<String, String>();
bridgeParams.put( CalendarBridge.RESOLUTION_PARAMETER, Resolution.YEAR.toString() );
bridge.setParameterValues( bridgeParams );
assertEquals( "2000", bridge.objectToString( c ) );
bridgeParams.put( CalendarBridge.RESOLUTION_PARAMETER, Resolution.DAY.toString() );
bridge.setParameterValues( bridgeParams );
assertEquals( "20001215", bridge.objectToString( c ) );
}
@Test
public void testIncorrectSetBridge() throws Exception {
IncorrectSet incorrect = new IncorrectSet();
incorrect.setSubIncorrect( new IncorrectSet.SubIncorrect() );
incorrect.getSubIncorrect().setName( "This is a name not a class" );
FullTextSession s = Search.getFullTextSession( openSession() );
Transaction tx = s.beginTransaction();
try {
s.persist( incorrect );
s.flush();
s.flushToIndexes();
fail( "Incorrect bridge should fail" );
}
catch (BridgeException e) {
tx.rollback();
}
catch (HibernateException e) {
final Throwable throwable = e.getCause();
if ( throwable instanceof BridgeException ) {
//expected
assertTrue( throwable.getMessage().contains( "class: " + IncorrectSet.class.getName() ) );
assertTrue( throwable.getMessage().contains( "path: subIncorrect.name" ) );
tx.rollback();
}
else {
e.printStackTrace();
fail( "Incorrect bridge should raise a SearchException: " + e.toString() );
}
}
catch (Exception e) {
e.printStackTrace();
fail( "Incorrect bridge should raise a SearchException" );
}
s.close();
}
@Test
public void testIncorrectGetBridge() throws Exception {
IncorrectGet incorrect = new IncorrectGet();
incorrect.setSubIncorrect( new IncorrectGet.SubIncorrect() );
incorrect.getSubIncorrect().setName( "This is a name not a class" );
FullTextSession s = Search.getFullTextSession( openSession() );
Transaction tx = s.beginTransaction();
s.persist( incorrect );
tx.commit();
s.clear();
tx = s.beginTransaction();
final QueryBuilder builder = s.getSearchFactory().buildQueryBuilder().forEntity( IncorrectGet.class ).get();
final Query query = builder.keyword().onField( "subIncorrect.name" ).matching( "name" ).createQuery();
try {
final FullTextQuery textQuery = s.createFullTextQuery( query, IncorrectGet.class ).setProjection( "subIncorrect.name" );
textQuery.list();
fail( "Incorrect bridge should fail" );
}
catch (BridgeException e) {
tx.rollback();
}
catch (HibernateException e) {
final Throwable throwable = e.getCause();
if ( throwable instanceof BridgeException ) {
//expected
//System.out.println( throwable.getMessage() );
assertTrue( throwable.getMessage().contains( "class: " + IncorrectGet.class.getName() ) );
assertTrue( throwable.getMessage().contains( "path: subIncorrect.name" ) );
tx.rollback();
}
else {
e.printStackTrace();
fail( "Incorrect bridge should raise a SearchException: " + e.toString() );
}
}
catch (Exception e) {
e.printStackTrace();
fail( "Incorrect bridge should raise a SearchException" );
}
tx = s.beginTransaction();
s.delete( s.get( IncorrectGet.class, incorrect.getId() ) );
tx.commit();
s.close();
}
@Test
public void testIncorrectObjectToStringBridge() throws Exception {
IncorrectObjectToString incorrect = new IncorrectObjectToString();
incorrect.setName( "test" );
FullTextSession s = Search.getFullTextSession( openSession() );
Transaction tx = s.beginTransaction();
try {
s.persist( incorrect );
s.flush();
s.flushToIndexes();
fail( "Incorrect bridge should fail" );
}
catch (BridgeException e) {
tx.rollback();
}
catch (HibernateException e) {
final Throwable throwable = e.getCause();
if ( throwable instanceof BridgeException ) {
//expected
assertTrue( throwable.getMessage().contains( "class: " + IncorrectObjectToString.class.getName() ) );
assertTrue( throwable.getMessage().contains( "path: id" ) );
tx.rollback();
}
else {
e.printStackTrace();
fail( "Incorrect bridge should raise a SearchException: " + e.toString() );
}
}
catch (Exception e) {
e.printStackTrace();
fail( "Incorrect bridge should raise a SearchException" );
}
s.close();
}
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class[] {
Cloud.class,
IncorrectSet.class,
IncorrectGet.class,
IncorrectObjectToString.class
};
}
@Override
protected void configure(Configuration cfg) {
super.configure( cfg );
cfg.setProperty( Environment.ANALYZER_CLASS, SimpleAnalyzer.class.getName() );
}
}