Hibernate SVN: r15537 - search/trunk/src/java/org/hibernate/search/filter.
by hibernate-commits@lists.jboss.org
Author: sannegrinovero
Date: 2008-11-10 04:25:20 -0500 (Mon, 10 Nov 2008)
New Revision: 15537
Modified:
search/trunk/src/java/org/hibernate/search/filter/AndDocIdSet.java
Log:
HSEARCH-289 visibility problem in iterators initialization
Modified: search/trunk/src/java/org/hibernate/search/filter/AndDocIdSet.java
===================================================================
--- search/trunk/src/java/org/hibernate/search/filter/AndDocIdSet.java 2008-11-09 16:23:24 UTC (rev 15536)
+++ search/trunk/src/java/org/hibernate/search/filter/AndDocIdSet.java 2008-11-10 09:25:20 UTC (rev 15537)
@@ -29,8 +29,8 @@
this.maxDocNumber = maxDocs;
}
- private synchronized void buildBitset() throws IOException {
- if ( docIdBitSet != null ) return; // double check for concurrent initialization
+ private synchronized OpenBitSet buildBitset() throws IOException {
+ if ( docIdBitSet != null ) return docIdBitSet; // double check for concurrent initialization
//TODO if all andedDocIdSets are actually DocIdBitSet, use their internal BitSet instead of next algo.
//TODO if some andedDocIdSets are DocIdBitSet, merge them first.
int size = andedDocIdSets.size();
@@ -49,6 +49,7 @@
bitSet = new OpenBitSet(); //TODO a less expensive "empty"
}
docIdBitSet = bitSet;
+ return bitSet;
}
private final void markBitSetOnAgree(final DocIdSetIterator[] iterators, final OpenBitSet result) throws IOException {
@@ -132,10 +133,9 @@
return iterator.skipTo( target );
}
- private void ensureInitialized() throws IOException {
- if ( docIdBitSet == null ) buildBitset();
+ private final void ensureInitialized() throws IOException {
if ( iterator == null ) {
- iterator = docIdBitSet.iterator();
+ iterator = buildBitset().iterator();
}
}
16 years, 2 months
Hibernate SVN: r15536 - in search/trunk/src: java/org/hibernate/search/filter and 1 other directories.
by hibernate-commits@lists.jboss.org
Author: sannegrinovero
Date: 2008-11-09 11:23:24 -0500 (Sun, 09 Nov 2008)
New Revision: 15536
Added:
search/trunk/src/test/org/hibernate/search/test/filter/AndDocIdSetsTest.java
Modified:
search/trunk/src/java/org/hibernate/search/engine/FilterDef.java
search/trunk/src/java/org/hibernate/search/filter/AndDocIdSet.java
search/trunk/src/java/org/hibernate/search/filter/ChainedFilter.java
Log:
HSEARCH-289 testcases and some speedup
Modified: search/trunk/src/java/org/hibernate/search/engine/FilterDef.java
===================================================================
--- search/trunk/src/java/org/hibernate/search/engine/FilterDef.java 2008-11-09 06:34:45 UTC (rev 15535)
+++ search/trunk/src/java/org/hibernate/search/engine/FilterDef.java 2008-11-09 16:23:24 UTC (rev 15536)
@@ -11,7 +11,7 @@
import org.hibernate.search.annotations.FullTextFilterDef;
/**
- * A wrapper class which encapsualtes all required information to create a defined filter.
+ * A wrapper class which encapsulates all required information to create a defined filter.
*
* @author Emmanuel Bernard
*/
Modified: search/trunk/src/java/org/hibernate/search/filter/AndDocIdSet.java
===================================================================
--- search/trunk/src/java/org/hibernate/search/filter/AndDocIdSet.java 2008-11-09 06:34:45 UTC (rev 15535)
+++ search/trunk/src/java/org/hibernate/search/filter/AndDocIdSet.java 2008-11-09 16:23:24 UTC (rev 15536)
@@ -1,30 +1,32 @@
package org.hibernate.search.filter;
import java.io.IOException;
-import java.util.BitSet;
import java.util.List;
import static java.lang.Math.max;
import org.apache.lucene.search.DocIdSet;
import org.apache.lucene.search.DocIdSetIterator;
-import org.apache.lucene.util.DocIdBitSet;
+import org.apache.lucene.util.OpenBitSet;
/**
- * A DocIdSet built as applying "AND" operation to a list of other DocIdSet.
+ * A DocIdSet built as applying "AND" operation to a list of other DocIdSet(s).
* The DocIdSetIterator returned will return only document ids contained
- * in all DocIdSet handed to the constructor.
+ * in all DocIdSet(s) handed to the constructor.
*
* @author Sanne Grinovero
*/
public class AndDocIdSet extends DocIdSet {
- private DocIdBitSet docIdBitSet;
+ private OpenBitSet docIdBitSet;
private final List<DocIdSet> andedDocIdSets;
- public AndDocIdSet(List<DocIdSet> andedDocIdSets) {
+ private final int maxDocNumber;
+
+ public AndDocIdSet(List<DocIdSet> andedDocIdSets, int maxDocs) {
if ( andedDocIdSets == null || andedDocIdSets.size() < 2 )
- throw new IllegalArgumentException( "To \"and\" some DocIdSet they should be at least 2" );
+ throw new IllegalArgumentException( "To \"and\" some DocIdSet(s) they should be at least 2" );
this.andedDocIdSets = andedDocIdSets;
+ this.maxDocNumber = maxDocs;
}
private synchronized void buildBitset() throws IOException {
@@ -33,71 +35,72 @@
//TODO if some andedDocIdSets are DocIdBitSet, merge them first.
int size = andedDocIdSets.size();
DocIdSetIterator[] iterators = new DocIdSetIterator[size];
- int[] positions = new int[size];
boolean valuesExist = true;
- int maxIndex = 0;
for (int i=0; i<size; i++) {
// build all iterators
- DocIdSetIterator iterator = andedDocIdSets.get(i).iterator();
- iterators[i] = iterator;
- // and move to first position
- boolean nextExists = iterator.next();
- if ( ! nextExists ) {
- valuesExist = false;
- break;
- }
- int currentFilterValue = iterator.doc();
- positions[i] = currentFilterValue;
- // find the initial maximum position
- maxIndex = max( maxIndex, currentFilterValue );
+ iterators[i] = andedDocIdSets.get(i).iterator();
}
- BitSet bitSet = new BitSet();
+ OpenBitSet bitSet;
if ( valuesExist ) { // skip further processing if some idSet is empty
- do {
- if ( allSame( positions ) ) {
- // enable a bit if all idSets agree on it:
- bitSet.set( maxIndex );
- maxIndex++;
- }
- maxIndex = advance( iterators, positions, maxIndex );
- } while ( maxIndex != -1 ); // -1 means the end of some bitSet has been reached (end condition)
+ bitSet = new OpenBitSet( maxDocNumber );
+ markBitSetOnAgree( iterators, bitSet );
}
- docIdBitSet = new DocIdBitSet( bitSet );
+ else {
+ bitSet = new OpenBitSet(); //TODO a less expensive "empty"
+ }
+ docIdBitSet = bitSet;
}
- /**
- * Have all DocIdSetIterator having current doc id minor than currentMaxPosition
- * skip to at least this position.
- * @param iterators
- * @param positions
- * @return maximum position of all DocIdSetIterator after the operation, or -1 when at least one reached the end.
- * @throws IOException
- */
- private final int advance(final DocIdSetIterator[] iterators, final int[] positions, int currentMaxPosition) throws IOException {
- for (int i=0; i<positions.length; i++) {
- if ( positions[i] != currentMaxPosition ) {
- boolean validPosition = iterators[i].skipTo( currentMaxPosition );
- if ( ! validPosition )
- return -1;
- positions[i] = iterators[i].doc();
- currentMaxPosition = max( currentMaxPosition, positions[i] );
+ private final void markBitSetOnAgree(final DocIdSetIterator[] iterators, final OpenBitSet result) throws IOException {
+ final int iteratorSize = iterators.length;
+ int targetPosition = Integer.MIN_VALUE;
+ int votes = 0;
+ // Each iterator can vote "ok" for the current target to
+ // be reached; when all agree the bit is set.
+ // if an iterator disagrees (it jumped longer), it's current position becomes the new targetPosition
+ // for the others and he is considered "first" in the voting round (every iterator votes for himself ;-)
+ int i = 0;
+ //iterator initialize, just one "next" for each DocIdSetIterator
+ for ( ;i<iteratorSize; i++ ) {
+ final DocIdSetIterator iterator = iterators[i];
+ if ( ! iterator.next() ) return; //current iterator has no values, so skip all
+ final int position = iterator.doc();
+ if ( targetPosition==position ) {
+ votes++; //stopped as same position of others
}
+ else {
+ targetPosition = max( targetPosition, position );
+ if (targetPosition==position) //means it changed
+ votes=1;
+ }
}
- return currentMaxPosition;
- }
-
- /**
- * see if all DocIdSetIterator stopped at the same position.
- * @param positions the array of current positions.
- * @return true if all DocIdSetIterator agree on the current docId.
- */
- private final boolean allSame(final int[] positions) {
- int base = positions[0];
- for (int i=1; i<positions.length; i++) {
- if ( base != positions[i] )
- return false;
+ // end iterator initialize
+ if (votes==iteratorSize) {
+ result.fastSet( targetPosition );
+ targetPosition++;
}
- return true;
+ i=0;
+ votes=0; //could be smarted but would make the code even more complex for a minor optimization out of cycle.
+ // enter main loop:
+ while ( true ) {
+ final DocIdSetIterator iterator = iterators[i];
+ final boolean validPosition = iterator.skipTo( targetPosition );
+ if ( ! validPosition )
+ return; //exit condition
+ final int position = iterator.doc();
+ if ( position == targetPosition ) {
+ if ( ++votes == iteratorSize ) {
+ result.fastSet( position );
+ votes = 0;
+ targetPosition++;
+ }
+ }
+ else {
+ votes = 1;
+ targetPosition = position;
+ }
+ i = ++i % iteratorSize;
+ }
}
@Override
Modified: search/trunk/src/java/org/hibernate/search/filter/ChainedFilter.java
===================================================================
--- search/trunk/src/java/org/hibernate/search/filter/ChainedFilter.java 2008-11-09 06:34:45 UTC (rev 15535)
+++ search/trunk/src/java/org/hibernate/search/filter/ChainedFilter.java 2008-11-09 16:23:24 UTC (rev 15536)
@@ -52,7 +52,7 @@
for ( Filter f : chainedFilters ) {
subSets.add( f.getDocIdSet( reader ) );
}
- return new AndDocIdSet( subSets );
+ return new AndDocIdSet( subSets, reader.maxDoc() );
}
}
Added: search/trunk/src/test/org/hibernate/search/test/filter/AndDocIdSetsTest.java
===================================================================
--- search/trunk/src/test/org/hibernate/search/test/filter/AndDocIdSetsTest.java (rev 0)
+++ search/trunk/src/test/org/hibernate/search/test/filter/AndDocIdSetsTest.java 2008-11-09 16:23:24 UTC (rev 15536)
@@ -0,0 +1,246 @@
+package org.hibernate.search.test.filter;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.Collections;
+import java.util.List;
+import java.util.Random;
+
+import org.apache.lucene.search.DocIdSet;
+import org.apache.lucene.search.DocIdSetIterator;
+import org.apache.lucene.util.DocIdBitSet;
+import org.hibernate.search.filter.AndDocIdSet;
+
+import junit.framework.TestCase;
+
+/**
+ * Functionality testcase for org.hibernate.search.filter.AndDocIdSet.
+ * There is a main method to run some very approximate performance
+ * comparisons with the use of java.util.BitSet ands.
+ * The numbers show the AndDocIdSet should be used only when it's not
+ * possible to rely on a BitSet; in this class however we use BitSet
+ * as it's useful to test the implementation.
+ *
+ * @see AndDocIdSet
+ * @see BitSet
+ * @author Sanne Grinovero
+ */
+public class AndDocIdSetsTest extends TestCase {
+
+ static final List<Integer> testDataFrom0to9 = toImmutableList( 0,1,2,3,4,5,6,7,8,9 );
+ static final List<Integer> testDataFrom1to10 = toImmutableList( 1,2,3,4,5,6,7,8,9,10 );
+ static final List<Integer> testDataFrom1to9 = toImmutableList( 1,2,3,4,5,6,7,8,9 );
+
+ private static final List<Integer> toImmutableList(int... is) {
+ List<Integer> l = new ArrayList<Integer>( is.length );
+ for ( int i=0; i<is.length; i++ ) {
+ l.add( Integer.valueOf( is[i] ) );
+ }
+ return Collections.unmodifiableList( l );
+ }
+
+ @SuppressWarnings("unchecked")
+ List<Integer> andLists(List<Integer>... lists) {
+ if (lists.length==0) {
+ return Collections.EMPTY_LIST;
+ }
+ List<Integer> result = new ArrayList<Integer>( lists[0] );
+ for (int i=1; i<lists.length; i++) {
+ result.retainAll( lists[i] );
+ }
+ return result;
+ }
+
+ // auto-testing of test utility methods for AND operations on test arrays
+ @SuppressWarnings("unchecked")
+ public void testAndingArrays() {
+ List<Integer> andLists = andLists( testDataFrom0to9, testDataFrom1to10 );
+ assertTrue( andLists.containsAll( testDataFrom1to9 ) );
+ assertFalse( andLists.contains( Integer.valueOf( 0 ) ) );
+ assertFalse( andLists.contains( Integer.valueOf( 10 ) ) );
+ assertTrue( andLists.equals( testDataFrom1to9 ) );
+ DocIdSet docIdSet0_9 = arrayToDocIdSet(testDataFrom0to9);
+ DocIdSet docIdSet1_10 = arrayToDocIdSet(testDataFrom1to10);
+ DocIdSet docIdSet1_9 = arrayToDocIdSet(testDataFrom1to9);
+ assertTrue( docIdSetsEqual( docIdSet0_9, docIdSet0_9 ) );
+ assertTrue( docIdSetsEqual( docIdSet1_10, docIdSet1_10 ) );
+ assertFalse( docIdSetsEqual( docIdSet1_10, docIdSet1_9 ) );
+ assertFalse( docIdSetsEqual( docIdSet0_9, docIdSet1_9 ) );
+ }
+
+ // auto-testing of test utility methods for conversion in DocIdSetIterator
+ public void testIteratorMatchesTestArray() throws IOException {
+ DocIdSet docIdSet0_9 = arrayToDocIdSet(testDataFrom0to9);
+ DocIdSetIterator docIdSetIterator = docIdSet0_9.iterator();
+ assertTrue( docIdSetIterator.next() );
+ assertEquals( 0, docIdSetIterator.doc() );
+ assertTrue( docIdSetIterator.skipTo(9) );
+ assertFalse( docIdSetIterator.skipTo(10) );
+ }
+
+ public void testAndDocIdSets() {
+ List<DocIdSet> filters = new ArrayList<DocIdSet>( 2 );
+ filters.add( arrayToDocIdSet( testDataFrom0to9 ) );
+ filters.add( arrayToDocIdSet( testDataFrom1to10 ) );
+ DocIdSet expected = arrayToDocIdSet( testDataFrom1to9 );
+ DocIdSet testedSet = new AndDocIdSet( filters, 10 );
+ assertTrue( docIdSetsEqual( expected, testedSet ) );
+ }
+
+ public void testOnRandomBigArrays(){
+ onRandomBigArraysTest( 13L );
+ onRandomBigArraysTest( 9L );
+ onRandomBigArraysTest( 71L );
+ }
+
+ public void onRandomBigArraysTest(long randomSeed) {
+ List<BitSet> filtersData = makeRandomBitSetList( randomSeed, 4, 1000000, 1500000 );
+ BitSet expectedBitset = applyANDOnBitSets( filtersData );
+ List<DocIdSet> filters = toDocIdSetList( filtersData );
+ DocIdBitSet expectedDocIdSet = new DocIdBitSet( expectedBitset );
+ DocIdSet testedSet = new AndDocIdSet( filters, 1500000 );
+ assertTrue( docIdSetsEqual(expectedDocIdSet, testedSet) );
+ }
+
+ private static List<DocIdSet> toDocIdSetList(List<BitSet> filtersData) {
+ List<DocIdSet> docIdSets = new ArrayList<DocIdSet>( filtersData.size() );
+ for (BitSet bitSet : filtersData) {
+ docIdSets.add ( new DocIdBitSet(bitSet) );
+ }
+ return docIdSets;
+ }
+
+ public static void main(String[] args) throws IOException {
+ compareAndingPerformance( 8, 1000000, 1500000 );
+ compareAndingPerformance( 4, 1000000, 1500000 );
+ compareAndingPerformance( 2, 1000000, 1500000 );
+ compareAndingPerformance( 2, 100000000, 150000000 );
+ compareAndingPerformance( 4, 100000000, 150000000 );
+ compareAndingPerformance( 8, 100000000, 150000000 );
+ }
+
+ private static void compareAndingPerformance(final int listSize,
+ final int minBitsSize, final int maxBitsSize) throws IOException {
+ List<BitSet> filtersData = makeRandomBitSetList( 13L, listSize, minBitsSize, maxBitsSize );
+ DocIdSet andedByBitsResult = null;
+ DocIdSet andedByIterationResult = null;
+ {
+ long startTime = System.currentTimeMillis();
+ for ( int i=0; i<1000; i++ ) {
+ BitSet expectedBitset = applyANDOnBitSets( filtersData );
+ andedByBitsResult = new DocIdBitSet( expectedBitset );
+ // iteration is needed to have a fair comparison with other impl:
+ iterateOnResults( andedByBitsResult );
+ }
+ long totalTimeMs = System.currentTimeMillis() - startTime;
+ System.out.println( "Time to \"AND " + listSize +
+ " BitSets and iterate on results\" 1000 times: " +
+ totalTimeMs + "ms. (" +
+ minBitsSize +" minimum BitSet size)");
+ }
+ List<DocIdSet> docIdSetList = toDocIdSetList( filtersData );
+ {
+ long startTime = System.currentTimeMillis();
+ for ( int i=0; i<1000; i++ ) {
+ andedByIterationResult = new AndDocIdSet( docIdSetList, maxBitsSize );
+ // iteration is needed because the AND is been done lazily on iterator access:
+ iterateOnResults( andedByIterationResult );
+ }
+ long totalTimeMs = System.currentTimeMillis() - startTime;
+ System.out.println( "Time to \"use AndDocIdSet iterator on " + listSize +
+ " Filters and iterate on results\" 1000 times: " +
+ totalTimeMs + "ms. (" +
+ minBitsSize +" minimum BitSet size)");
+ }
+ System.out.println(" Results are same: " + docIdSetsEqual( andedByBitsResult, andedByIterationResult ) );
+ }
+
+ private static int iterateOnResults(DocIdSet docIdBitSet) throws IOException {
+ DocIdSetIterator iterator = docIdBitSet.iterator();
+ int i = 0;
+ while ( iterator.next() ) {
+ i += iterator.doc();
+ }
+ return i;
+ }
+
+ private static final BitSet applyANDOnBitSets(final List<BitSet> filtersData) {
+ BitSet andedBitSet = null;
+ for (BitSet bits : filtersData) {
+ if ( andedBitSet==null ) {
+ andedBitSet = (BitSet) bits.clone();
+ }
+ else {
+ andedBitSet.and( bits );
+ }
+ }
+ return andedBitSet;
+ }
+
+ private static List<BitSet> makeRandomBitSetList(final long randomSeed, final int listSize,
+ final int minBitsSize, final int maxBitsSize) {
+ Random r = new Random( randomSeed ); //have a fixed Seed for repeatable tests
+ List<BitSet> restulList = new ArrayList<BitSet>( listSize );
+ for (int i=0; i<listSize; i++) {
+ int arraySize = minBitsSize + r.nextInt( maxBitsSize-minBitsSize );
+ restulList.add( makeRandomBitSet( r, arraySize) );
+ }
+ return restulList;
+ }
+
+ private static BitSet makeRandomBitSet(final Random randomSource, final int maxSize){
+ BitSet bitSet = new BitSet();
+ for ( int datai=0; datai<maxSize; datai++ ) {
+ // each bit has 50% change to be set:
+ if ( randomSource.nextBoolean() ) bitSet.set( datai );
+ }
+ return bitSet;
+ }
+
+ /**
+ * converts a list of Integers representing Document ids
+ * into a Lucene DocIdSet
+ * @param docIdList
+ * @return
+ */
+ public DocIdSet arrayToDocIdSet(List<Integer> docIdList) {
+ BitSet bitset = new BitSet();
+ for (int i : docIdList) {
+ bitset.set(i);
+ }
+ return new DocIdBitSet(bitset);
+ }
+
+ /**
+ * @param a
+ * @param b
+ * @return true if the two DocIdSet are equal: contain the same number of ids, same order and all are equal
+ */
+ public static final boolean docIdSetsEqual(DocIdSet expected, DocIdSet tested) {
+ DocIdSetIterator iterA = expected.iterator();
+ DocIdSetIterator iterB = tested.iterator();
+ boolean nextA = false;
+ boolean nextB = false;
+ try{
+ do {
+ nextA = iterA.next();
+ nextB = iterB.next();
+ if ( nextA!=nextB ) {
+ return false;
+ }
+ else if ( nextA==false) {
+ return true;
+ }
+ else if ( iterA.doc() != iterB.doc() ) {
+ return false;
+ }
+ } while ( nextA && nextB );
+ }
+ catch (IOException ioe) {
+ fail( "these DocIdSetIterator instances should not throw any exceptions" );
+ }
+ return true;
+ }
+
+}
Property changes on: search/trunk/src/test/org/hibernate/search/test/filter/AndDocIdSetsTest.java
___________________________________________________________________
Name: svn:executable
+ *
16 years, 2 months
Hibernate SVN: r15535 - in search/trunk/src: test/org/hibernate/search/test/filter and 1 other directory.
by hibernate-commits@lists.jboss.org
Author: epbernard
Date: 2008-11-09 01:34:45 -0500 (Sun, 09 Nov 2008)
New Revision: 15535
Added:
search/trunk/src/java/org/hibernate/search/filter/AndDocIdSet.java
search/trunk/src/java/org/hibernate/search/filter/EmptyDocIdBitSet.java
Modified:
search/trunk/src/java/org/hibernate/search/filter/CachingWrapperFilter.java
search/trunk/src/java/org/hibernate/search/filter/ChainedFilter.java
search/trunk/src/test/org/hibernate/search/test/filter/ExcludeAllFilter.java
Log:
HSEARCH-289 move to DocIdSet use.
Added: search/trunk/src/java/org/hibernate/search/filter/AndDocIdSet.java
===================================================================
--- search/trunk/src/java/org/hibernate/search/filter/AndDocIdSet.java (rev 0)
+++ search/trunk/src/java/org/hibernate/search/filter/AndDocIdSet.java 2008-11-09 06:34:45 UTC (rev 15535)
@@ -0,0 +1,141 @@
+package org.hibernate.search.filter;
+
+import java.io.IOException;
+import java.util.BitSet;
+import java.util.List;
+import static java.lang.Math.max;
+
+import org.apache.lucene.search.DocIdSet;
+import org.apache.lucene.search.DocIdSetIterator;
+import org.apache.lucene.util.DocIdBitSet;
+
+/**
+ * A DocIdSet built as applying "AND" operation to a list of other DocIdSet.
+ * The DocIdSetIterator returned will return only document ids contained
+ * in all DocIdSet handed to the constructor.
+ *
+ * @author Sanne Grinovero
+ */
+public class AndDocIdSet extends DocIdSet {
+
+ private DocIdBitSet docIdBitSet;
+ private final List<DocIdSet> andedDocIdSets;
+
+ public AndDocIdSet(List<DocIdSet> andedDocIdSets) {
+ if ( andedDocIdSets == null || andedDocIdSets.size() < 2 )
+ throw new IllegalArgumentException( "To \"and\" some DocIdSet they should be at least 2" );
+ this.andedDocIdSets = andedDocIdSets;
+ }
+
+ private synchronized void buildBitset() throws IOException {
+ if ( docIdBitSet != null ) return; // double check for concurrent initialization
+ //TODO if all andedDocIdSets are actually DocIdBitSet, use their internal BitSet instead of next algo.
+ //TODO if some andedDocIdSets are DocIdBitSet, merge them first.
+ int size = andedDocIdSets.size();
+ DocIdSetIterator[] iterators = new DocIdSetIterator[size];
+ int[] positions = new int[size];
+ boolean valuesExist = true;
+ int maxIndex = 0;
+ for (int i=0; i<size; i++) {
+ // build all iterators
+ DocIdSetIterator iterator = andedDocIdSets.get(i).iterator();
+ iterators[i] = iterator;
+ // and move to first position
+ boolean nextExists = iterator.next();
+ if ( ! nextExists ) {
+ valuesExist = false;
+ break;
+ }
+ int currentFilterValue = iterator.doc();
+ positions[i] = currentFilterValue;
+ // find the initial maximum position
+ maxIndex = max( maxIndex, currentFilterValue );
+ }
+ BitSet bitSet = new BitSet();
+ if ( valuesExist ) { // skip further processing if some idSet is empty
+ do {
+ if ( allSame( positions ) ) {
+ // enable a bit if all idSets agree on it:
+ bitSet.set( maxIndex );
+ maxIndex++;
+ }
+ maxIndex = advance( iterators, positions, maxIndex );
+ } while ( maxIndex != -1 ); // -1 means the end of some bitSet has been reached (end condition)
+ }
+ docIdBitSet = new DocIdBitSet( bitSet );
+ }
+
+ /**
+ * Have all DocIdSetIterator having current doc id minor than currentMaxPosition
+ * skip to at least this position.
+ * @param iterators
+ * @param positions
+ * @return maximum position of all DocIdSetIterator after the operation, or -1 when at least one reached the end.
+ * @throws IOException
+ */
+ private final int advance(final DocIdSetIterator[] iterators, final int[] positions, int currentMaxPosition) throws IOException {
+ for (int i=0; i<positions.length; i++) {
+ if ( positions[i] != currentMaxPosition ) {
+ boolean validPosition = iterators[i].skipTo( currentMaxPosition );
+ if ( ! validPosition )
+ return -1;
+ positions[i] = iterators[i].doc();
+ currentMaxPosition = max( currentMaxPosition, positions[i] );
+ }
+ }
+ return currentMaxPosition;
+ }
+
+ /**
+ * see if all DocIdSetIterator stopped at the same position.
+ * @param positions the array of current positions.
+ * @return true if all DocIdSetIterator agree on the current docId.
+ */
+ private final boolean allSame(final int[] positions) {
+ int base = positions[0];
+ for (int i=1; i<positions.length; i++) {
+ if ( base != positions[i] )
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public DocIdSetIterator iterator() {
+ return new AndingDocIdSetIterator();
+ }
+
+ private class AndingDocIdSetIterator extends DocIdSetIterator {
+
+ private DocIdSetIterator iterator;
+
+ @Override
+ public int doc() {
+ // should never happen when respecting interface contract; otherwise I
+ // prefer a NPE than a hard to debug return 0.
+ assert iterator != null : "Illegal state, can't be called before next() or skipTo(int)";
+ return iterator.doc();
+ }
+
+ @Override
+ public boolean next() throws IOException {
+ ensureInitialized(); //can't initialize before as it would not be allowed to throw IOException
+ return iterator.next();
+ }
+
+ @Override
+ public boolean skipTo(int target) throws IOException {
+ ensureInitialized(); //can't initialize before as it would not be allowed to throw IOException
+ return iterator.skipTo( target );
+ }
+
+ private void ensureInitialized() throws IOException {
+ if ( docIdBitSet == null ) buildBitset();
+ if ( iterator == null ) {
+ iterator = docIdBitSet.iterator();
+ }
+ }
+
+ }
+
+}
Modified: search/trunk/src/java/org/hibernate/search/filter/CachingWrapperFilter.java
===================================================================
--- search/trunk/src/java/org/hibernate/search/filter/CachingWrapperFilter.java 2008-11-08 22:25:28 UTC (rev 15534)
+++ search/trunk/src/java/org/hibernate/search/filter/CachingWrapperFilter.java 2008-11-09 06:34:45 UTC (rev 15535)
@@ -5,6 +5,7 @@
import java.util.BitSet;
import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.search.DocIdSet;
import org.apache.lucene.search.Filter;
import org.slf4j.Logger;
@@ -27,53 +28,56 @@
public static final int DEFAULT_SIZE = 5;
- private final int size;
-
/**
* The cache using soft references in order to store the filter bit sets.
*/
- private transient SoftLimitMRUCache cache;
+ private final SoftLimitMRUCache cache;
private final Filter filter;
/**
- * @param filter
- * Filter to cache results of
+ * @param filter Filter to cache results of
*/
public CachingWrapperFilter(Filter filter) {
this(filter, DEFAULT_SIZE);
}
/**
- * @param filter
- * Filter to cache results of
+ * @param filter Filter to cache results of
*/
public CachingWrapperFilter(Filter filter, int size) {
this.filter = filter;
- this.size = size;
+ log.debug( "Initialising SoftLimitMRUCache with hard ref size of {}", size );
+ this.cache = new SoftLimitMRUCache( size );
}
+ @Override
public BitSet bits(IndexReader reader) throws IOException {
- if (cache == null) {
- log.debug("Initialising SoftLimitMRUCache with hard ref size of {}", size);
- cache = new SoftLimitMRUCache(size);
+ throw new UnsupportedOperationException();
+ /* BitSet cached = (BitSet) cache.get(reader);
+ if (cached != null) {
+ return cached;
}
-
- //memory barrier ensure cache == null will not always stay true on concurrent threads
- synchronized (cache) { // check cache
- BitSet cached = (BitSet) cache.get(reader);
- if (cached != null) {
+ final BitSet bits = filter.bits(reader);
+ cache.put(reader, bits);
+ return bits; */
+ }
+
+ @Override
+ public DocIdSet getDocIdSet(IndexReader reader) throws IOException {
+ DocIdSet cached = (DocIdSet) cache.get( reader );
+ if ( cached != null ) {
+ return cached;
+ }
+ synchronized (cache) {
+ cached = (DocIdSet) cache.get( reader );
+ if ( cached != null ) {
return cached;
}
+ final DocIdSet docIdSet = filter.getDocIdSet( reader );
+ cache.put( reader, docIdSet );
+ return docIdSet;
}
-
- final BitSet bits = filter.bits(reader);
-
- synchronized (cache) { // update cache
- cache.put(reader, bits);
- }
-
- return bits;
}
public String toString() {
Modified: search/trunk/src/java/org/hibernate/search/filter/ChainedFilter.java
===================================================================
--- search/trunk/src/java/org/hibernate/search/filter/ChainedFilter.java 2008-11-08 22:25:28 UTC (rev 15534)
+++ search/trunk/src/java/org/hibernate/search/filter/ChainedFilter.java 2008-11-09 06:34:45 UTC (rev 15535)
@@ -6,6 +6,7 @@
import java.util.ArrayList;
import java.io.IOException;
+import org.apache.lucene.search.DocIdSet;
import org.apache.lucene.search.Filter;
import org.apache.lucene.index.IndexReader;
import org.hibernate.annotations.common.AssertionFailure;
@@ -14,6 +15,7 @@
* @author Emmanuel Bernard
*/
public class ChainedFilter extends Filter {
+
private static final long serialVersionUID = -6153052295766531920L;
private final List<Filter> chainedFilters = new ArrayList<Filter>();
@@ -23,6 +25,8 @@
}
public BitSet bits(IndexReader reader) throws IOException {
+ throw new UnsupportedOperationException();
+ /*
if (chainedFilters.size() == 0) throw new AssertionFailure("Chainedfilter has no filters to chain for");
//we need to copy the first BitSet because BitSet is modified by .logicalOp
Filter filter = chainedFilters.get( 0 );
@@ -31,7 +35,26 @@
result.and( chainedFilters.get( index ).bits( reader ) );
}
return result;
+ */
}
+
+ @Override
+ public DocIdSet getDocIdSet(IndexReader reader) throws IOException {
+ int size = chainedFilters.size();
+ if ( size == 0 ) {
+ throw new AssertionFailure( "Chainedfilter has no filters to chain for" );
+ }
+ else if ( size == 1 ) {
+ return chainedFilters.get(0).getDocIdSet(reader);
+ }
+ else {
+ List<DocIdSet> subSets = new ArrayList<DocIdSet>( size );
+ for ( Filter f : chainedFilters ) {
+ subSets.add( f.getDocIdSet( reader ) );
+ }
+ return new AndDocIdSet( subSets );
+ }
+ }
public String toString() {
StringBuilder sb = new StringBuilder("ChainedFilter [");
Added: search/trunk/src/java/org/hibernate/search/filter/EmptyDocIdBitSet.java
===================================================================
--- search/trunk/src/java/org/hibernate/search/filter/EmptyDocIdBitSet.java (rev 0)
+++ search/trunk/src/java/org/hibernate/search/filter/EmptyDocIdBitSet.java 2008-11-09 06:34:45 UTC (rev 15535)
@@ -0,0 +1,46 @@
+package org.hibernate.search.filter;
+
+import java.io.IOException;
+
+import org.apache.lucene.search.DocIdSet;
+import org.apache.lucene.search.DocIdSetIterator;
+
+public class EmptyDocIdBitSet extends DocIdSet {
+
+ public static final DocIdSet instance = new EmptyDocIdBitSet();
+
+ private final DocIdSetIterator iterator = new EmptyDocIdSetIterator();
+
+ private EmptyDocIdBitSet(){
+ // is singleton
+ }
+
+ @Override
+ public DocIdSetIterator iterator() {
+ return iterator;
+ }
+
+ /**
+ * implements a DocIdSetIterator for an empty DocIdSet
+ * As it is empty it also is stateless and so it can be reused.
+ */
+ private static class EmptyDocIdSetIterator extends DocIdSetIterator {
+
+ @Override
+ public int doc() {
+ throw new IllegalStateException("Should never be called");
+ }
+
+ @Override
+ public boolean next() throws IOException {
+ return false;
+ }
+
+ @Override
+ public boolean skipTo(int target) throws IOException {
+ return false;
+ }
+
+ }
+
+}
Modified: search/trunk/src/test/org/hibernate/search/test/filter/ExcludeAllFilter.java
===================================================================
--- search/trunk/src/test/org/hibernate/search/test/filter/ExcludeAllFilter.java 2008-11-08 22:25:28 UTC (rev 15534)
+++ search/trunk/src/test/org/hibernate/search/test/filter/ExcludeAllFilter.java 2008-11-09 06:34:45 UTC (rev 15535)
@@ -4,20 +4,33 @@
import java.util.BitSet;
import java.io.IOException;
+import org.apache.lucene.search.DocIdSet;
import org.apache.lucene.search.Filter;
import org.apache.lucene.index.IndexReader;
+import org.hibernate.search.filter.EmptyDocIdBitSet;
/**
* @author Emmanuel Bernard
*/
@SuppressWarnings("serial")
public class ExcludeAllFilter extends Filter {
+
+ //ugly but useful for test purposes
private static volatile boolean done = false;
+ @Override
public BitSet bits(IndexReader reader) throws IOException {
- if (done) throw new IllegalStateException("Called twice");
+ if ( done ) throw new IllegalStateException( "Called twice" );
BitSet bitSet = new BitSet( reader.maxDoc() );
done = true;
return bitSet;
}
+
+ @Override
+ public DocIdSet getDocIdSet(IndexReader reader) throws IOException {
+ if ( done ) throw new IllegalStateException( "Called twice" );
+ done = true;
+ return EmptyDocIdBitSet.instance;
+ }
+
}
16 years, 2 months
Hibernate SVN: r15534 - in search/trunk/src: java/org/hibernate/search/util and 1 other directories.
by hibernate-commits@lists.jboss.org
Author: epbernard
Date: 2008-11-08 17:25:28 -0500 (Sat, 08 Nov 2008)
New Revision: 15534
Modified:
search/trunk/src/java/org/hibernate/search/annotations/FilterCacheModeType.java
search/trunk/src/java/org/hibernate/search/annotations/FullTextFilterDef.java
search/trunk/src/java/org/hibernate/search/util/FilterCacheModeTypeHelper.java
search/trunk/src/test/org/hibernate/search/test/filter/Driver.java
Log:
HSEARCH-294 rename to INSTANCE_AND_DOCIDSETRESULTS
Modified: search/trunk/src/java/org/hibernate/search/annotations/FilterCacheModeType.java
===================================================================
--- search/trunk/src/java/org/hibernate/search/annotations/FilterCacheModeType.java 2008-11-07 19:58:13 UTC (rev 15533)
+++ search/trunk/src/java/org/hibernate/search/annotations/FilterCacheModeType.java 2008-11-08 22:25:28 UTC (rev 15534)
@@ -15,7 +15,7 @@
/**
* The filter instance is cached by Hibernate Search and reused across
- * concurrent <code>Filter.bits()</code> calls.
+ * concurrent <code>Filter.getDocIdSet()</code> calls.
* Results are not cached by Hibernate Search.
*
* @see org.apache.lucene.search.Filter#bits(org.apache.lucene.index.IndexReader)
@@ -24,13 +24,13 @@
INSTANCE_ONLY,
/**
- * Both the filter instance and the <code>BitSet</code> results are cached.
+ * Both the filter instance and the <code>DocIdSet</code> results are cached.
* The filter instance is cached by Hibernate Search and reused across
- * concurrent <code>Filter.bits()</code> calls.
- * <code>BitSet</code> results are cached per <code>IndexReader</code>.
+ * concurrent <code>Filter.getDocIdSet()</code> calls.
+ * <code>DocIdSet</code> results are cached per <code>IndexReader</code>.
*
* @see org.apache.lucene.search.Filter#bits(org.apache.lucene.index.IndexReader)
*/
- INSTANCE_AND_BITSETRESULTS
+ INSTANCE_AND_DOCIDSETRESULTS
}
Modified: search/trunk/src/java/org/hibernate/search/annotations/FullTextFilterDef.java
===================================================================
--- search/trunk/src/java/org/hibernate/search/annotations/FullTextFilterDef.java 2008-11-07 19:58:13 UTC (rev 15533)
+++ search/trunk/src/java/org/hibernate/search/annotations/FullTextFilterDef.java 2008-11-08 22:25:28 UTC (rev 15534)
@@ -37,5 +37,5 @@
/**
* Cache mode for the filter. Default to instance and results caching
*/
- FilterCacheModeType cache() default FilterCacheModeType.INSTANCE_AND_BITSETRESULTS;
+ FilterCacheModeType cache() default FilterCacheModeType.INSTANCE_AND_DOCIDSETRESULTS;
}
Modified: search/trunk/src/java/org/hibernate/search/util/FilterCacheModeTypeHelper.java
===================================================================
--- search/trunk/src/java/org/hibernate/search/util/FilterCacheModeTypeHelper.java 2008-11-07 19:58:13 UTC (rev 15533)
+++ search/trunk/src/java/org/hibernate/search/util/FilterCacheModeTypeHelper.java 2008-11-08 22:25:28 UTC (rev 15534)
@@ -13,7 +13,7 @@
switch ( type ) {
case NONE:
return false;
- case INSTANCE_AND_BITSETRESULTS:
+ case INSTANCE_AND_DOCIDSETRESULTS:
return true;
case INSTANCE_ONLY:
return true;
@@ -26,7 +26,7 @@
switch ( type ) {
case NONE:
return false;
- case INSTANCE_AND_BITSETRESULTS:
+ case INSTANCE_AND_DOCIDSETRESULTS:
return true;
case INSTANCE_ONLY:
return false;
Modified: search/trunk/src/test/org/hibernate/search/test/filter/Driver.java
===================================================================
--- search/trunk/src/test/org/hibernate/search/test/filter/Driver.java 2008-11-07 19:58:13 UTC (rev 15533)
+++ search/trunk/src/test/org/hibernate/search/test/filter/Driver.java 2008-11-08 22:25:28 UTC (rev 15534)
@@ -22,8 +22,8 @@
@Indexed
@FullTextFilterDefs( {
@FullTextFilterDef(name = "bestDriver", impl = BestDriversFilter.class, cache = FilterCacheModeType.NONE), //actual Filter implementation
- @FullTextFilterDef(name = "security", impl = SecurityFilterFactory.class, cache = FilterCacheModeType.INSTANCE_AND_BITSETRESULTS), //Filter factory with parameters
- @FullTextFilterDef(name = "cacheresultstest", impl = ExcludeAllFilterFactory.class, cache = FilterCacheModeType.INSTANCE_AND_BITSETRESULTS),
+ @FullTextFilterDef(name = "security", impl = SecurityFilterFactory.class, cache = FilterCacheModeType.INSTANCE_AND_DOCIDSETRESULTS), //Filter factory with parameters
+ @FullTextFilterDef(name = "cacheresultstest", impl = ExcludeAllFilterFactory.class, cache = FilterCacheModeType.INSTANCE_AND_DOCIDSETRESULTS),
@FullTextFilterDef(name = "cacheinstancetest", impl = InstanceBasedExcludeAllFilter.class, cache = FilterCacheModeType.INSTANCE_ONLY)
})
public class Driver {
16 years, 2 months
Hibernate SVN: r15533 - in search/trunk: src/test/org/hibernate/search/test and 1 other directories.
by hibernate-commits@lists.jboss.org
Author: hardy.ferentschik
Date: 2008-11-07 14:58:13 -0500 (Fri, 07 Nov 2008)
New Revision: 15533
Added:
search/trunk/src/test/org/hibernate/search/test/TestCase.java
search/trunk/src/test/org/hibernate/search/test/classloading/
search/trunk/src/test/org/hibernate/search/test/classloading/Animal.hbm.xml
search/trunk/src/test/org/hibernate/search/test/classloading/Animal.java
search/trunk/src/test/org/hibernate/search/test/classloading/NoAnnotationsTest.java
Modified:
search/trunk/build.xml
search/trunk/common-build.xml
search/trunk/src/test/org/hibernate/search/test/HANTestCase.java
Log:
HSEARCH-104
Changed the build so that some tests are run without the optional jar files. Added test that it is possible to use Hibernate Search without JPA.
Modified: search/trunk/build.xml
===================================================================
--- search/trunk/build.xml 2008-11-07 16:06:17 UTC (rev 15532)
+++ search/trunk/build.xml 2008-11-07 19:58:13 UTC (rev 15533)
@@ -8,163 +8,186 @@
-->
<project name="Hibernate Search" default="dist" basedir="."
- xmlns:ivy="antlib:fr.jayasoft.ivy.ant">
+ xmlns:ivy="antlib:fr.jayasoft.ivy.ant">
<!-- Give user a chance to override without editing this file
(and without typing -D each time it compiles it) -->
- <property file="build.properties"/>
- <property file="${user.home}/.ant.properties"/>
+ <property file="build.properties"/>
+ <property file="${user.home}/.ant.properties"/>
- <!-- Name of project and version, used to create filenames -->
- <property name="Name" value="Hibernate Search"/>
- <property name="name" value="hibernate-search"/>
- <property name="version" value="3.1.0.Beta2"/>
- <property name="javadoc.packagenames" value="org.hibernate.search.*"/>
- <property name="copy.test" value="true"/>
- <property name="javac.source" value="1.5"/>
- <property name="javac.target" value="1.5"/>
+ <!-- Name of project and version, used to create filenames -->
+ <property name="Name" value="Hibernate Search"/>
+ <property name="name" value="hibernate-search"/>
+ <property name="version" value="3.1.0.Beta2"/>
+ <property name="javadoc.packagenames" value="org.hibernate.search.*"/>
+ <property name="copy.test" value="true"/>
+ <property name="javac.source" value="1.5"/>
+ <property name="javac.target" value="1.5"/>
<property name="jdbc.dir" value="jdbc"/>
<property name="common.dir" value="${basedir}"/>
- <property name="ivy.dep.dir" value="${basedir}/build/lib" />
+ <property name="ivy.dep.dir" value="${basedir}/build/lib"/>
<!-- ivy load -->
- <property name="ivy.jar.dir" value="${basedir}/ivy" />
- <property name="ivy.conf.dir" value="${basedir}" />
- <path id="ivy.lib.path">
- <fileset dir="${ivy.jar.dir}" includes="*.jar"/>
- </path>
- <taskdef resource="fr/jayasoft/ivy/ant/antlib.xml"
- uri="antlib:fr.jayasoft.ivy.ant" classpathref="ivy.lib.path"/>
+ <property name="ivy.jar.dir" value="${basedir}/ivy"/>
+ <property name="ivy.conf.dir" value="${basedir}"/>
+ <path id="ivy.lib.path">
+ <fileset dir="${ivy.jar.dir}" includes="*.jar"/>
+ </path>
+ <taskdef resource="fr/jayasoft/ivy/ant/antlib.xml"
+ uri="antlib:fr.jayasoft.ivy.ant" classpathref="ivy.lib.path"/>
<import file="${common.dir}/common-build.xml"/>
<property name="build.testresources.dir" value="${build.dir}/testresources"/>
<property name="testresources.dir" value="${basedir}/src/test-resources"/>
- <!-- override order for JBossXB to bootstrap properly -->
- <path id="junit.classpath">
- <fileset dir="${lib.dir}">
- <include name="*.jar"/>
- </fileset>
- <pathelement path="${classes.dir}"/>
- <pathelement path="${testclasses.dir}"/>
- <path refid="junit.moduleclasspath"/>
- <path refid="lib.class.path"/>
- <path location="${clover.jar}"/>
- </path>
-
- <!-- override order for JBossXB to bootstrap properly -->
- <path id="lib.class.path">
+
+ <path id="lib.class.path.required" description="Compile and runtime libraries. Required jars only.">
<fileset dir="${ivy.dep.dir}/core">
<include name="*.jar"/>
<exclude name="xml-apis.jar"/>
<exclude name="xerces*.jar"/>
+ <exclude name="solr*.jar"/>
+ <exclude name="ejb3-persistence.jar"/>
</fileset>
<fileset dir="${lib.dir}">
<include name="*.jar"/>
</fileset>
- <pathelement path="${clover.jar}"/>
</path>
-
- <path id="junit.moduleclasspath">
+
+ <path id="lib.class.path.optional" description="Compile and runtime libraries. Optional jars only.">
+ <fileset dir="${ivy.dep.dir}/core">
+ <include name="solr*.jar"/>
+ <include name="ejb3-persistence.jar"/>
+ </fileset>
+ </path>
+
+ <path id="lib.class.path" description="Compile and runtime libraries.">
+ <path refid="lib.class.path.required"/>
+ <path refid="lib.class.path.optional"/>
+ </path>
+
+ <path id="junit.moduleclasspath.required" description="Test classes. Optional jars excluded.">
<!-- order matters for JBoss XB proper bootstrap -->
<fileset dir="${lib.dir}/test">
- <include name="*.jar"/>
- <include name="*.zip"/>
- </fileset>
+ <include name="*.jar"/>
+ </fileset>
<pathelement location="${src.dir}"/>
- <pathelement location="${test.dir}"/>
- <!-- pathelement location="${annotations.jar}"/>
- <pathelement location="${entitymanager.jar}"/ -->
+ <pathelement location="${test.dir}"/>
<fileset dir="${ivy.dep.dir}/test">
- <include name="*.jar"/>
- </fileset>
+ <include name="*.jar"/>
+ <exclude name="annotations.jar"/>
+ </fileset>
<fileset dir="${jdbc.dir}">
- <include name="*.jar"/>
- <include name="*.zip"/>
- </fileset>
- </path>
+ <include name="*.jar"/>
+ <include name="*.zip"/>
+ </fileset>
+ </path>
+ <path id="junit.moduleclasspath.optional" description="Optional test jars.">
+ <fileset dir="${ivy.dep.dir}/test">
+ <include name="annotations.jar"/>
+ </fileset>
+ </path>
+
+ <path id="junit.classpath.required.only"
+ description="Classpath containing all compile and test classes excluding the optional ones, eg Annotations, Solr, JPA">
+ <fileset dir="${lib.dir}">
+ <include name="*.jar"/>
+ </fileset>
+ <pathelement path="${classes.dir}"/>
+ <pathelement path="${testclasses.dir}"/>
+ <path refid="junit.moduleclasspath.required"/>
+ <path refid="lib.class.path.required"/>
+ </path>
+
+ <path id="junit.classpath"
+ description="Classpath containing all compile and test classes including the optional ones">
+ <path refid="junit.classpath.required.only"/>
+ <path refid="junit.moduleclasspath.optional"/>
+ <path refid="lib.class.path.optional"/>
+ </path>
+
<target name="init">
- <antcall target="common-build.init"/>
+ <antcall target="common-build.init"/>
<tstamp>
<format property="now" pattern="yyyyMMddhhmmss"/>
</tstamp>
<mkdir dir="${ivy.dep.dir}/core"/>
<mkdir dir="${ivy.dep.dir}/test"/>
- <ivy:configure file="${ivy.jar.dir}/ivyconf.xml" />
+ <ivy:configure file="${ivy.jar.dir}/ivyconf.xml"/>
<mkdir dir="${lib.dir}/test"/>
<mkdir dir="${build.testresources.dir}"/>
</target>
<target name="get.deps.core" depends="init" description="retrieve the core dependencies">
- <ivy:resolve conf="default" />
- <ivy:retrieve pattern="${ivy.dep.dir}/core/[artifact].[ext]" conf="default" />
+ <ivy:resolve conf="default"/>
+ <ivy:retrieve pattern="${ivy.dep.dir}/core/[artifact].[ext]" conf="default"/>
</target>
<target name="compile" depends="init,get.deps.core" description="Compile the Java source code">
<available
- classname="org.eclipse.core.launcher.Main"
- property="build.compiler"
- value="org.eclipse.jdt.core.JDTCompilerAdapter"
- classpath="${java.class.path}"/>
- <javac
- srcdir="${src.dir}"
- destdir="${classes.dir}"
- classpathref="lib.class.path"
- debug="${javac.debug}"
- optimize="${javac.optimize}"
- nowarn="on"
+ classname="org.eclipse.core.launcher.Main"
+ property="build.compiler"
+ value="org.eclipse.jdt.core.JDTCompilerAdapter"
+ classpath="${java.class.path}"/>
+ <javac
+ srcdir="${src.dir}"
+ destdir="${classes.dir}"
+ classpathref="lib.class.path"
+ debug="${javac.debug}"
+ optimize="${javac.optimize}"
+ nowarn="on"
source="${javac.source}"
target="${javac.target}">
- <src path="${src.dir}"/>
- </javac>
- <copy todir="${classes.dir}">
- <fileset dir="${src.dir}">
- <include name="**/resources/*.properties"/>
- <include name="**/*.xsd"/>
- </fileset>
- </copy>
- </target>
+ <src path="${src.dir}"/>
+ </javac>
+ <copy todir="${classes.dir}">
+ <fileset dir="${src.dir}">
+ <include name="**/resources/*.properties"/>
+ <include name="**/*.xsd"/>
+ </fileset>
+ </copy>
+ </target>
- <target name="get.deps.test" depends="init" description="retrieve the test dependencies">
- <ivy:resolve conf="test" />
- <ivy:retrieve pattern="${ivy.dep.dir}/test/[artifact].[ext]" conf="test" />
+ <target name="get.deps.test" depends="init" description="retrieve the test dependencies">
+ <ivy:resolve conf="test"/>
+ <ivy:retrieve pattern="${ivy.dep.dir}/test/[artifact].[ext]" conf="test"/>
</target>
<target name="compiletest" depends="init,get.deps.test,compile" description="Compile the tests">
<available
- classname="org.eclipse.core.launcher.Main"
- property="build.compiler"
- value="org.eclipse.jdt.core.JDTCompilerAdapter"
- classpath="${java.class.path}"/>
- <javac
- destdir="${testclasses.dir}"
- classpathref="junit.classpath"
- debug="${javac.debug}"
- optimize="${javac.optimize}"
- nowarn="on"
+ classname="org.eclipse.core.launcher.Main"
+ property="build.compiler"
+ value="org.eclipse.jdt.core.JDTCompilerAdapter"
+ classpath="${java.class.path}"/>
+ <javac
+ destdir="${testclasses.dir}"
+ classpathref="junit.classpath"
+ debug="${javac.debug}"
+ optimize="${javac.optimize}"
+ nowarn="on"
source="${javac.source}"
target="${javac.target}">
- <src refid="testsrc.path"/>
- </javac>
- </target>
+ <src refid="testsrc.path"/>
+ </javac>
+ </target>
<target name="prepare-test-resources" depends="compiletest">
<copy todir="${build.testresources.dir}">
<fileset dir="${testresources.dir}">
<include name="**/*.*"/>
- <exclude name="hibernate.properties"/>
+ <exclude name="hibernate.properties"/>
</fileset>
</copy>
<mkdir dir="${build.testresources.dir}/jars"/>
- <jar filesetmanifest="merge" jarfile="${build.testresources.dir}/jars/jms-slave.jar" >
+ <jar filesetmanifest="merge" jarfile="${build.testresources.dir}/jars/jms-slave.jar">
<fileset dir="${testclasses.dir}">
<include name="org/hibernate/search/test/jms/slave/**.*"/>
</fileset>
</jar>
- <jar filesetmanifest="merge" jarfile="${build.testresources.dir}/jars/jms-master.jar" >
+ <jar filesetmanifest="merge" jarfile="${build.testresources.dir}/jars/jms-master.jar">
<fileset dir="${testclasses.dir}">
<include name="org/hibernate/search/test/jms/master/**.*"/>
</fileset>
@@ -172,101 +195,123 @@
</target>
<target name="junit" depends="compiletest, prepare-test-resources">
- <for list="${targetdb}" param="db">
- <sequential>
- <antcall target="test-resources">
- <param name="db" value="@{db}"/>
- </antcall>
- <mkdir dir="${testreports.dir}/@{db}"/>
- <echo>Running against db: @{db}</echo>
- <junit forkmode="perBatch" printsummary="yes" haltonfailure="yes">
- <classpath>
- <path path="${build.testresources.dir}"/>
- <path refid="junit.classpath"/>
- <fileset dir="${jdbc.dir}">
- <include name="**/*.jar"/>
- <include name="**/*.zip"/>
- </fileset>
- </classpath>
- <sysproperty key="build.dir" value="${build.dir}"/>
- <formatter type="plain"/>
- <formatter type="xml"/>
- <batchtest fork="yes" todir="${testreports.dir}/@{db}" haltonfailure="no">
- <fileset dir="${testclasses.dir}">
- <include name="**/*Test.class"/>
- <exclude name="**/JMSSlaveTest.class"/>
- </fileset>
- </batchtest>
- <test fork="yes" todir="${testreports.dir}/@{db}" haltonfailure="no" name="org.hibernate.search.test.jms.slave.JMSSlaveTest"/>
- </junit>
- </sequential>
- </for>
+ <for list="${targetdb}" param="db">
+ <sequential>
+ <antcall target="test-resources">
+ <param name="db" value="@{db}"/>
+ </antcall>
+ <mkdir dir="${testreports.dir}/@{db}"/>
+ <echo>Running against db: @{db}</echo>
+ <junit forkmode="perBatch" printsummary="yes" haltonfailure="yes">
+ <classpath>
+ <path path="${build.testresources.dir}"/>
+ <path refid="junit.classpath"/>
+ <fileset dir="${jdbc.dir}">
+ <include name="**/*.jar"/>
+ <include name="**/*.zip"/>
+ </fileset>
+ </classpath>
+ <sysproperty key="build.dir" value="${build.dir}"/>
+ <formatter type="plain"/>
+ <formatter type="xml"/>
+ <batchtest fork="yes" todir="${testreports.dir}/@{db}" haltonfailure="no">
+ <fileset dir="${testclasses.dir}">
+ <include name="**/*Test.class"/>
+ <exclude name="**/JMSSlaveTest.class"/>
+ <exclude name="**/classloading/**"/>
+ </fileset>
+ </batchtest>
+ <test fork="yes"
+ todir="${testreports.dir}/@{db}"
+ haltonfailure="no"
+ name="org.hibernate.search.test.jms.slave.JMSSlaveTest"/>
+ </junit>
+ <junit forkmode="perBatch" printsummary="yes" haltonfailure="yes">
+ <classpath>
+ <path path="${build.testresources.dir}"/>
+ <path refid="junit.classpath.required.only"/>
+ <fileset dir="${jdbc.dir}">
+ <include name="**/*.jar"/>
+ <include name="**/*.zip"/>
+ </fileset>
+ </classpath>
+ <sysproperty key="build.dir" value="${build.dir}"/>
+ <formatter type="plain"/>
+ <formatter type="xml"/>
+ <batchtest fork="yes" todir="${testreports.dir}/@{db}" haltonfailure="no">
+ <fileset dir="${testclasses.dir}">
+ <include name="**/classloading/**/*Test.class"/>
+ </fileset>
+ </batchtest>
+ </junit>
+ </sequential>
+ </for>
</target>
- <!-- Run a single unit test. -->
- <target name="junitsingle" depends="compiletest"
- description="Run a single test suite (requires testname and jdbc.driver properties)">
- <for list="${targetdb}" param="db">
- <sequential>
- <antcall target="test-resources">
- <param name="db" value="@{db}"/>
- </antcall>
- <mkdir dir="${testreports.dir}/@{db}"/>
- <echo>Running against db: @{db}</echo>
- <junit printsummary="yes" fork="yes" haltonfailure="yes">
- <classpath>
- <path path="${build.testresources.dir}"/>
- <path refid="junit.classpath"/>
- <fileset dir="${jdbc.dir}">
- <include name="**/*.jar"/>
- <include name="**/*.zip"/>
- </fileset>
- </classpath>
- <sysproperty key="build.dir" value="${build.dir}"/>
- <formatter type="plain"/>
- <formatter type="xml"/>
- <test fork="yes" todir="${testreports.dir}/@{db}" haltonfailure="no" name="${testname}"/>
- </junit>
- </sequential>
- </for>
- </target>
+ <!-- Run a single unit test. -->
+ <target name="junitsingle" depends="compiletest"
+ description="Run a single test suite (requires testname and jdbc.driver properties)">
+ <for list="${targetdb}" param="db">
+ <sequential>
+ <antcall target="test-resources">
+ <param name="db" value="@{db}"/>
+ </antcall>
+ <mkdir dir="${testreports.dir}/@{db}"/>
+ <echo>Running against db: @{db}</echo>
+ <junit printsummary="yes" fork="yes" haltonfailure="yes">
+ <classpath>
+ <path path="${build.testresources.dir}"/>
+ <path refid="junit.classpath"/>
+ <fileset dir="${jdbc.dir}">
+ <include name="**/*.jar"/>
+ <include name="**/*.zip"/>
+ </fileset>
+ </classpath>
+ <sysproperty key="build.dir" value="${build.dir}"/>
+ <formatter type="plain"/>
+ <formatter type="xml"/>
+ <test fork="yes" todir="${testreports.dir}/@{db}" haltonfailure="no" name="${testname}"/>
+ </junit>
+ </sequential>
+ </for>
+ </target>
- <target name="jar" depends="compile" description="Build the distribution .jar file">
- <mkdir dir="${classes.dir}/META-INF"/>
- <manifest file="${classes.dir}/META-INF/MANIFEST.MF">
- <attribute name="Implementation-Title" value="${Name}"/>
- <attribute name="Implementation-Version" value="${version}"/>
+ <target name="jar" depends="compile" description="Build the distribution .jar file">
+ <mkdir dir="${classes.dir}/META-INF"/>
+ <manifest file="${classes.dir}/META-INF/MANIFEST.MF">
+ <attribute name="Implementation-Title" value="${Name}"/>
+ <attribute name="Implementation-Version" value="${version}"/>
<attribute name="Implementation-Vendor" value="hibernate.org"/>
<attribute name="Implementation-Vendor-Id" value="hibernate.org"/>
<attribute name="Implementation-URL" value="http://search.hibernate.org"/>
- </manifest>
- <antcall target="common-build.jar"/>
+ </manifest>
+ <antcall target="common-build.jar"/>
<ivy:resolve conf="default"/>
<ivy:publish artifactspattern="${dist.dir}/[artifact].[ext]"
- resolver="local"
- pubrevision="latest"
- pubdate="${now}"
- status="integration"
- />
+ resolver="local"
+ pubrevision="latest"
+ pubdate="${now}"
+ status="integration"
+ />
</target>
- <!-- Some of this can probably be moved to common-build... -->
- <target name="dist" depends="get.deps.core,get.deps.test,jar,jar,javadoc,copysource,copytest,copylib,extras"
- description="Build everything">
+ <!-- Some of this can probably be moved to common-build... -->
+ <target name="dist" depends="get.deps.core,get.deps.test,jar,jar,javadoc,copysource,copytest,copylib,extras"
+ description="Build everything">
- <ant inheritall="false" dir="${basedir}/doc/reference"/>
- <copy todir="${dist.dir}/doc/reference" failonerror="false">
- <fileset dir="${basedir}/doc/reference/build">
- <include name="**/*.*"/>
+ <ant inheritall="false" dir="${basedir}/doc/reference"/>
+ <copy todir="${dist.dir}/doc/reference" failonerror="false">
+ <fileset dir="${basedir}/doc/reference/build">
+ <include name="**/*.*"/>
<exclude name="en/master.xml"/>
- </fileset>
- </copy>
+ </fileset>
+ </copy>
- <copy todir="${dist.dir}" failonerror="false">
- <fileset dir="${common.dir}">
- <include name="common-build.xml"/>
- </fileset>
- </copy>
+ <copy todir="${dist.dir}" failonerror="false">
+ <fileset dir="${common.dir}">
+ <include name="common-build.xml"/>
+ </fileset>
+ </copy>
<copy todir="${dist.dir}/test-resources" failonerror="false">
<fileset dir="${testresources.dir}">
@@ -281,31 +326,32 @@
<!-- copy dependencies -->
<copy todir="${dist.lib.dir}" failonerror="false">
- <!-- fileset file="${jpa-api.jar}"/>
- <fileset file="${commons-annotations.jar}"/ -->
+ <!-- fileset file="${jpa-api.jar}"/>
+ <fileset file="${commons-annotations.jar}"/ -->
<fileset dir="${ivy.dep.dir}/core">
<include name="*.jar"/>
</fileset>
</copy>
<mkdir dir="${dist.lib.dir}/test"/>
<copy todir="${dist.lib.dir}/test" failonerror="false">
- <fileset dir="${ivy.dep.dir}/test">
+ <fileset dir="${ivy.dep.dir}/test">
<include name="*.jar"/>
</fileset>
</copy>
<copy todir="${dist.lib.dir}/test" failonerror="false">
- <fileset file="${lib.dir}/test/*.jar"/>
+ <fileset file="${lib.dir}/test/*.jar"/>
</copy>
<mkdir dir="${dist.lib.dir}/build"/>
<copy todir="${dist.lib.dir}/build" failonerror="false">
- <fileset file="${lib.dir}/build/*.jar"/>
+ <fileset file="${lib.dir}/build/*.jar"/>
</copy>
<!-- ivy uses the module name without hibernate- (to mimic the directory names). Revert the situation -->
<move file="${dist.lib.dir}/commons-annotations.jar" tofile="${dist.lib.dir}/hibernate-commons-annotations.jar"
failonerror="false"/>
- <move file="${dist.lib.dir}/test/commons-annotations.jar" tofile="${dist.lib.dir}/test/hibernate-commons-annotations.jar"
+ <move file="${dist.lib.dir}/test/commons-annotations.jar"
+ tofile="${dist.lib.dir}/test/hibernate-commons-annotations.jar"
failonerror="false"/>
<move file="${dist.lib.dir}/test/annotations.jar" tofile="${dist.lib.dir}/test/hibernate-annotations.jar"
failonerror="false"/>
@@ -314,16 +360,16 @@
<copy file="${basedir}/build.properties.dist" tofile="${dist.dir}/build.properties" failonerror="false">
- </copy>
- <antcall target="common-build.dist"/>
- </target>
+ </copy>
+ <antcall target="common-build.dist"/>
+ </target>
<target name="zip-dist" description="zip the dist">
- <zip zipfile="${dist.dir}-${version}.zip">
- <zipfileset prefix="${name}-${version}" dir="${dist.dir}"/>
- </zip>
- <tar compression="gzip" tarfile="${dist.dir}-${version}.tar.gz">
- <tarfileset prefix="${name}-${version}" dir="${dist.dir}"/>
- </tar>
- </target>
+ <zip zipfile="${dist.dir}-${version}.zip">
+ <zipfileset prefix="${name}-${version}" dir="${dist.dir}"/>
+ </zip>
+ <tar compression="gzip" tarfile="${dist.dir}-${version}.tar.gz">
+ <tarfileset prefix="${name}-${version}" dir="${dist.dir}"/>
+ </tar>
+ </target>
</project>
Modified: search/trunk/common-build.xml
===================================================================
--- search/trunk/common-build.xml 2008-11-07 16:06:17 UTC (rev 15532)
+++ search/trunk/common-build.xml 2008-11-07 19:58:13 UTC (rev 15533)
@@ -99,7 +99,6 @@
<path id="lib.class.path">
<path refid="lib.moduleclass.path"/>
- <pathelement path="${clover.jar}"/>
</path>
<!-- overridable in modules -->
@@ -137,15 +136,7 @@
<path id="testsrc.path">
<pathelement location="${test.dir}"/>
</path>
-
- <path id="junit.classpath">
- <pathelement path="${classes.dir}"/>
- <pathelement path="${testclasses.dir}"/>
- <path refid="lib.class.path"/>
- <path refid="junit.moduleclasspath"/>
- <path location="${clover.jar}"/>
- </path>
-
+
<!-- Determine the database against which to run tests-->
<if>
<equals arg1="${targetdb}" arg2="$${targetdb}"/>
@@ -155,30 +146,11 @@
</then>
</if>
- <!-- Clover tasks -->
- <target name="with.clover">
- <clover-setup initString="clover_coverage.db"/>
- </target>
-
- <target name="cloverreport.html" depends="with.clover"
- description="Generate a clover report from the current clover database.">
- <clover-report>
- <current outfile="${clover.out.dir}">
- <format type="html"/>
- </current>
- </clover-report>
- </target>
-
- <target name="cloverreport"
- depends="with.clover,junitreport,cloverreport.html"
- description="Run the tests and generate a clover report">
- </target>
-
+
<!-- Tasks -->
<target name="clean" description="Cleans up build and dist directories">
<delete dir="${build.dir}"/>
<delete dir="${dist.target.dir}"/>
- <delete dir="${clover.out.dir}"/>
</target>
<target name="init" description="Initialize the build">
Modified: search/trunk/src/test/org/hibernate/search/test/HANTestCase.java
===================================================================
--- search/trunk/src/test/org/hibernate/search/test/HANTestCase.java 2008-11-07 16:06:17 UTC (rev 15532)
+++ search/trunk/src/test/org/hibernate/search/test/HANTestCase.java 2008-11-07 19:58:13 UTC (rev 15533)
@@ -3,27 +3,18 @@
import java.io.InputStream;
-import org.hibernate.SessionFactory;
-import org.hibernate.Session;
-import org.hibernate.HibernateException;
-import org.hibernate.Interceptor;
-import org.hibernate.dialect.Dialect;
import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.cfg.Environment;
-import org.hibernate.cfg.Configuration;
+import org.hibernate.dialect.Dialect;
/**
- * copy from HAN
+ * Originally a copy from Hibernate Annotations.
+ *
* @author Emmanuel Bernard
+ * @author Hardy Ferentschik
*/
-public abstract class HANTestCase extends junit.framework.TestCase {
+public abstract class HANTestCase extends TestCase {
- private static SessionFactory sessions;
- private static AnnotationConfiguration cfg;
- private static Dialect dialect;
- private static Class lastTestClass;
- private Session session;
-
public HANTestCase() {
super();
}
@@ -33,28 +24,29 @@
}
protected void buildSessionFactory(Class[] classes, String[] packages, String[] xmlFiles) throws Exception {
-
- if ( getSessions() != null ) getSessions().close();
+ if ( getSessions() != null ) {
+ getSessions().close();
+ }
try {
setCfg( new AnnotationConfiguration() );
configure( cfg );
if ( recreateSchema() ) {
cfg.setProperty( Environment.HBM2DDL_AUTO, "create-drop" );
}
- for ( int i = 0; i < packages.length; i++ ) {
- getCfg().addPackage( packages[i] );
+ for ( String aPackage : packages ) {
+ ( ( AnnotationConfiguration ) getCfg() ).addPackage( aPackage );
}
- for ( int i = 0; i < classes.length; i++ ) {
- getCfg().addAnnotatedClass( classes[i] );
+ for ( Class aClass : classes ) {
+ ( ( AnnotationConfiguration ) getCfg() ).addAnnotatedClass( aClass );
}
- for ( int i = 0; i < xmlFiles.length; i++ ) {
- InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream( xmlFiles[i] );
+ for ( String xmlFile : xmlFiles ) {
+ InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream( xmlFile );
getCfg().addInputStream( is );
}
setDialect( Dialect.getDialect() );
setSessions( getCfg().buildSessionFactory( /*new TestInterceptor()*/ ) );
}
- catch (Exception e) {
+ catch ( Exception e ) {
e.printStackTrace();
throw e;
}
@@ -67,92 +59,9 @@
}
}
- protected void runTest() throws Throwable {
- try {
- super.runTest();
- if ( session != null && session.isOpen() ) {
- if ( session.isConnected() ) session.connection().rollback();
- session.close();
- session = null;
- fail( "unclosed session" );
- }
- else {
- session = null;
- }
- }
- catch (Throwable e) {
- try {
- if ( session != null && session.isOpen() ) {
- if ( session.isConnected() ) session.connection().rollback();
- session.close();
- }
- }
- catch (Exception ignore) {
- }
- try {
- if ( sessions != null ) {
- sessions.close();
- sessions = null;
- }
- }
- catch (Exception ignore) {
- }
- throw e;
- }
- }
-
- public Session openSession() throws HibernateException {
- session = getSessions().openSession();
- return session;
- }
-
- public Session openSession(Interceptor interceptor) throws HibernateException {
- session = getSessions().openSession( interceptor );
- return session;
- }
-
protected abstract Class[] getMappings();
protected String[] getAnnotatedPackages() {
- return new String[]{};
+ return new String[] { };
}
-
- protected String[] getXmlFiles() {
- return new String[]{};
- }
-
- private void setSessions(SessionFactory sessions) {
- HANTestCase.sessions = sessions;
- }
-
- protected SessionFactory getSessions() {
- return sessions;
- }
-
- private void setDialect(Dialect dialect) {
- HANTestCase.dialect = dialect;
- }
-
- protected Dialect getDialect() {
- return dialect;
- }
-
- protected static void setCfg(AnnotationConfiguration cfg) {
- HANTestCase.cfg = cfg;
- }
-
- protected static AnnotationConfiguration getCfg() {
- return cfg;
- }
-
- protected void configure(Configuration cfg) {
- //cfg.setNamingStrategy( AlternativeNamingStrategy.INSTANCE );
- //cfg.getSessionEventListenerConfig().setFlushEventListener( new EJB3FlushEventListener() );
- //cfg.getSessionEventListenerConfig().setAutoFlushEventListener( new EJB3AutoFlushEventListener() );
- }
-
- protected boolean recreateSchema() {
- return true;
- }
-
}
Added: search/trunk/src/test/org/hibernate/search/test/TestCase.java
===================================================================
--- search/trunk/src/test/org/hibernate/search/test/TestCase.java (rev 0)
+++ search/trunk/src/test/org/hibernate/search/test/TestCase.java 2008-11-07 19:58:13 UTC (rev 15533)
@@ -0,0 +1,157 @@
+//$Id: HANTestCase.java 14687 2008-05-22 18:21:01Z epbernard $
+package org.hibernate.search.test;
+
+import java.io.InputStream;
+
+import org.apache.lucene.analysis.StopAnalyzer;
+
+import org.hibernate.HibernateException;
+import org.hibernate.Interceptor;
+import org.hibernate.Session;
+import org.hibernate.SessionFactory;
+import org.hibernate.search.store.RAMDirectoryProvider;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+import org.hibernate.dialect.Dialect;
+
+/**
+ * A modified base class for tests without annotations.
+ *
+ * @author Hardy Ferentschik
+ */
+public abstract class TestCase extends junit.framework.TestCase {
+
+ protected static SessionFactory sessions;
+ protected static Configuration cfg;
+ protected static Dialect dialect;
+ protected static Class lastTestClass;
+ protected Session session;
+
+ public TestCase() {
+ super();
+ }
+
+ public TestCase(String x) {
+ super( x );
+ }
+
+ protected void buildSessionFactory(String[] xmlFiles) throws Exception {
+
+ if ( getSessions() != null ) {
+ getSessions().close();
+ }
+ try {
+ setCfg( new Configuration() );
+ configure( cfg );
+ if ( recreateSchema() ) {
+ cfg.setProperty( Environment.HBM2DDL_AUTO, "create-drop" );
+ }
+ for ( String xmlFile : xmlFiles ) {
+ InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream( xmlFile );
+ getCfg().addInputStream( is );
+ }
+ setDialect( Dialect.getDialect() );
+ setSessions( getCfg().buildSessionFactory() );
+ }
+ catch ( Exception e ) {
+ e.printStackTrace();
+ throw e;
+ }
+ }
+
+ protected void setUp() throws Exception {
+ if ( getSessions() == null || getSessions().isClosed() || lastTestClass != getClass() ) {
+ buildSessionFactory( getXmlFiles() );
+ lastTestClass = getClass();
+ }
+ }
+
+ protected void runTest() throws Throwable {
+ try {
+ super.runTest();
+ if ( session != null && session.isOpen() ) {
+ if ( session.isConnected() ) {
+ session.connection().rollback();
+ }
+ session.close();
+ session = null;
+ fail( "unclosed session" );
+ }
+ else {
+ session = null;
+ }
+ }
+ catch ( Throwable e ) {
+ try {
+ if ( session != null && session.isOpen() ) {
+ if ( session.isConnected() ) {
+ session.connection().rollback();
+ }
+ session.close();
+ }
+ }
+ catch ( Exception ignore ) {
+ }
+ try {
+ if ( sessions != null ) {
+ sessions.close();
+ sessions = null;
+ }
+ }
+ catch ( Exception ignore ) {
+ }
+ throw e;
+ }
+ }
+
+ public Session openSession() throws HibernateException {
+ session = getSessions().openSession();
+ return session;
+ }
+
+ public Session openSession(Interceptor interceptor) throws HibernateException {
+ session = getSessions().openSession( interceptor );
+ return session;
+ }
+
+ protected String[] getXmlFiles() {
+ return new String[] { };
+ }
+
+ protected void setSessions(SessionFactory sessions) {
+ TestCase.sessions = sessions;
+ }
+
+ protected SessionFactory getSessions() {
+ return sessions;
+ }
+
+ protected void setDialect(Dialect dialect) {
+ TestCase.dialect = dialect;
+ }
+
+ protected Dialect getDialect() {
+ return dialect;
+ }
+
+ protected static void setCfg(Configuration cfg) {
+ TestCase.cfg = cfg;
+ }
+
+ protected static Configuration getCfg() {
+ return cfg;
+ }
+
+ protected void configure(Configuration cfg) {
+ cfg.setListener( "post-update", "org.hibernate.search.event.FullTextIndexEventListener" );
+ cfg.setListener( "post-insert", "org.hibernate.search.event.FullTextIndexEventListener" );
+ cfg.setListener( "post-delete", "org.hibernate.search.event.FullTextIndexEventListener" );
+
+ cfg.setProperty( "hibernate.search.default.directory_provider", RAMDirectoryProvider.class.getName() );
+ cfg.setProperty( org.hibernate.search.Environment.ANALYZER_CLASS, StopAnalyzer.class.getName() );
+ }
+
+ protected boolean recreateSchema() {
+ return true;
+ }
+}
\ No newline at end of file
Added: search/trunk/src/test/org/hibernate/search/test/classloading/Animal.hbm.xml
===================================================================
--- search/trunk/src/test/org/hibernate/search/test/classloading/Animal.hbm.xml (rev 0)
+++ search/trunk/src/test/org/hibernate/search/test/classloading/Animal.hbm.xml 2008-11-07 19:58:13 UTC (rev 15533)
@@ -0,0 +1,13 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+ "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+ "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="org.hibernate.search.test.classloading">
+ <class name="Animal">
+ <id name="id" type="java.lang.Long">
+ <generator class="increment"/>
+ </id>
+ <property name="name"/>
+ </class>
+</hibernate-mapping>
\ No newline at end of file
Added: search/trunk/src/test/org/hibernate/search/test/classloading/Animal.java
===================================================================
--- search/trunk/src/test/org/hibernate/search/test/classloading/Animal.java (rev 0)
+++ search/trunk/src/test/org/hibernate/search/test/classloading/Animal.java 2008-11-07 19:58:13 UTC (rev 15533)
@@ -0,0 +1,54 @@
+// $Id:$
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2008, Red Hat Middleware LLC, and individual contributors
+* by the @authors tag. See the copyright.txt in the distribution for a
+* full listing of individual contributors.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+* http://www.apache.org/licenses/LICENSE-2.0
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package org.hibernate.search.test.classloading;
+
+import org.hibernate.search.annotations.Field;
+import org.hibernate.search.annotations.Index;
+import org.hibernate.search.annotations.Indexed;
+import org.hibernate.search.annotations.DocumentId;
+
+/**
+ * Test class which is configured via XML and does not depend on Hibernate Annotations.
+ *
+ * @author Hardy Ferentschik
+ */
+@Indexed(index = "Animal")
+public class Animal {
+ @DocumentId
+ private Long id;
+
+ @Field(index = Index.TOKENIZED)
+ private String name;
+
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+}
\ No newline at end of file
Added: search/trunk/src/test/org/hibernate/search/test/classloading/NoAnnotationsTest.java
===================================================================
--- search/trunk/src/test/org/hibernate/search/test/classloading/NoAnnotationsTest.java (rev 0)
+++ search/trunk/src/test/org/hibernate/search/test/classloading/NoAnnotationsTest.java 2008-11-07 19:58:13 UTC (rev 15533)
@@ -0,0 +1,48 @@
+// $Id: NoAnnotationsTest.java 15532 2008-11-07 16:06:17Z hardy.ferentschik $
+package org.hibernate.search.test.classloading;
+
+import java.util.List;
+
+import org.apache.lucene.index.Term;
+import org.apache.lucene.search.TermQuery;
+
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.search.Search;
+
+
+/**
+ * @author Hardy Ferentschik
+ */
+public class NoAnnotationsTest extends org.hibernate.search.test.TestCase {
+
+ /**
+ * Tests that @DocumentId is optional. See HSEARCH-104.
+ *
+ * @throws Exception in case the test fails.
+ */
+ public void testConfigurationWithoutAnnotations() throws Exception {
+ Animal dog = new Animal();
+ dog.setName( "Dog" );
+
+ Session s = openSession();
+ Transaction tx = s.beginTransaction();
+ s.save( dog );
+ tx.commit();
+ s.clear();
+
+ tx = s.beginTransaction();
+ List results = Search.getFullTextSession( s ).createFullTextQuery(
+ new TermQuery( new Term( "name", "dog" ) )
+ ).list();
+ assertEquals( 1, results.size() );
+ tx.commit();
+ s.close();
+ }
+
+ protected String[] getXmlFiles() {
+ return new String[] {
+ "org/hibernate/search/test/classloading/Animal.hbm.xml"
+ };
+ }
+}
\ No newline at end of file
16 years, 2 months
Hibernate SVN: r15532 - in search/trunk/src: java/org/hibernate/search/impl and 1 other directories.
by hibernate-commits@lists.jboss.org
Author: hardy.ferentschik
Date: 2008-11-07 11:06:17 -0500 (Fri, 07 Nov 2008)
New Revision: 15532
Added:
search/trunk/src/test/org/hibernate/search/test/id/Animal.java
search/trunk/src/test/org/hibernate/search/test/id/ImplicitIdTest.java
Modified:
search/trunk/src/java/org/hibernate/search/engine/DocumentBuilder.java
search/trunk/src/java/org/hibernate/search/impl/InitContext.java
Log:
HSEARCH-104
Use @Id when no @DocumentId is specified.
Modified: search/trunk/src/java/org/hibernate/search/engine/DocumentBuilder.java
===================================================================
--- search/trunk/src/java/org/hibernate/search/engine/DocumentBuilder.java 2008-11-07 11:58:00 UTC (rev 15531)
+++ search/trunk/src/java/org/hibernate/search/engine/DocumentBuilder.java 2008-11-07 16:06:17 UTC (rev 15532)
@@ -3,6 +3,8 @@
import java.io.Serializable;
import java.lang.reflect.Modifier;
+import java.lang.reflect.Method;
+import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -75,6 +77,11 @@
private final DirectoryProvider[] directoryProviders;
private final IndexShardingStrategy shardingStrategy;
private String idKeywordName;
+
+ /**
+ * Flag indicating whether <code>@DocumentId</code> was explicitly specified.
+ */
+ private boolean explicitDocumentId = false;
private XMember idGetter;
private Float idBoost;
public static final String CLASS_FIELDNAME = "_hibernate_class";
@@ -91,13 +98,8 @@
private boolean idProvided = false;
private EntityState entityState;
-
- public boolean isRoot() {
- return isRoot;
- }
-
/**
- * used on an @Indexed entity
+ * Constructor used on an @Indexed entity.
*/
public DocumentBuilder(XClass clazz, InitContext context, DirectoryProvider[] directoryProviders,
IndexShardingStrategy shardingStrategy, ReflectionManager reflectionManager) {
@@ -135,7 +137,7 @@
}
/**
- * used on a non @Indexed entity
+ * Constructor used on a non @Indexed entity.
*/
public DocumentBuilder(XClass clazz, InitContext context, ReflectionManager reflectionManager) {
this.entityState = EntityState.CONTAINED_IN_ONLY;
@@ -153,6 +155,10 @@
}
}
+ public boolean isRoot() {
+ return isRoot;
+ }
+
private ProvidedId findProvidedId(XClass clazz, ReflectionManager reflectionManager) {
ProvidedId id = null;
XClass currentClass = clazz;
@@ -214,7 +220,7 @@
if ( analyzer != null ) {
propertiesMetadata.analyzer = analyzer;
}
- getAnalyzerDefs( currClass, context );
+ checkForAnalyzerDefs( currClass, context );
// Check for any ClassBridges annotation.
ClassBridges classBridgesAnn = currClass.getAnnotation( ClassBridges.class );
if ( classBridgesAnn != null ) {
@@ -265,7 +271,7 @@
}
}
- private void getAnalyzerDefs(XAnnotatedElement annotatedElement, InitContext context) {
+ private void checkForAnalyzerDefs(XAnnotatedElement annotatedElement, InitContext context) {
AnalyzerDefs defs = annotatedElement.getAnnotation( AnalyzerDefs.class );
if ( defs != null ) {
for (AnalyzerDef def : defs.value()) {
@@ -287,62 +293,41 @@
private void initializeMember(XProperty member, PropertiesMetadata propertiesMetadata, boolean isRoot,
String prefix, Set<XClass> processedClasses, InitContext context) {
- DocumentId documentIdAnn = member.getAnnotation( DocumentId.class );
- if ( documentIdAnn != null ) {
- if ( isRoot ) {
- if ( idKeywordName != null ) {
- throw new AssertionFailure( "Two document id assigned: "
- + idKeywordName + " and " + BinderHelper.getAttributeName( member, documentIdAnn.name() ) );
- }
- idKeywordName = prefix + BinderHelper.getAttributeName( member, documentIdAnn.name() );
- FieldBridge fieldBridge = BridgeFactory.guessType( null, member, reflectionManager );
- if ( fieldBridge instanceof TwoWayFieldBridge ) {
- idBridge = (TwoWayFieldBridge) fieldBridge;
- }
- else {
- throw new SearchException(
- "Bridge for document id does not implement TwoWayFieldBridge: " + member.getName() );
- }
- idBoost = getBoost( member, null );
- setAccessible( member );
- idGetter = member;
- }
- else {
- //component should index their document id
- setAccessible( member );
- propertiesMetadata.fieldGetters.add( member );
- String fieldName = prefix + BinderHelper.getAttributeName( member, documentIdAnn.name() );
- propertiesMetadata.fieldNames.add( fieldName );
- propertiesMetadata.fieldStore.add( getStore( Store.YES ) );
- propertiesMetadata.fieldIndex.add( getIndex( Index.UN_TOKENIZED ) );
- propertiesMetadata.fieldTermVectors.add( getTermVector( TermVector.NO ) );
- propertiesMetadata.fieldBridges.add( BridgeFactory.guessType( null, member, reflectionManager ) );
- propertiesMetadata.fieldBoosts.add( getBoost( member, null ) );
- // property > entity analyzer (no field analyzer)
- Analyzer analyzer = getAnalyzer( member, context );
- if ( analyzer == null ) analyzer = propertiesMetadata.analyzer;
- if ( analyzer == null ) throw new AssertionFailure( "Analizer should not be undefined" );
- this.analyzer.addScopedAnalyzer( fieldName, analyzer );
- }
- }
- {
- org.hibernate.search.annotations.Field fieldAnn =
- member.getAnnotation( org.hibernate.search.annotations.Field.class );
- if ( fieldAnn != null ) {
+ checkDocumentId( member, propertiesMetadata, isRoot, prefix, context );
+ checkForField( member, propertiesMetadata, prefix, context );
+ checkForFields( member, propertiesMetadata, prefix, context );
+ checkForAnalyzerDefs( member, context );
+ checkForIndexedEmbedded( member, propertiesMetadata, prefix, processedClasses, context );
+ checkForConstraintIn( member, propertiesMetadata );
+ }
+
+ private void checkForFields(XProperty member, PropertiesMetadata propertiesMetadata, String prefix, InitContext context) {
+ org.hibernate.search.annotations.Fields fieldsAnn =
+ member.getAnnotation( org.hibernate.search.annotations.Fields.class );
+ if ( fieldsAnn != null ) {
+ for (org.hibernate.search.annotations.Field fieldAnn : fieldsAnn.value()) {
bindFieldAnnotation( member, propertiesMetadata, prefix, fieldAnn, context );
}
}
- {
- org.hibernate.search.annotations.Fields fieldsAnn =
- member.getAnnotation( org.hibernate.search.annotations.Fields.class );
- if ( fieldsAnn != null ) {
- for (org.hibernate.search.annotations.Field fieldAnn : fieldsAnn.value()) {
- bindFieldAnnotation( member, propertiesMetadata, prefix, fieldAnn, context );
- }
- }
+ }
+
+ private void checkForField(XProperty member, PropertiesMetadata propertiesMetadata, String prefix, InitContext context) {
+ org.hibernate.search.annotations.Field fieldAnn =
+ member.getAnnotation( org.hibernate.search.annotations.Field.class );
+ if ( fieldAnn != null ) {
+ bindFieldAnnotation( member, propertiesMetadata, prefix, fieldAnn, context );
}
- getAnalyzerDefs( member, context );
+ }
+ private void checkForConstraintIn(XProperty member, PropertiesMetadata propertiesMetadata) {
+ ContainedIn containedAnn = member.getAnnotation( ContainedIn.class );
+ if ( containedAnn != null ) {
+ setAccessible( member );
+ propertiesMetadata.containedInGetters.add( member );
+ }
+ }
+
+ private void checkForIndexedEmbedded(XProperty member, PropertiesMetadata propertiesMetadata, String prefix, Set<XClass> processedClasses, InitContext context) {
IndexedEmbedded embeddedAnn = member.getAnnotation( IndexedEmbedded.class );
if ( embeddedAnn != null ) {
int oldMaxLevel = maxLevel;
@@ -411,14 +396,103 @@
level--;
maxLevel = oldMaxLevel; //set back the the old max level
}
+ }
- ContainedIn containedAnn = member.getAnnotation( ContainedIn.class );
- if ( containedAnn != null ) {
- setAccessible( member );
- propertiesMetadata.containedInGetters.add( member );
+ private void checkDocumentId(XProperty member, PropertiesMetadata propertiesMetadata, boolean isRoot, String prefix, InitContext context) {
+ Annotation idAnnotation = getIdAnnotation( member, context );
+ if ( idAnnotation != null ) {
+ String attributeName = getIdAttributeName( member, idAnnotation );
+ if ( isRoot ) {
+ if ( idKeywordName != null && explicitDocumentId ) {
+ throw new AssertionFailure( "Two document id assigned: "
+ + idKeywordName + " and " + attributeName );
+ }
+ idKeywordName = prefix + attributeName;
+ FieldBridge fieldBridge = BridgeFactory.guessType( null, member, reflectionManager );
+ if ( fieldBridge instanceof TwoWayFieldBridge ) {
+ idBridge = (TwoWayFieldBridge) fieldBridge;
+ }
+ else {
+ throw new SearchException(
+ "Bridge for document id does not implement TwoWayFieldBridge: " + member.getName() );
+ }
+ idBoost = getBoost( member, null );
+ setAccessible( member );
+ idGetter = member;
+ }
+ else {
+ //component should index their document id
+ setAccessible( member );
+ propertiesMetadata.fieldGetters.add( member );
+ String fieldName = prefix + attributeName;
+ propertiesMetadata.fieldNames.add( fieldName );
+ propertiesMetadata.fieldStore.add( getStore( Store.YES ) );
+ propertiesMetadata.fieldIndex.add( getIndex( Index.UN_TOKENIZED ) );
+ propertiesMetadata.fieldTermVectors.add( getTermVector( TermVector.NO ) );
+ propertiesMetadata.fieldBridges.add( BridgeFactory.guessType( null, member, reflectionManager ) );
+ propertiesMetadata.fieldBoosts.add( getBoost( member, null ) );
+ // property > entity analyzer (no field analyzer)
+ Analyzer analyzer = getAnalyzer( member, context );
+ if ( analyzer == null ) analyzer = propertiesMetadata.analyzer;
+ if ( analyzer == null ) throw new AssertionFailure( "Analizer should not be undefined" );
+ this.analyzer.addScopedAnalyzer( fieldName, analyzer );
+ }
}
}
+ /**
+ * Checks whether the specified property contains an annotation used as document id.
+ * This can either be an explicit <code>@DocumentId</code> or if no <code>@DocumentId</code> is specified a
+ * JPA <code>@Id</code> annotation. The check for the JPA annotation is indirectly to avoid a hard dependency
+ * to Hibernate Annotations.
+ *
+ * @param member the property to check for the id annotation.
+ * @return the annotation used as document id or <code>null</code> if id annotation is specified on the property.
+ */
+ private Annotation getIdAnnotation(XProperty member, InitContext context) {
+ // check for explicit DocumentId
+ Annotation documentIdAnn = member.getAnnotation( DocumentId.class );
+ if ( documentIdAnn != null ) {
+ explicitDocumentId = true;
+ return documentIdAnn;
+ }
+
+ // check for JPA @Id
+ if ( !explicitDocumentId && context.isJpaPresent() ) {
+ Class idClass;
+ try {
+ idClass = org.hibernate.util.ReflectHelper.classForName( "javax.persistence.Id", InitContext.class );
+ } catch ( ClassNotFoundException e ) {
+ throw new SearchException( "Unable to load @Id.class even though it should be present ?!" );
+ }
+ documentIdAnn = member.getAnnotation( idClass );
+ if ( documentIdAnn != null )
+ log.debug( "Found JPA id and using it as document id" );
+ }
+ return documentIdAnn;
+ }
+
+ /**
+ * Determines the property name for the document id. It is either the name of the property itself or the
+ * value of the name attribute of the <code>idAnnotation</code>.
+ *
+ * @param member the property used as id property.
+ * @param idAnnotation the id annotation
+ * @return property name to be used as document id.
+ */
+ private String getIdAttributeName(XProperty member, Annotation idAnnotation) {
+ String name = null;
+ try {
+ Method m = idAnnotation.getClass().getMethod( "name" );
+ name = (String) m.invoke( idAnnotation );
+ }
+ catch ( Exception e ) {
+ // ignore
+ }
+
+ return BinderHelper.getAttributeName( member, name );
+ }
+
private void bindClassAnnotation(String prefix, PropertiesMetadata propertiesMetadata, ClassBridge ann, InitContext context) {
//FIXME name should be prefixed
String fieldName = prefix + ann.name();
Modified: search/trunk/src/java/org/hibernate/search/impl/InitContext.java
===================================================================
--- search/trunk/src/java/org/hibernate/search/impl/InitContext.java 2008-11-07 11:58:00 UTC (rev 15531)
+++ search/trunk/src/java/org/hibernate/search/impl/InitContext.java 2008-11-07 16:06:17 UTC (rev 15532)
@@ -19,7 +19,12 @@
import org.hibernate.util.ReflectHelper;
/**
+ * Provides access to some default configuration settings (eg default <code>Analyzer</code> or default
+ * <code>Similarity</code>) and checks whether certain optional libraries are available.
+ *
+ *
* @author Emmanuel Bernard
+ * @author Hardy Ferentschik
*/
public class InitContext {
private final Map<String, AnalyzerDef> analyzerDefs = new HashMap<String, AnalyzerDef>();
@@ -27,11 +32,13 @@
private final Analyzer defaultAnalyzer;
private final Similarity defaultSimilarity;
private final boolean solrPresent;
+ private final boolean jpaPresent;
public InitContext(SearchConfiguration cfg) {
defaultAnalyzer = initAnalyzer(cfg);
defaultSimilarity = initSimilarity(cfg);
solrPresent = isPresent( "org.apache.solr.analysis.TokenizerFactory" );
+ jpaPresent = isPresent( "javax.persistence.Id" );
}
public void addAnalyzerDef(AnalyzerDef ann) {
@@ -68,8 +75,6 @@
analyzerClass = ReflectHelper.classForName(analyzerClassName);
} catch (Exception e) {
return buildLazyAnalyzer( analyzerClassName );
-// throw new SearchException("Lucene analyzer class '" + analyzerClassName + "' defined in property '"
-// + Environment.ANALYZER_CLASS + "' could not be found.", e);
}
} else {
analyzerClass = StandardAnalyzer.class;
@@ -88,7 +93,10 @@
}
/**
- * Initializes the Lucene similarity to use
+ * Initializes the Lucene similarity to use.
+ *
+ * @param cfg the search configuration.
+ * @return returns the default similarity class.
*/
private Similarity initSimilarity(SearchConfiguration cfg) {
Class similarityClass;
@@ -165,8 +173,8 @@
if ( ! solrPresent ) {
throw new SearchException( "Use of @AnalyzerDef while Solr is not present in the classpath. Add apache-solr-analyzer.jar" );
}
- //SolrAnalyzerBuilder references Solr classes.
- //InitContext should not (directly or indirectly) load a Solr class to avoid hard dependency
+ // SolrAnalyzerBuilder references Solr classes.
+ // InitContext should not (directly or indirectly) load a Solr class to avoid hard dependency
// unless necessary
// the curent mecanism (check sor class presence and call SolrAnalyzerBuilder if needed
// seems to be sufficient on Apple VM (derived from Sun's
@@ -174,6 +182,10 @@
return SolrAnalyzerBuilder.buildAnalyzer( analyzerDef );
}
+ public boolean isJpaPresent() {
+ return jpaPresent;
+ }
+
private boolean isPresent(String classname) {
try {
ReflectHelper.classForName( classname, InitContext.class );
Property changes on: search/trunk/src/java/org/hibernate/search/impl/InitContext.java
___________________________________________________________________
Name: svn:keywords
+ Id
Added: search/trunk/src/test/org/hibernate/search/test/id/Animal.java
===================================================================
--- search/trunk/src/test/org/hibernate/search/test/id/Animal.java (rev 0)
+++ search/trunk/src/test/org/hibernate/search/test/id/Animal.java 2008-11-07 16:06:17 UTC (rev 15532)
@@ -0,0 +1,56 @@
+// $Id:$
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2008, Red Hat Middleware LLC, and individual contributors
+* by the @authors tag. See the copyright.txt in the distribution for a
+* full listing of individual contributors.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+* http://www.apache.org/licenses/LICENSE-2.0
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package org.hibernate.search.test.id;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.GeneratedValue;
+
+import org.hibernate.search.annotations.Field;
+import org.hibernate.search.annotations.Index;
+import org.hibernate.search.annotations.Indexed;
+
+/**
+ * @author Hardy Ferentschik
+ */
+@Entity
+@Indexed(index = "Animal")
+public class Animal {
+ @Id @GeneratedValue
+ private Integer id;
+
+ @Field(index = Index.TOKENIZED)
+ private String name;
+
+
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+}
Copied: search/trunk/src/test/org/hibernate/search/test/id/ImplicitIdTest.java (from rev 15529, search/trunk/src/test/org/hibernate/search/test/id/EmbeddedIdTest.java)
===================================================================
--- search/trunk/src/test/org/hibernate/search/test/id/ImplicitIdTest.java (rev 0)
+++ search/trunk/src/test/org/hibernate/search/test/id/ImplicitIdTest.java 2008-11-07 16:06:17 UTC (rev 15532)
@@ -0,0 +1,48 @@
+// $Id$
+package org.hibernate.search.test.id;
+
+import java.util.List;
+
+import org.apache.lucene.index.Term;
+import org.apache.lucene.search.TermQuery;
+
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.search.Search;
+import org.hibernate.search.test.SearchTestCase;
+
+/**
+ * @author Hardy Ferentschik
+ */
+public class ImplicitIdTest extends SearchTestCase {
+
+ /**
+ * Tests that @DocumentId is optional. See HSEARCH-104.
+ *
+ * @throws Exception in case the test fails.
+ */
+ public void testImplicitDocumentId() throws Exception {
+ Animal dog = new Animal();
+ dog.setName( "Dog" );
+
+ Session s = openSession();
+ Transaction tx = s.beginTransaction();
+ s.save( dog );
+ tx.commit();
+ s.clear();
+
+ tx = s.beginTransaction();
+ List results = Search.getFullTextSession( s ).createFullTextQuery(
+ new TermQuery( new Term( "name", "dog" ) )
+ ).list();
+ assertEquals( 1, results.size() );
+ tx.commit();
+ s.close();
+ }
+
+ protected Class[] getMappings() {
+ return new Class[] {
+ Animal.class
+ };
+ }
+}
\ No newline at end of file
Property changes on: search/trunk/src/test/org/hibernate/search/test/id/ImplicitIdTest.java
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:mergeinfo
+
16 years, 2 months
Hibernate SVN: r15531 - search/trunk/src/test/org/hibernate/search/test/worker/duplication.
by hibernate-commits@lists.jboss.org
Author: hardy.ferentschik
Date: 2008-11-07 06:58:00 -0500 (Fri, 07 Nov 2008)
New Revision: 15531
Modified:
search/trunk/src/test/org/hibernate/search/test/worker/duplication/WorkDuplicationTest.java
Log:
HSEARCH-293 - added test case
Modified: search/trunk/src/test/org/hibernate/search/test/worker/duplication/WorkDuplicationTest.java
===================================================================
--- search/trunk/src/test/org/hibernate/search/test/worker/duplication/WorkDuplicationTest.java 2008-11-07 10:32:33 UTC (rev 15530)
+++ search/trunk/src/test/org/hibernate/search/test/worker/duplication/WorkDuplicationTest.java 2008-11-07 11:58:00 UTC (rev 15531)
@@ -2,6 +2,7 @@
package org.hibernate.search.test.worker.duplication;
import java.util.List;
+import java.util.ArrayList;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.index.IndexReader;
@@ -13,6 +14,13 @@
import org.hibernate.Transaction;
import org.hibernate.search.FullTextQuery;
import org.hibernate.search.FullTextSession;
+import org.hibernate.search.SearchFactory;
+import org.hibernate.search.backend.WorkType;
+import org.hibernate.search.backend.LuceneWork;
+import org.hibernate.search.backend.AddLuceneWork;
+import org.hibernate.search.backend.DeleteLuceneWork;
+import org.hibernate.search.engine.DocumentBuilder;
+import org.hibernate.search.impl.SearchFactoryImpl;
import org.hibernate.search.reader.ReaderProvider;
import org.hibernate.search.store.DirectoryProvider;
import org.hibernate.search.test.SearchTestCase;
@@ -86,6 +94,44 @@
s.close();
}
+ /**
+ * Tests that adding and deleting the same entity only results into a single delete in the work queue.
+ * See HSEARCH-293.
+ *
+ * @throws Exception in case the test fails.
+ */
+ @SuppressWarnings( "unchecked" )
+ public void testAddWorkGetReplacedByDeleteWork() throws Exception {
+ FullTextSession fullTextSession = org.hibernate.search.Search.getFullTextSession( openSession() );
+ SearchFactoryImpl searchFactory = ( SearchFactoryImpl ) fullTextSession.getSearchFactory();
+ DocumentBuilder builder = searchFactory.getDocumentBuilder( SpecialPerson.class );
+
+ // create test entity
+ SpecialPerson person = new SpecialPerson();
+ person.setName( "Joe Smith" );
+
+ EmailAddress emailAddress = new EmailAddress();
+ emailAddress.setAddress( "foo(a)foobar.com" );
+ emailAddress.setDefaultAddress(true);
+
+ person.addEmailAddress( emailAddress );
+
+ List<LuceneWork> queue = new ArrayList<LuceneWork>();
+
+ builder.addWorkToQueue( SpecialPerson.class, person, 1, WorkType.ADD, queue, searchFactory );
+
+ assertEquals("There should only be one job in the queue", 1, queue.size());
+ assertTrue("Wrong job type", queue.get(0) instanceof AddLuceneWork );
+
+ builder.addWorkToQueue( SpecialPerson.class, person, 1, WorkType.DELETE, queue, searchFactory );
+
+ assertEquals("There should only be one job in the queue", 1, queue.size());
+ assertTrue("Wrong job type. Add job should have been replaced by delete.", queue.get(0) instanceof DeleteLuceneWork );
+
+ fullTextSession.close();
+ }
+
+
protected Class[] getMappings() {
return new Class[] { Person.class, EmailAddress.class, SpecialPerson.class };
}
16 years, 2 months
Hibernate SVN: r15530 - search/trunk/src/java/org/hibernate/search/reader.
by hibernate-commits@lists.jboss.org
Author: hardy.ferentschik
Date: 2008-11-07 05:32:33 -0500 (Fri, 07 Nov 2008)
New Revision: 15530
Modified:
search/trunk/src/java/org/hibernate/search/reader/SharedReaderProvider.java
Log:
HSEARCH-250 added a comment that HSEARCH-250 won't be fixed in deprecated class for now
Modified: search/trunk/src/java/org/hibernate/search/reader/SharedReaderProvider.java
===================================================================
--- search/trunk/src/java/org/hibernate/search/reader/SharedReaderProvider.java 2008-11-06 23:21:06 UTC (rev 15529)
+++ search/trunk/src/java/org/hibernate/search/reader/SharedReaderProvider.java 2008-11-07 10:32:33 UTC (rev 15530)
@@ -25,8 +25,10 @@
/**
* Share readers per <code>SearchFactory</code>, reusing them if they are still valid.
*
- * @Deprecated replaced by SharingBufferReaderProvider
+ * @deprecated replaced by SharingBufferReaderProvider
* @author Emmanuel Bernard
+ * @todo This class contains several bugs including HSEARCH-250. Since it is deprecated we are not going to
+ * fix them right now.
*/
@Deprecated
public class SharedReaderProvider implements ReaderProvider {
16 years, 2 months
Hibernate SVN: r15529 - in core/branches/Branch_3_2/test/org/hibernate: junit/functional and 1 other directories.
by hibernate-commits@lists.jboss.org
Author: gbadner
Date: 2008-11-06 18:21:06 -0500 (Thu, 06 Nov 2008)
New Revision: 15529
Modified:
core/branches/Branch_3_2/test/org/hibernate/junit/UnitTestCase.java
core/branches/Branch_3_2/test/org/hibernate/junit/functional/DatabaseSpecificFunctionalTestCase.java
core/branches/Branch_3_2/test/org/hibernate/test/cascade/BidirectionalOneToManyCascadeTest.java
Log:
Tweak FailureExpected validation to not throw FailureExpectedTestPassedException when a test is skipped
Modified: core/branches/Branch_3_2/test/org/hibernate/junit/UnitTestCase.java
===================================================================
--- core/branches/Branch_3_2/test/org/hibernate/junit/UnitTestCase.java 2008-11-06 23:11:06 UTC (rev 15528)
+++ core/branches/Branch_3_2/test/org/hibernate/junit/UnitTestCase.java 2008-11-06 23:21:06 UTC (rev 15529)
@@ -32,7 +32,7 @@
try {
log.info( "Starting test [" + fullTestName() + "]" );
super.runBare();
- if ( doValidate ) {
+ if ( !isTestSkipped() && doValidate ) {
throw new FailureExpectedTestPassedException();
}
}
@@ -58,6 +58,18 @@
}
}
+ /**
+ * Is this test skipped?
+ *
+ * TODO: This method should no longer be needed FunctionalTestClassTestSuite.addTest() is
+ * changed to only include non-skipped tests.
+ *
+ * @return true, if the test is skipped; false, otherwise.
+ */
+ protected boolean isTestSkipped() {
+ return false;
+ }
+
protected void skipExpectedFailure(Throwable error) {
reportSkip( "ignoring *FailuredExpected methods", "Failed with: " + error.toString() );
}
Modified: core/branches/Branch_3_2/test/org/hibernate/junit/functional/DatabaseSpecificFunctionalTestCase.java
===================================================================
--- core/branches/Branch_3_2/test/org/hibernate/junit/functional/DatabaseSpecificFunctionalTestCase.java 2008-11-06 23:11:06 UTC (rev 15528)
+++ core/branches/Branch_3_2/test/org/hibernate/junit/functional/DatabaseSpecificFunctionalTestCase.java 2008-11-06 23:21:06 UTC (rev 15529)
@@ -8,10 +8,15 @@
* @author Steve Ebersole
*/
public abstract class DatabaseSpecificFunctionalTestCase extends FunctionalTestCase {
+
public DatabaseSpecificFunctionalTestCase(String string) {
super( string );
}
+ protected boolean isTestSkipped() {
+ return ! appliesTo( getDialect() );
+ }
+
protected void runTest() throws Throwable {
// Note: this protection comes into play when running
// tests individually. The suite as a whole is already
Modified: core/branches/Branch_3_2/test/org/hibernate/test/cascade/BidirectionalOneToManyCascadeTest.java
===================================================================
--- core/branches/Branch_3_2/test/org/hibernate/test/cascade/BidirectionalOneToManyCascadeTest.java 2008-11-06 23:11:06 UTC (rev 15528)
+++ core/branches/Branch_3_2/test/org/hibernate/test/cascade/BidirectionalOneToManyCascadeTest.java 2008-11-06 23:21:06 UTC (rev 15529)
@@ -8,8 +8,11 @@
import org.hibernate.Session;
import org.hibernate.Transaction;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.id.SequenceGenerator;
import org.hibernate.junit.functional.FunctionalTestCase;
import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.junit.functional.DatabaseSpecificFunctionalTestCase;
/**
* @author Gail Badner (based on annotations test case submitted by Edward Costello)
@@ -20,7 +23,7 @@
* one-to-many collection and the many-to-one side is also cascaded a
* TransientObjectException is thrown.
*/
-public class BidirectionalOneToManyCascadeTest extends FunctionalTestCase {
+public class BidirectionalOneToManyCascadeTest extends DatabaseSpecificFunctionalTestCase {
public BidirectionalOneToManyCascadeTest(String name) {
super( name );
@@ -34,6 +37,15 @@
};
}
+ public boolean appliesTo(Dialect dialect) {
+ if ( "testSaveOrphanDeleteChildWithParentFailureExpected".equals( getName() ) &&
+ sfi().getEntityPersister( "org.hibernate.test.cascade.Child" ).getIdentifierGenerator() instanceof SequenceGenerator ) {
+ reportSkip( "test is known to pass with ID generated by SequenceGenerator", "skip FailureExpected test");
+ return false;
+ }
+ return true;
+ }
+
public static Test suite() {
return new FunctionalTestClassTestSuite( BidirectionalOneToManyCascadeTest.class );
}
@@ -119,9 +131,36 @@
* uses cascade="all-delete-orphan" and the many-to-one association uses
* cascade="all"
* <p/>
- * This test is known to fail. See HHH-2269.
+ * Until HHH-2269 is fixed, the Child ID generator has to be a sequence to pass.
*/
+ public void testSaveOrphanDeleteChildWithParent() {
+ // TODO: remove the following check when HHH-2269 is fixed.
+ if ( ! ( sfi().getEntityPersister( "org.hibernate.test.cascade.Child" ).getIdentifierGenerator() instanceof SequenceGenerator ) ) {
+ return;
+ }
+ saveOrphanDeleteChildWithParent();
+ }
+
+ /**
+ * Saves the child object with the parent when the one-to-many association
+ * uses cascade="all-delete-orphan" and the many-to-one association uses
+ * cascade="all"
+ * <p/>
+ * This test is known to fail when the Child ID generator is not a sequence.
+ * See HHH-2269.
+ * <p/>
+ * TODO: When HHH-2269 is fixed, this test should be deleted and
+ * the check for the Child ID generator in testSaveOrphanDeleteChildWithParent()
+ * should be removed.
+ */
public void testSaveOrphanDeleteChildWithParentFailureExpected() {
+ if ( sfi().getEntityPersister( "org.hibernate.test.cascade.Child" ).getIdentifierGenerator() instanceof SequenceGenerator ) {
+ return;
+ }
+ saveOrphanDeleteChildWithParent();
+ }
+
+ private void saveOrphanDeleteChildWithParent() {
Session session = openSession();
Transaction txn = session.beginTransaction();
Parent parent = new Parent();
16 years, 2 months
Hibernate SVN: r15528 - in search/trunk: src/java/org/hibernate/search/bridge and 1 other directory.
by hibernate-commits@lists.jboss.org
Author: sannegrinovero
Date: 2008-11-06 18:11:06 -0500 (Thu, 06 Nov 2008)
New Revision: 15528
Modified:
search/trunk/doc/reference/en/modules/mapping.xml
search/trunk/src/java/org/hibernate/search/bridge/FieldBridge.java
search/trunk/src/java/org/hibernate/search/bridge/ParameterizedBridge.java
search/trunk/src/java/org/hibernate/search/bridge/StringBridge.java
search/trunk/src/java/org/hibernate/search/bridge/TwoWayStringBridge.java
Log:
HSEARCH-291 improve documentation about thread safety requirements of Bridges
Modified: search/trunk/doc/reference/en/modules/mapping.xml
===================================================================
--- search/trunk/doc/reference/en/modules/mapping.xml 2008-11-06 16:44:55 UTC (rev 15527)
+++ search/trunk/doc/reference/en/modules/mapping.xml 2008-11-06 23:11:06 UTC (rev 15528)
@@ -988,11 +988,13 @@
<section>
<title>StringBridge</title>
- <para>The simpliest custom solution is to give Hibernate Search an
+ <para>The simplest custom solution is to give Hibernate Search an
implementation of your expected <emphasis>object to String</emphasis>
bridge. To do so you need to implements the
<literal>org.hibernate.search.bridge.StringBridge</literal>
- interface</para>
+ interface.</para>
+ <para>All implementations have to be thread-safe as they
+ are used concurrently.</para>
<programlisting>/**
* Padding Integer bridge.
@@ -1063,6 +1065,9 @@
<classname>TwoWayStringBridge</classname> ,
<classname>FieldBridge</classname> implementations (see
bellow).</para>
+ <para>All implementations have to be thread-safe, but the parameters
+ are set during initialization and no special care is required at
+ this stage.</para>
<para>If you expect to use your bridge implementation on for an id
property (ie annotated with <literal>@DocumentId</literal> ), you need
@@ -1178,7 +1183,7 @@
<para>It is sometimes useful to combine more than one property of a
given entity and index this combination in a specific way into the
Lucene index. The <classname>@ClassBridge</classname> and
- <classname>@ClassBridges</classname> annotations can be defined at the
+ <classname>@ClassBridge</classname> annotations can be defined at the
class level (as opposed to the property level). In this case the
custom field bridge implementation receives the entity instance as the
value parameter instead of a particular property. Though not shown in
Modified: search/trunk/src/java/org/hibernate/search/bridge/FieldBridge.java
===================================================================
--- search/trunk/src/java/org/hibernate/search/bridge/FieldBridge.java 2008-11-06 16:44:55 UTC (rev 15527)
+++ search/trunk/src/java/org/hibernate/search/bridge/FieldBridge.java 2008-11-06 23:11:06 UTC (rev 15528)
@@ -5,7 +5,9 @@
/**
* Link between a java property and a Lucene Document
- * Usually a Java property will be linked to a Document Field
+ * Usually a Java property will be linked to a Document Field.
+ *
+ * All implementations need to be threadsafe.
*
* @author Emmanuel Bernard
*/
Modified: search/trunk/src/java/org/hibernate/search/bridge/ParameterizedBridge.java
===================================================================
--- search/trunk/src/java/org/hibernate/search/bridge/ParameterizedBridge.java 2008-11-06 16:44:55 UTC (rev 15527)
+++ search/trunk/src/java/org/hibernate/search/bridge/ParameterizedBridge.java 2008-11-06 23:11:06 UTC (rev 15528)
@@ -4,7 +4,11 @@
import java.util.Map;
/**
- * Allow parameter injection to a given bridge
+ * Allow parameter injection to a given bridge.
+ *
+ * Implementors need to be threadsafe, but the
+ * setParameterValues method doesn't need any
+ * guard as initialization is always safe.
*
* @author Emmanuel Bernard
*/
Modified: search/trunk/src/java/org/hibernate/search/bridge/StringBridge.java
===================================================================
--- search/trunk/src/java/org/hibernate/search/bridge/StringBridge.java 2008-11-06 16:44:55 UTC (rev 15527)
+++ search/trunk/src/java/org/hibernate/search/bridge/StringBridge.java 2008-11-06 23:11:06 UTC (rev 15528)
@@ -2,7 +2,12 @@
package org.hibernate.search.bridge;
/**
- * Transform an object into a string representation
+ * Transform an object into a string representation.
+ *
+ * All implementations are required to be threadsafe;
+ * usually this is easily achieved avoiding the usage
+ * of class fields, unless they are either immutable
+ * or needed to store parameters.
*
* @author Emmanuel Bernard
*/
Modified: search/trunk/src/java/org/hibernate/search/bridge/TwoWayStringBridge.java
===================================================================
--- search/trunk/src/java/org/hibernate/search/bridge/TwoWayStringBridge.java 2008-11-06 16:44:55 UTC (rev 15527)
+++ search/trunk/src/java/org/hibernate/search/bridge/TwoWayStringBridge.java 2008-11-06 23:11:06 UTC (rev 15528)
@@ -8,6 +8,9 @@
*
* objectToString( stringToObject( string ) ).equals(string) for string not null
* stringToObject( objectToString( object ) ).equals(object) for object not null
+ *
+ * As for all Bridges implementors must be threasafe.
+ *
* @author Emmanuel Bernard
*/
public interface TwoWayStringBridge extends StringBridge {
16 years, 2 months