/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2011, Red Hat, Inc. and/or its affiliates or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat, Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.search.query.dsl.impl;
import java.util.Date;
import java.util.List;
import org.hibernate.search.SearchException;
import org.hibernate.search.engine.spi.DocumentBuilderIndexedEntity;
import org.hibernate.search.engine.spi.EntityIndexBinder;
import org.hibernate.search.engine.spi.SearchFactoryImplementor;
import org.hibernate.search.query.facet.FacetSortOrder;
import org.hibernate.search.query.facet.FacetingRequest;
import static org.hibernate.search.util.impl.CollectionHelper.newArrayList;
/**
* @author Hardy Ferentschik
*/
class FacetBuildingContext<T> {
/**
* The list of types which are supported for range faceting
*/
private static final List<Class<?>> allowedRangeTypes = newArrayList();
static {
allowedRangeTypes.add( String.class );
allowedRangeTypes.add( Integer.class );
allowedRangeTypes.add( Long.class );
allowedRangeTypes.add( Double.class );
allowedRangeTypes.add( Float.class );
allowedRangeTypes.add( Date.class );
}
private final SearchFactoryImplementor factory;
private final Class<?> entityType;
private String name;
private String fieldName;
private FacetSortOrder sort = FacetSortOrder.COUNT_DESC;
private boolean includeZeroCount = true;
private boolean isRangeQuery = false;
private List<FacetRange<T>> rangeList = newArrayList();
private T rangeStart;
private boolean includeRangeStart = true;
private T rangeEnd;
private boolean includeRangeEnd = true;
private int maxFacetCount = -1;
private DocumentBuilderIndexedEntity<?> documentBuilder;
public FacetBuildingContext(SearchFactoryImplementor factory, Class<?> entityType) {
this.factory = factory;
this.entityType = entityType;
}
void setName(String name) {
this.name = name;
}
void setFieldName(String fieldName) {
this.fieldName = fieldName;
assertFacetingFieldExists();
}
void setSort(FacetSortOrder sort) {
this.sort = sort;
}
void setIncludeZeroCount(boolean includeZeroCount) {
this.includeZeroCount = includeZeroCount;
}
public void setRangeQuery(boolean rangeQuery) {
isRangeQuery = rangeQuery;
}
public void setRangeStart(T rangeStart) {
this.rangeStart = rangeStart;
}
public void setIncludeRangeStart(boolean includeRangeStart) {
this.includeRangeStart = includeRangeStart;
}
public void setRangeEnd(T rangeEnd) {
this.rangeEnd = rangeEnd;
}
public void setIncludeRangeEnd(boolean includeRangeEnd) {
this.includeRangeEnd = includeRangeEnd;
}
public void setMaxFacetCount(int maxFacetCount) {
this.maxFacetCount = maxFacetCount;
}
public void makeRange() {
Class<?> type = getRangeType();
assertValidRangeType( type );
FacetRange<T> facetRange = new FacetRange<T>(
type,
rangeStart,
rangeEnd,
includeRangeStart,
includeRangeEnd,
fieldName,
documentBuilder
);
rangeList.add( facetRange );
rangeStart = null;
rangeEnd = null;
includeRangeStart = true;
includeRangeEnd = true;
}
private void assertValidRangeType(Class<?> clazz) {
if ( !allowedRangeTypes.contains( clazz ) ) {
throw new SearchException( "Unsupported range type: " + clazz.getName() );
}
}
private Class<?> getRangeType() {
if ( rangeStart == null && rangeEnd == null ) {
throw new SearchException( "You have to at least specify a start or end of the range" );
}
T tmp = rangeStart;
if ( tmp == null ) {
tmp = rangeEnd;
}
return tmp.getClass();
}
FacetingRequest getFacetingRequest() {
FacetingRequestImpl request;
if ( isRangeQuery ) {
request = new RangeFacetRequest<T>( name, fieldName, rangeList, documentBuilder );
}
else {
if ( FacetSortOrder.RANGE_DEFINITION_ODER.equals( sort ) ) {
throw new SearchException(
"RANGE_DEFINITION_ODER is not a valid sort order for a discrete faceting request."
);
}
request = new DiscreteFacetRequest( name, fieldName );
}
request.setSort( sort );
request.setIncludeZeroCounts( includeZeroCount );
request.setMaxNumberOfFacets( maxFacetCount );
return request;
}
private void assertFacetingFieldExists() {
if ( fieldName == null ) {
throw new IllegalArgumentException( "null is an invalid field name" );
}
EntityIndexBinder indexBinding = factory.getIndexBindingForEntity( entityType );
if ( indexBinding == null ) {
throw new SearchException(
"Entity " + entityType.getName()
+ " is not an indexed entity. Unable to create faceting request"
);
}
documentBuilder = indexBinding.getDocumentBuilder();
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder();
sb.append( "FacetBuildingContext" );
sb.append( "{name='" ).append( name ).append( '\'' );
sb.append( ", fieldName='" ).append( fieldName ).append( '\'' );
sb.append( ", sort=" ).append( sort );
sb.append( ", includeZeroCount=" ).append( includeZeroCount );
sb.append( ", isRangeQuery=" ).append( isRangeQuery );
sb.append( ", rangeList=" ).append( rangeList );
sb.append( ", rangeStart=" ).append( rangeStart );
sb.append( ", includeRangeStart=" ).append( includeRangeStart );
sb.append( ", rangeEnd=" ).append( rangeEnd );
sb.append( ", includeRangeEnd=" ).append( includeRangeEnd );
sb.append( '}' );
return sb.toString();
}
}