Skip to content

Commit

Permalink
HSEARCH-2067 Expose IndexManager type to BridgeFactory
Browse files Browse the repository at this point in the history
Heavily based on Gunnar's feedback
  • Loading branch information
gsmet authored and Sanne committed Apr 22, 2016
1 parent 78e3897 commit 8051606
Show file tree
Hide file tree
Showing 18 changed files with 208 additions and 64 deletions.
Expand Up @@ -35,6 +35,7 @@
import org.hibernate.search.engine.service.classloading.spi.ClassLoaderService;
import org.hibernate.search.engine.service.spi.ServiceManager;
import org.hibernate.search.exception.AssertionFailure;
import org.hibernate.search.indexes.spi.IndexManager;
import org.hibernate.search.util.impl.ReflectionHelper;
import org.hibernate.search.util.logging.impl.Log;
import org.hibernate.search.util.logging.impl.LoggerFactory;
Expand Down Expand Up @@ -177,19 +178,28 @@ public FieldBridge buildSpatialBridge(Spatial spatial, XClass clazz, String lati
public FieldBridge buildFieldBridge(XMember member,
boolean isId,
boolean isExplicitlyMarkedAsNumeric,
Class<? extends IndexManager> indexManagerType,
ReflectionManager reflectionManager,
ServiceManager serviceManager
) {
return buildFieldBridge( null, member, isId, isExplicitlyMarkedAsNumeric, reflectionManager, serviceManager );
return buildFieldBridge( null, member, isId, isExplicitlyMarkedAsNumeric, indexManagerType,
reflectionManager, serviceManager );
}

public FieldBridge buildFieldBridge(Field field,
XMember member,
boolean isId,
boolean isExplicitlyMarkedAsNumeric,
Class<? extends IndexManager> indexManagerType,
ReflectionManager reflectionManager,
ServiceManager serviceManager
) {
// if we don't know to which IndexManager the entity is rattached, we cannot build the right
// FieldBridge as it might depend on this information due to backend specific BridgeProviders.
if ( indexManagerType == null ) {
throw LOG.indexManagerTypeRequiredToBuildFieldBridge( member.getType().getName(), member.getName() );
}

FieldBridge bridge = findExplicitFieldBridge( field, member, reflectionManager );
if ( bridge != null ) {
return bridge;
Expand Down
Expand Up @@ -84,6 +84,7 @@
import org.hibernate.search.engine.impl.nullencoding.NumericNullEncodersHelper;
import org.hibernate.search.exception.AssertionFailure;
import org.hibernate.search.exception.SearchException;
import org.hibernate.search.indexes.spi.IndexManager;
import org.hibernate.search.metadata.NumericFieldSettingsDescriptor.NumericEncodingType;
import org.hibernate.search.spatial.Coordinates;
import org.hibernate.search.spatial.SpatialFieldBridge;
Expand Down Expand Up @@ -139,18 +140,35 @@ private Class<? extends Annotation> loadAnnotationClass(String className, Config
}

@Override
public TypeMetadata getTypeMetadataFor(Class<?> clazz) {
public TypeMetadata getTypeMetadataForContainedIn(Class<?> clazz) {
XClass xClass = reflectionManager.toXClass( clazz );
TypeMetadata.Builder typeMetadataBuilder = new TypeMetadata.Builder( clazz, configContext )
.boost( getBoost( xClass ) )
.boostStrategy( AnnotationProcessingHelper.getDynamicBoost( xClass ) )
.analyzer( configContext.getDefaultAnalyzer() );

ParseContext parseContext = new ParseContext();
parseContext.processingClass( xClass );
parseContext.setCurrentClass( xClass );

inizializePackageLevelAnnotations( packageInfo( clazz ), configContext );
return doGetTypeMetadataFor( clazz, xClass, parseContext );
}

@Override
public TypeMetadata getTypeMetadataFor(Class<?> clazz, Class<? extends IndexManager> indexManagerType) {
XClass xClass = reflectionManager.toXClass( clazz );

ParseContext parseContext = new ParseContext();
parseContext.setIndexManagerType( indexManagerType );
parseContext.processingClass( xClass );
parseContext.setCurrentClass( xClass );

return doGetTypeMetadataFor( clazz, xClass, parseContext );
}

private TypeMetadata doGetTypeMetadataFor(Class<?> clazz, XClass xClass, ParseContext parseContext) {
TypeMetadata.Builder typeMetadataBuilder = new TypeMetadata.Builder( clazz, configContext )
.boost( getBoost( xClass ) )
.boostStrategy( AnnotationProcessingHelper.getDynamicBoost( xClass ) )
.analyzer( configContext.getDefaultAnalyzer() );

initializePackageLevelAnnotations( packageInfo( clazz ), configContext );

initializeClass(
typeMetadataBuilder,
Expand Down Expand Up @@ -220,7 +238,7 @@ private void checkDocumentId(XProperty member,
}
else {
if ( parseContext.includeEmbeddedObjectId() || pathsContext.containsPath( path ) ) {
createPropertyMetadataForEmbeddedId( member, typeMetadataBuilder, propertyMetadataBuilder, numericFields, configContext, unprefixedAttributeName, path );
createPropertyMetadataForEmbeddedId( member, typeMetadataBuilder, propertyMetadataBuilder, numericFields, configContext, parseContext, unprefixedAttributeName, path );
}
}

Expand All @@ -229,17 +247,24 @@ private void checkDocumentId(XProperty member,
}
}

private void createPropertyMetadataForEmbeddedId(XProperty member, TypeMetadata.Builder typeMetadataBuilder, PropertyMetadata.Builder propertyMetadataBuilder, NumericFieldsConfiguration numericFields, ConfigContext configContext, String unprefixedFieldName, String fieldName) {
private void createPropertyMetadataForEmbeddedId(XProperty member, TypeMetadata.Builder typeMetadataBuilder, PropertyMetadata.Builder propertyMetadataBuilder, NumericFieldsConfiguration numericFields, ConfigContext configContext, ParseContext parseContext, String unprefixedFieldName, String fieldName) {
Field.Index index = AnnotationProcessingHelper.getIndex( Index.YES, Analyze.NO, Norms.YES );
Field.TermVector termVector = AnnotationProcessingHelper.getTermVector( TermVector.NO );

FieldBridge fieldBridge = bridgeFactory.buildFieldBridge(
member,
true,
numericFields.isNumericField( unprefixedFieldName ),
reflectionManager,
configContext.getServiceManager()
);
FieldBridge fieldBridge;
if ( parseContext.skipFieldBridges() ) {
fieldBridge = null;
}
else {
fieldBridge = bridgeFactory.buildFieldBridge(
member,
true,
numericFields.isNumericField( unprefixedFieldName ),
parseContext.getIndexManagerType(),
reflectionManager,
configContext.getServiceManager()
);
}

DocumentFieldMetadata fieldMetadata =
new DocumentFieldMetadata.Builder( fieldName, Store.YES, index, termVector )
Expand Down Expand Up @@ -293,17 +318,24 @@ private void createIdPropertyMetadata(XProperty member,
numericFieldAnnotation = null;
}

FieldBridge idBridge = bridgeFactory.buildFieldBridge(
member,
true,
numericFieldAnnotation != null,
reflectionManager,
configContext.getServiceManager()
);
if ( !( idBridge instanceof TwoWayFieldBridge ) ) {
throw new SearchException(
"Bridge for document id does not implement TwoWayFieldBridge: " + member.getName()
FieldBridge idBridge;
if ( parseContext.skipFieldBridges() ) {
idBridge = null;
}
else {
idBridge = bridgeFactory.buildFieldBridge(
member,
true,
numericFieldAnnotation != null,
parseContext.getIndexManagerType(),
reflectionManager,
configContext.getServiceManager()
);
if ( !( idBridge instanceof TwoWayFieldBridge ) ) {
throw new SearchException(
"Bridge for document id does not implement TwoWayFieldBridge: " + member.getName()
);
}
}

Field.TermVector termVector = AnnotationProcessingHelper.getTermVector( TermVector.NO );
Expand Down Expand Up @@ -534,7 +566,7 @@ private void initializeClass(TypeMetadata.Builder typeMetadataBuilder,
}
}

private void inizializePackageLevelAnnotations(XPackage xPackage, ConfigContext configContext) {
private void initializePackageLevelAnnotations(XPackage xPackage, ConfigContext configContext) {
if ( xPackage != null ) {
checkForAnalyzerDefs( xPackage, configContext );
checkForFullTextFilterDefs( xPackage, configContext );
Expand Down Expand Up @@ -680,6 +712,7 @@ private void bindSpatialAnnotation(Spatial spatialAnnotation,
member,
false,
false,
parseContext.getIndexManagerType(),
reflectionManager,
configContext.getServiceManager()
);
Expand Down Expand Up @@ -1139,14 +1172,21 @@ private void bindFieldAnnotation(

NumericField numericFieldAnnotation = numericFields.getNumericFieldAnnotation( unPrefixedFieldName );

FieldBridge fieldBridge = bridgeFactory.buildFieldBridge(
fieldAnnotation,
member,
false,
numericFieldAnnotation != null,
reflectionManager,
configContext.getServiceManager()
);
FieldBridge fieldBridge;
if ( parseContext.skipFieldBridges() ) {
fieldBridge = null;
}
else {
fieldBridge = bridgeFactory.buildFieldBridge(
fieldAnnotation,
member,
false,
numericFieldAnnotation != null,
parseContext.getIndexManagerType(),
reflectionManager,
configContext.getServiceManager()
);
}

if ( fieldBridge instanceof MetadataProvidingFieldBridge ) {
MetadataProvidingFieldBridge metadataProvidingFieldBridge = (MetadataProvidingFieldBridge) fieldBridge;
Expand Down
Expand Up @@ -6,6 +6,8 @@
*/
package org.hibernate.search.engine.metadata.impl;

import org.hibernate.search.indexes.spi.IndexManager;

/**
* @author Hardy Ferentschik
*/
Expand All @@ -15,10 +17,26 @@ public interface MetadataProvider {
* Returns the Search related metadata for the specified type.
*
* @param clazz The type of interest.
* @param indexManagerType the {@code IndexManager} type managing this entity type
*
* @return the {@code TypeMetadata} for the specified type
*/
TypeMetadata getTypeMetadataFor(Class<?> clazz);
TypeMetadata getTypeMetadataFor(Class<?> clazz, Class<? extends IndexManager> indexManagerType);

/**
* Returns the ContainedIn related metadata for the specified type.
*
* The metadata for ContainedIn are not comprehensive: they do not
* contain the information about the FieldBridges. It's of no use
* for ContainedIn resolution and we can't build these information
* because classes only marked with {@code ContainedIn} are not tied
* to an {@code IndexManager}.
*
* @param clazz The type of interest.
*
* @return the {@code ContainedInTypeMetadata} for the specified type
*/
TypeMetadata getTypeMetadataForContainedIn(Class<?> clazz);

boolean containsSearchMetadata(Class<?> clazz);
}
Expand Up @@ -11,6 +11,7 @@
import java.util.TreeSet;

import org.hibernate.annotations.common.reflection.XClass;
import org.hibernate.search.indexes.spi.IndexManager;

/**
* Collects context information needed during the processing of the annotations.
Expand All @@ -22,12 +23,28 @@ public class ParseContext {
private final Set<String> spatialNames = new TreeSet<>();
private final Set<String> unqualifiedCollectedCollectionRoles = new HashSet<>();

private Class<? extends IndexManager> indexManagerType;
private XClass currentClass;
private int level = 0;
private int maxLevel = Integer.MAX_VALUE;
private boolean explicitDocumentId = false;
private boolean includeEmbeddedObjectId = false;

public Class<? extends IndexManager> getIndexManagerType() {
return indexManagerType;
}

void setIndexManagerType(Class<? extends IndexManager> indexManagerType) {
this.indexManagerType = indexManagerType;
}

/**
* If the {@code IndexManager} type is not defined, we skip the {@code FieldBridge} construction.
*/
boolean skipFieldBridges() {
return indexManagerType == null;
}

boolean hasBeenProcessed(XClass processedClass) {
return processedClasses.contains( processedClass );
}
Expand Down
Expand Up @@ -65,6 +65,10 @@ public class IndexManagerHolder {

private static final Similarity DEFAULT_SIMILARITY = new ClassicSimilarity();

private static final String DEFAULT_INDEX_MANAGER_KEY = "__DEFAULT__";

private final Map<String, Class<? extends IndexManager>> indexManagerImplementationsRegistry
= new ConcurrentHashMap<String, Class<? extends IndexManager>>();
private final Map<String, IndexManager> indexManagersRegistry = new ConcurrentHashMap<String, IndexManager>();

// I currently think it's easier to not hide sharding implementations in a custom
Expand Down Expand Up @@ -547,4 +551,34 @@ private boolean isShardingDynamic(Properties indexProperty, WorkerBuildContext b

return isShardingDynamic;
}

public Class<? extends IndexManager> getIndexManagerType(XClass entity, SearchConfiguration cfg, WorkerBuildContext buildContext) {
ServiceManager serviceManager = buildContext.getServiceManager();
IndexManagerFactory indexManagerFactory = serviceManager.requestService( IndexManagerFactory.class );

String indexName = getIndexName( entity, cfg );
Properties[] indexProperties = getIndexProperties( cfg, indexName );
String indexManagerImplementationName = indexProperties[0].getProperty( Environment.INDEX_MANAGER_IMPL_NAME );

String indexManagerImplementationKey = indexManagerImplementationName != null ?
indexManagerImplementationName : DEFAULT_INDEX_MANAGER_KEY;
if ( indexManagerImplementationsRegistry.containsKey( indexManagerImplementationKey ) ) {
return indexManagerImplementationsRegistry.get( indexManagerImplementationKey );
}

try {
Class<? extends IndexManager> indexManagerType;
if ( StringHelper.isEmpty( indexManagerImplementationName ) ) {
indexManagerType = indexManagerFactory.createDefaultIndexManager().getClass();
}
else {
indexManagerType = indexManagerFactory.createIndexManagerByName( indexManagerImplementationName ).getClass();
}
indexManagerImplementationsRegistry.put( indexManagerImplementationKey, indexManagerType );
return indexManagerType;
}
finally {
serviceManager.releaseService( IndexManagerFactory.class );
}
}
}
Expand Up @@ -63,6 +63,7 @@
import org.hibernate.search.filter.impl.CachingWrapperFilter;
import org.hibernate.search.filter.impl.MRUFilterCachingStrategy;
import org.hibernate.search.indexes.impl.IndexManagerHolder;
import org.hibernate.search.indexes.spi.IndexManager;
import org.hibernate.search.spi.impl.ExtendedSearchIntegratorWithShareableState;
import org.hibernate.search.spi.impl.PolymorphicIndexHierarchy;
import org.hibernate.search.spi.impl.SearchFactoryState;
Expand Down Expand Up @@ -335,7 +336,10 @@ else if ( metadataProvider.containsSearchMetadata( mappedClass ) ) {
//FIXME DocumentBuilderIndexedEntity needs to be built by a helper method receiving Class<T> to infer T properly
//XClass unfortunately is not (yet) genericized: TODO?

TypeMetadata typeMetadata = metadataProvider.getTypeMetadataFor( mappedClass );
// For ContainedIn, we get partial metadata information as we can't build
// the FieldBridges. This is not a problem as these metadata information
// are only used to track dependencies.
TypeMetadata typeMetadata = metadataProvider.getTypeMetadataForContainedIn( mappedClass );
final DocumentBuilderContainedEntity documentBuilder = new DocumentBuilderContainedEntity(
mappedXClass,
typeMetadata,
Expand Down Expand Up @@ -367,10 +371,13 @@ else if ( metadataProvider.containsSearchMetadata( mappedClass ) ) {
optimizationBlackListedTypes.add( mappedXClass );
}

Class<? extends IndexManager> indexManagerType = indexesFactory.getIndexManagerType(
mappedXClass, searchConfiguration, buildContext );

// Create all DocumentBuilderIndexedEntity
// FIXME DocumentBuilderIndexedEntity needs to be built by a helper method receiving Class<T> to infer T properly
// XClass unfortunately is not (yet) genericized: TODO ?
TypeMetadata typeMetadata = metadataProvider.getTypeMetadataFor( mappedClass );
TypeMetadata typeMetadata = metadataProvider.getTypeMetadataFor( mappedClass, indexManagerType );
final DocumentBuilderIndexedEntity documentBuilder =
new DocumentBuilderIndexedEntity(
mappedXClass,
Expand Down
Expand Up @@ -934,4 +934,8 @@ public interface Log extends BasicLogger {

@Message(id = 305, value = "Analyzer reference with name '%2$s' not initialized for field '%1$s' ")
SearchException analyzerReferenceNotInitialized(String fieldName, String name);

@Message(id = 306, value = "IndexManager type is required to build a FieldBridge for %2$s in %1$s")
SearchException indexManagerTypeRequiredToBuildFieldBridge(String className, String fieldName);

}

0 comments on commit 8051606

Please sign in to comment.