Skip to content

Commit

Permalink
HSEARCH-1161 Throw a more specific exception type on searching on mea…
Browse files Browse the repository at this point in the history
…ningless input
  • Loading branch information
Sanne committed Jun 20, 2012
1 parent 898234a commit e4a62f8
Show file tree
Hide file tree
Showing 5 changed files with 156 additions and 2 deletions.
@@ -0,0 +1,53 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* JBoss, Home of Professional Open Source
* Copyright 2012 Red Hat Inc. and/or its affiliates and other contributors
* as indicated by the @authors tag. All rights reserved.
* See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License, v. 2.1.
* This program is distributed in the hope that it will be useful, but WITHOUT A
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General Public License,
* v.2.1 along with this distribution; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/
package org.hibernate.search.errors;

import org.hibernate.search.SearchException;


/**
* This Exception is thrown when an empty TermQuery (keyword query) is created,
* or if any string query only returns whitespace after applying Analyzers.
*
* Applications should validate user input before running such a Query;
*
* @see org.hibernate.search.util.AnalyzerUtils
* @author Sanne Grinovero <sanne@hibernate.org> (C) 2012 Red Hat Inc.
*/
public class EmptyQueryException extends SearchException {

public EmptyQueryException() {
super();
}

public EmptyQueryException(String message) {
super( message );
}

public EmptyQueryException(String message, Throwable cause) {
super( message, cause );
}

public EmptyQueryException(Throwable cause) {
super( cause );
}

}
Expand Up @@ -46,11 +46,16 @@
import org.hibernate.search.bridge.util.impl.NumericFieldUtils;
import org.hibernate.search.engine.spi.DocumentBuilderIndexedEntity;
import org.hibernate.search.query.dsl.TermTermination;
import org.hibernate.search.util.logging.impl.Log;
import org.hibernate.search.util.logging.impl.LoggerFactory;

/**
* @author Emmanuel Bernard
*/
public class ConnectedMultiFieldsTermQueryBuilder implements TermTermination {

private static final Log log = LoggerFactory.make();

private final Object value;
private final QueryCustomizer queryCustomizer;
private final TermQueryContext termContext;
Expand Down Expand Up @@ -103,7 +108,7 @@ private Query createQuery(FieldContext fieldContext, ConversionContext conversio
);

if ( terms.size() == 0 ) {
throw new SearchException( "Try to search with an empty string: " + fieldContext.getField() );
throw log.queryWithNoTermsAfterAnalysis( fieldContext.getField(), searchTerm );
}
else if ( terms.size() == 1 ) {
perFieldQuery = createTermQuery( fieldContext, terms.get( 0 ) );
Expand Down
Expand Up @@ -37,6 +37,7 @@
import org.hibernate.search.SearchException;
import org.hibernate.search.backend.impl.jgroups.JGroupsChannelProvider;
import org.hibernate.search.backend.spi.WorkType;
import org.hibernate.search.errors.EmptyQueryException;

import static org.jboss.logging.Logger.Level.ERROR;
import static org.jboss.logging.Logger.Level.INFO;
Expand Down Expand Up @@ -551,9 +552,14 @@ public interface Log extends BasicLogger {
"not as an IndexManager property for index '%1$s'. See http://docs.jboss.org/hibernate/search/4.1/reference/en-US/html_single/#jgroups-backend")
SearchException legacyJGroupsConfigurationDefined(String indexName);

@Message(id = 131, value = "The query string '%2$s' applied on field '%1$s' has no meaningfull tokens to be matched. Validate the query input " +
"against the Analyzer applied on this field.")
EmptyQueryException queryWithNoTermsAfterAnalysis(String field, String searchTerm);

@Message(id = 132, value = "Configured JGroups channel is a Muxer! MuxId option is required: define '" + JGroupsChannelProvider.MUX_ID + "'.")
SearchException missingJGroupsMuxId();

@Message(id = 133, value = "MuxId '%1$d' configured on the JGroups was already taken. Can't register handler!")
SearchException jGroupsMuxIdAlreadyTaken(short n);

}
@@ -0,0 +1,81 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* JBoss, Home of Professional Open Source
* Copyright 2012 Red Hat Inc. and/or its affiliates and other contributors
* as indicated by the @authors tag. All rights reserved.
* See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License, v. 2.1.
* This program is distributed in the hope that it will be useful, but WITHOUT A
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General Public License,
* v.2.1 along with this distribution; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/
package org.hibernate.search.test.dsl;

import org.hibernate.search.annotations.DocumentId;
import org.hibernate.search.annotations.Field;
import org.hibernate.search.annotations.Indexed;
import org.hibernate.search.backend.spi.Work;
import org.hibernate.search.backend.spi.WorkType;
import org.hibernate.search.engine.spi.SearchFactoryImplementor;
import org.hibernate.search.errors.EmptyQueryException;
import org.hibernate.search.query.dsl.QueryBuilder;
import org.hibernate.search.test.programmaticmapping.TestingSearchFactoryHolder;
import org.hibernate.search.test.util.ManualTransactionContext;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;


/**
* Verifies an EmptyQueryException is thrown when appropriate.
*
* @author Sanne Grinovero <sanne@hibernate.org> (C) 2012 Red Hat Inc.
*/
public class EmptyQueryExceptionTest {

@Rule
public TestingSearchFactoryHolder sfHolder = new TestingSearchFactoryHolder( Book.class );

@Rule
public ExpectedException exceptions = ExpectedException.none();

@Test
public void verifyExceptionOnNonMeaningfullQueries() {
final SearchFactoryImplementor searchFactory = sfHolder.getSearchFactory();

Book book = new Book();
book.title = "Empty Book";
book.text = "The question is, does an empty book have 'space' tokens in it?";

Work work = new Work( book, book.title, WorkType.ADD, false );
ManualTransactionContext tc = new ManualTransactionContext();
searchFactory.getWorker().performWork( work, tc );
tc.end();

QueryBuilder queryBuilder = searchFactory.buildQueryBuilder().forEntity( Book.class ).get();

exceptions.expect( EmptyQueryException.class );

queryBuilder.keyword().onField( "text" ).matching( " " ).createQuery();
// Hence the answer is: a program won't be able to tell you.
}

@Indexed
static class Book {
@DocumentId
String title;

@Field
String text;
}

}
Expand Up @@ -36,9 +36,15 @@ public class TestingSearchFactoryHolder extends ExternalResource {

private final SearchMapping buildMappingDefinition;
private SearchFactoryImplementor sf;
private final Class<?>[] entities;

public TestingSearchFactoryHolder(SearchMapping buildMappingDefinition) {
public TestingSearchFactoryHolder(Class<?>... entities) {
this( null, entities );
}

public TestingSearchFactoryHolder(SearchMapping buildMappingDefinition, Class<?>... entities) {
this.buildMappingDefinition = buildMappingDefinition;
this.entities = entities;
}

public SearchFactoryImplementor getSearchFactory() {
Expand All @@ -50,6 +56,9 @@ protected void before() throws Throwable {
ManualConfiguration cfg = new ManualConfiguration();
cfg.setProgrammaticMapping( buildMappingDefinition );
cfg.addProperty( "hibernate.search.default.directory_provider", "ram" );
for ( Class<?> c : entities ) {
cfg.addClass( c );
}
sf = new SearchFactoryBuilder().configuration( cfg ).buildSearchFactory();
}

Expand Down

0 comments on commit e4a62f8

Please sign in to comment.