Skip to content

Commit

Permalink
HSEARCH-2521 Throw a specific error when trying to build a query on a…
Browse files Browse the repository at this point in the history
… type that is not even configured
  • Loading branch information
yrodiere authored and Sanne committed Mar 14, 2017
1 parent b755fc4 commit 5ab13cd
Show file tree
Hide file tree
Showing 9 changed files with 119 additions and 48 deletions.
Expand Up @@ -67,7 +67,7 @@
import org.hibernate.search.spi.SearchIntegrator;
import org.hibernate.search.spi.WorkerBuildContext;
import org.hibernate.search.spi.impl.ExtendedSearchIntegratorWithShareableState;
import org.hibernate.search.spi.impl.PolymorphicIndexHierarchy;
import org.hibernate.search.spi.impl.TypeHierarchy;
import org.hibernate.search.spi.impl.SearchFactoryState;
import org.hibernate.search.stat.Statistics;
import org.hibernate.search.stat.impl.StatisticsImpl;
Expand Down Expand Up @@ -102,7 +102,8 @@ public class ImmutableSearchFactory implements ExtendedSearchIntegratorWithShare
private final AtomicBoolean stopped = new AtomicBoolean( false );
private final int cacheBitResultsSize;
private final Properties configurationProperties;
private final PolymorphicIndexHierarchy indexHierarchy;
private final TypeHierarchy configuredTypeHierarchy;
private final TypeHierarchy indexedTypeHierarchy;
private final StatisticsImpl statistics;
private final boolean transactionManagerExpected;
private final IndexManagerHolder allIndexesManager;
Expand Down Expand Up @@ -139,7 +140,8 @@ public ImmutableSearchFactory(SearchFactoryState state) {
this.documentBuildersContainedEntities = state.getDocumentBuildersContainedEntities();
this.filterCachingStrategy = state.getFilterCachingStrategy();
this.filterDefinitions = state.getFilterDefinitions();
this.indexHierarchy = state.getIndexHierarchy();
this.configuredTypeHierarchy = state.getConfiguredTypeHierarchy();
this.indexedTypeHierarchy = state.getIndexedTypeHierarchy();
this.indexingMode = state.getIndexingMode();
this.worker = state.getWorker();
this.serviceManager = state.getServiceManager();
Expand Down Expand Up @@ -460,9 +462,14 @@ public int getFilterCacheBitResultsSize() {
return cacheBitResultsSize;
}

@Override
public Set<Class<?>> getConfiguredTypesPolymorphic(Class<?>[] classes) {
return configuredTypeHierarchy.getConfiguredClasses( classes );
}

@Override
public Set<Class<?>> getIndexedTypesPolymorphic(Class<?>[] classes) {
return indexHierarchy.getIndexedClasses( classes );
return indexedTypeHierarchy.getConfiguredClasses( classes );
}

@Override
Expand All @@ -471,8 +478,13 @@ public BatchBackend makeBatchBackend(MassIndexerProgressMonitor progressMonitor)
}

