/* * Hibernate, Relational Persistence for Idiomatic Java * * Copyright (c) 2010, Red Hat, Inc. and/or its affiliates or third-party contributors as * indicated by the @author tags or express copyright attribution * statements applied by the authors. All third-party contributions are * distributed under license by Red Hat, Inc. * * This copyrighted material is made available to anyone wishing to use, modify, * copy, or redistribute it subject to the terms and conditions of the GNU * Lesser General Public License, as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this distribution; if not, write to: * Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA */ 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.SimpleAnalyzer; import org.apache.lucene.index.Term; import org.apache.lucene.queryParser.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.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.SearchTestCase; import org.hibernate.search.test.TestConstants; /** * @author Emmanuel Bernard */ public class BridgeTest extends SearchTestCase { 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(); } 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(); } 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(); } 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 ) ); } 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(); } 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(); } 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(); } protected Class<?>[] getAnnotatedClasses() { return new Class[] { Cloud.class, IncorrectSet.class, IncorrectGet.class, IncorrectObjectToString.class }; } protected void configure(Configuration cfg) { super.configure( cfg ); cfg.setProperty( Environment.ANALYZER_CLASS, SimpleAnalyzer.class.getName() ); } }