@Override
public PolymorphicIndexHierarchy getIndexHierarchy() {
return indexHierarchy;
public TypeHierarchy getConfiguredTypeHierarchy() {
return configuredTypeHierarchy;
}

@Override
public TypeHierarchy getIndexedTypeHierarchy() {
return indexedTypeHierarchy;
}

@Override
Expand Down
Expand Up @@ -45,7 +45,7 @@
import org.hibernate.search.spi.SearchIntegratorBuilder;
import org.hibernate.search.spi.WorkerBuildContext;
import org.hibernate.search.spi.impl.ExtendedSearchIntegratorWithShareableState;
import org.hibernate.search.spi.impl.PolymorphicIndexHierarchy;
import org.hibernate.search.spi.impl.TypeHierarchy;
import org.hibernate.search.stat.Statistics;
import org.hibernate.search.stat.spi.StatisticsImplementor;

Expand Down Expand Up @@ -162,6 +162,11 @@ public int getFilterCacheBitResultsSize() {
return delegate.getFilterCacheBitResultsSize();
}

@Override
public Set<Class<?>> getConfiguredTypesPolymorphic(Class<?>[] classes) {
return delegate.getConfiguredTypesPolymorphic( classes );
}

@Override
public Set<Class<?>> getIndexedTypesPolymorphic(Class<?>[] classes) {
return delegate.getIndexedTypesPolymorphic( classes );
Expand All @@ -183,8 +188,13 @@ public StatisticsImplementor getStatisticsImplementor() {
}

@Override
public PolymorphicIndexHierarchy getIndexHierarchy() {
return delegate.getIndexHierarchy();
public TypeHierarchy getConfiguredTypeHierarchy() {
return delegate.getConfiguredTypeHierarchy();
}

@Override
public TypeHierarchy getIndexedTypeHierarchy() {
return delegate.getIndexedTypeHierarchy();
}

@Override
Expand Down
Expand Up @@ -29,7 +29,7 @@
import org.hibernate.search.spi.IndexingMode;
import org.hibernate.search.spi.InstanceInitializer;
import org.hibernate.search.spi.impl.ExtendedSearchIntegratorWithShareableState;
import org.hibernate.search.spi.impl.PolymorphicIndexHierarchy;
import org.hibernate.search.spi.impl.TypeHierarchy;
import org.hibernate.search.spi.impl.SearchFactoryState;
import org.hibernate.search.stat.Statistics;
import org.hibernate.search.util.configuration.impl.ConfigurationParseHelper;
Expand All @@ -51,7 +51,8 @@ public class MutableSearchFactoryState implements SearchFactoryState {
private Map<IndexManagerType, AnalyzerRegistry> analyzerRegistries = new ConcurrentHashMap<>();
private int cacheBitResultsSize;
private Properties configurationProperties;
private PolymorphicIndexHierarchy indexHierarchy;
private TypeHierarchy configuredTypeHierarchy;
private TypeHierarchy indexedTypeHierarchy;
private ServiceManager serviceManager;
private boolean transactionManagerExpected;
private IndexManagerHolder allIndexesManager;
Expand Down Expand Up @@ -80,7 +81,8 @@ public void copyStateFromOldFactory(SearchFactoryState oldFactoryState) {
analyzerRegistries.putAll( oldFactoryState.getAnalyzerRegistries() );
cacheBitResultsSize = oldFactoryState.getCacheBitResultsSize();
configurationProperties = oldFactoryState.getConfigurationProperties();
indexHierarchy = oldFactoryState.getIndexHierarchy();
configuredTypeHierarchy = oldFactoryState.getConfiguredTypeHierarchy();
indexedTypeHierarchy = oldFactoryState.getIndexedTypeHierarchy();
serviceManager = oldFactoryState.getServiceManager();
transactionManagerExpected = oldFactoryState.isTransactionManagerExpected();
allIndexesManager = oldFactoryState.getAllIndexesManager();
Expand Down Expand Up @@ -158,8 +160,13 @@ public Properties getConfigurationProperties() {
}

@Override
public PolymorphicIndexHierarchy getIndexHierarchy() {
return indexHierarchy;
public TypeHierarchy getConfiguredTypeHierarchy() {
return configuredTypeHierarchy;
}

@Override
public TypeHierarchy getIndexedTypeHierarchy() {
return indexedTypeHierarchy;
}

public void setDocumentBuildersContainedEntities(Map<Class<?>, DocumentBuilderContainedEntity> documentBuildersContainedEntities) {
Expand Down Expand Up @@ -205,8 +212,12 @@ public void setConfigurationProperties(Properties configurationProperties) {
);
}

public void setIndexHierarchy(PolymorphicIndexHierarchy indexHierarchy) {
this.indexHierarchy = indexHierarchy;
public void setConfiguredTypeHierarchy(TypeHierarchy configuredTypeHierarchy) {
this.configuredTypeHierarchy = configuredTypeHierarchy;
}

public void setIndexedTypeHierarchy(TypeHierarchy indexedTypeHierarchy) {
this.indexedTypeHierarchy = indexedTypeHierarchy;
}

@Override
Expand Down
Expand Up @@ -11,6 +11,7 @@
import java.util.Set;

import org.hibernate.search.analyzer.spi.ScopedAnalyzerReference;
import org.hibernate.search.cfg.spi.SearchConfiguration;
import org.hibernate.search.engine.impl.AnalyzerRegistry;
import org.hibernate.search.engine.impl.FilterDef;
import org.hibernate.search.engine.spi.DocumentBuilderContainedEntity;
Expand Down Expand Up @@ -52,17 +53,30 @@ public interface ExtendedSearchIntegrator extends SearchIntegrator {
int getFilterCacheBitResultsSize();

/**
* Given a set of target entities, return the set of indexed types following our
* polymorphism rules for propagation of the {@code Indexed} annotation:
* It returns an empty set if none of the target entities is indexed, nor any of their sub types.
* Each of the classes of the argument is returned iff explicitly marked as indexed.
* Each of the known subtypes of these classes which are explicitly marked as indexed are
* added to the returned set.
* The {@code Indexed} annotation is not inherited by subtypes which don't explicitly have it.
* Passing {@code Object.class} among the parameters will have the returned set contain all known indexed types.
* Given a set of target entities, return the set of configured subtypes.
* <p>
* "Configured" types are types that Hibernate Search was instructed to take into consideration,
* i.e. types returned by {@link SearchConfiguration#getClassMappings()}.
*
* @param classes a list of types
* @return a set containing the types as in the above rules
* @param classes an array of types
* @return the set of configured subtypes
*/
Set<Class<?>> getConfiguredTypesPolymorphic(Class<?>[] classes);

/**
* Given a set of target entities, return the set of configured subtypes that are indexed.
* <p>
* "Configured" types are types that Hibernate Search was instructed to take into consideration,
* i.e. types returned by {@link SearchConfiguration#getClassMappings()}.
* <p>
* "Indexed" types are configured types that happened to be annotated with {@code @Indexed},
* or similarly configured through a programmatic mapping.
* <p>
* Note: the fact that a given type is configured or indexed doesn't mean that its subtypes are, too.
* Each type must be configured explicitly.
*
* @param classes an array of types
* @return the set of configured subtypes that are indexed
*/
Set<Class<?>> getIndexedTypesPolymorphic(Class<?>[] classes);

Expand Down
Expand Up @@ -51,7 +51,13 @@ public HSearchEntityContext(Class<?> entityType, ExtendedSearchIntegrator factor
indexBoundType = getIndexBoundType( entityType, factory );

if ( indexBoundType == null ) {
throw log.cantQueryUnindexedType( entityType.getCanonicalName() );
Set<Class<?>> configuredSubTypes = factory.getConfiguredTypesPolymorphic( new Class<?>[] { entityType } );
if ( configuredSubTypes.isEmpty() ) {
throw log.cantQueryUnconfiguredType( entityType.getCanonicalName() );
}
else {
throw log.cantQueryUnindexedType( entityType.getCanonicalName() );
}
}

queryAnalyzerReferenceBuilder = factory.getAnalyzerReference( indexBoundType ).startCopy();
Expand Down
Expand Up @@ -67,7 +67,7 @@
import org.hibernate.search.indexes.spi.IndexManagerType;
import org.hibernate.search.indexes.spi.IndexNameNormalizer;
import org.hibernate.search.spi.impl.ExtendedSearchIntegratorWithShareableState;
import org.hibernate.search.spi.impl.PolymorphicIndexHierarchy;
import org.hibernate.search.spi.impl.TypeHierarchy;
import org.hibernate.search.spi.impl.SearchFactoryState;
import org.hibernate.search.util.StringHelper;
import org.hibernate.search.util.configuration.impl.ConfigurationParseHelper;
Expand Down Expand Up @@ -279,7 +279,8 @@ private void createCleanFactoryState(SearchConfiguration cfg, BuildContext build
rootFactory = new MutableSearchFactory();
factoryState.setDocumentBuildersIndexedEntities( new ConcurrentHashMap<Class<?>, EntityIndexBinding>() );
factoryState.setDocumentBuildersContainedEntities( new ConcurrentHashMap<Class<?>, DocumentBuilderContainedEntity>() );
factoryState.setIndexHierarchy( new PolymorphicIndexHierarchy() );
factoryState.setConfiguredTypeHierarchy( new TypeHierarchy() );
factoryState.setIndexedTypeHierarchy( new TypeHierarchy() );
factoryState.setConfigurationProperties( cfg.getProperties() );
factoryState.setServiceManager(
new StandardServiceManager(
Expand Down Expand Up @@ -310,7 +311,8 @@ private void initDocumentBuilders(SearchConfiguration searchConfiguration, Build

initProgrammaticAnalyzers( configContext, searchConfiguration.getReflectionManager() );
initProgrammaticallyDefinedFilterDef( configContext, searchConfiguration.getReflectionManager() );
final PolymorphicIndexHierarchy indexingHierarchy = factoryState.getIndexHierarchy();
final TypeHierarchy configuredTypeHierarchy = factoryState.getConfiguredTypeHierarchy();
final TypeHierarchy indexedTypeHierarchy = factoryState.getIndexedTypeHierarchy();
final Map<Class<?>, EntityIndexBinding> documentBuildersIndexedEntities = factoryState.getIndexBindings();
final Map<Class<?>, DocumentBuilderContainedEntity> documentBuildersContainedEntities = factoryState.getDocumentBuildersContainedEntities();
final Set<XClass> optimizationBlackListedTypes = new HashSet<XClass>();
Expand All @@ -335,7 +337,8 @@ private void initDocumentBuilders(SearchConfiguration searchConfiguration, Build
}

rootIndexedEntities.add( mappedXClass );
indexingHierarchy.addIndexedClass( mappedClass );
configuredTypeHierarchy.addConfiguredClass( mappedClass );
indexedTypeHierarchy.addConfiguredClass( mappedClass );
}
else if ( metadataProvider.containsSearchMetadata( mappedClass ) ) {
//FIXME DocumentBuilderIndexedEntity needs to be built by a helper method receiving Class<T> to infer T properly
Expand All @@ -356,6 +359,10 @@ else if ( metadataProvider.containsSearchMetadata( mappedClass ) ) {
if ( documentBuilder.getEntityState() != EntityState.NON_INDEXABLE ) {
documentBuildersContainedEntities.put( mappedClass, documentBuilder );
}
configuredTypeHierarchy.addConfiguredClass( mappedClass );
}
else {
configuredTypeHierarchy.addConfiguredClass( mappedClass );
}
}

Expand Down
Expand Up @@ -53,7 +53,16 @@ public interface SearchFactoryState {

Properties getConfigurationProperties();

PolymorphicIndexHierarchy getIndexHierarchy();
/**
* @return The type hierarchy for all configured types, indexed or not.
*/
TypeHierarchy getConfiguredTypeHierarchy();

/**
* @return The type hierarchy for configured types that are indexed
* (for instance because they are annotated with @Indexed)
*/
TypeHierarchy getIndexedTypeHierarchy();

ServiceManager getServiceManager();

Expand Down
Expand Up @@ -19,46 +19,45 @@
import org.hibernate.search.util.logging.impl.LoggerFactory;

/**
* Helper class which keeps track of all super classes and interfaces of the indexed entities.
* Helper class which keeps track of all super classes and interfaces of known entities.
*/
//FIXME make it immutable (builder pattern)
public class PolymorphicIndexHierarchy {
public class TypeHierarchy {
private static final Log log = LoggerFactory.make();

private Map<Class<?>, Set<Class<?>>> classToIndexedClass;
private Map<Class<?>, Set<Class<?>>> classToConfiguredClass;

public PolymorphicIndexHierarchy() {
classToIndexedClass = new HashMap<Class<?>, Set<Class<?>>>();
public TypeHierarchy() {
classToConfiguredClass = new HashMap<Class<?>, Set<Class<?>>>();
}

public void addIndexedClass(Class<?> indexedClass) {
addClass( indexedClass, indexedClass );
Class<?> superClass = indexedClass.getSuperclass();
public void addConfiguredClass(Class<?> configuredClass) {
addClass( configuredClass, configuredClass );
Class<?> superClass = configuredClass.getSuperclass();
while ( superClass != null ) {
addClass( superClass, indexedClass );
addClass( superClass, configuredClass );
superClass = superClass.getSuperclass();
}
for ( Class<?> clazz : indexedClass.getInterfaces() ) {
addClass( clazz, indexedClass );
for ( Class<?> clazz : configuredClass.getInterfaces() ) {
addClass( clazz, configuredClass );
}
}

private void addClass(Class<?> superclass, Class<?> indexedClass) {
Set<Class<?>> classesSet = classToIndexedClass.get( superclass );
Set<Class<?>> classesSet = classToConfiguredClass.get( superclass );
if ( classesSet == null ) {
classesSet = new HashSet<Class<?>>();
classToIndexedClass.put( superclass, classesSet );
classToConfiguredClass.put( superclass, classesSet );
}
classesSet.add( indexedClass );
}

public Set<Class<?>> getIndexedClasses(Class<?>[] classes) {
public Set<Class<?>> getConfiguredClasses(Class<?>[] classes) {
if ( classes == null ) {
return Collections.<Class<?>>emptySet();
}
Set<Class<?>> indexedClasses = new HashSet<Class<?>>();
for ( Class<?> clazz : classes ) {
Set<Class<?>> set = classToIndexedClass.get( clazz );
Set<Class<?>> set = classToConfiguredClass.get( clazz );
if ( set != null ) {
// at this point we don't have to care about including indexed subclasses of a indexed class
// MultiClassesQueryLoader will take care of this later and optimise the queries
Expand Down
Expand Up @@ -1013,4 +1013,7 @@ public interface Log extends BasicLogger {

@Message(id = 330, value = "Multiple analyzer definitions with the same name: '%1$s'." )
SearchException analyzerDefinitionNamingConflict(String analyzerDefinitionName);

@Message(id = 331, value = "Can't build query for type '%1$s' which is neither configured nor has any configured sub-types.")
SearchException cantQueryUnconfiguredType(String canonicalEntityName);
}

0 comments on commit 5ab13cd

Please sign in to comment.