Skip to content

Commit

Permalink
HSEARCH-3386 Allow to create BeanReference configuration properties
Browse files Browse the repository at this point in the history
  • Loading branch information
yrodiere committed Dec 4, 2018
1 parent e5e2897 commit 65b2410
Show file tree
Hide file tree
Showing 11 changed files with 421 additions and 32 deletions.
Expand Up @@ -38,6 +38,7 @@
import org.hibernate.search.engine.cfg.spi.ConfigurationProperty;
import org.hibernate.search.engine.backend.spi.BackendBuildContext;
import org.hibernate.search.engine.environment.bean.BeanProvider;
import org.hibernate.search.engine.environment.bean.BeanReference;
import org.hibernate.search.engine.logging.spi.EventContexts;
import org.hibernate.search.util.AssertionFailure;
import org.hibernate.search.util.EventContext;
Expand Down Expand Up @@ -66,6 +67,11 @@ public class ElasticsearchBackendFactory implements BackendFactory {
.withDefault( SearchBackendElasticsearchSettings.Defaults.LOG_JSON_PRETTY_PRINTING )
.build();

private static final ConfigurationProperty<Optional<BeanReference>> ANALYSIS_CONFIGURER =
ConfigurationProperty.forKey( SearchBackendElasticsearchSettings.ANALYSIS_CONFIGURER )
.asBeanReference( ElasticsearchAnalysisConfigurer.class )
.build();

@Override
public BackendImplementor<?> create(String name, BackendBuildContext buildContext, ConfigurationPropertySource propertySource) {
EventContext backendContext = EventContexts.fromBackendName( name );
Expand Down Expand Up @@ -128,15 +134,8 @@ private ElasticsearchAnalysisDefinitionRegistry getAnalysisDefinitionRegistry(Ev
try {
// Apply the user-provided analysis configurer if necessary
final BeanProvider beanProvider = buildContext.getServiceManager().getBeanProvider();
ConfigurationProperty<Optional<ElasticsearchAnalysisConfigurer>> analysisConfigurerProperty =
ConfigurationProperty.forKey( SearchBackendElasticsearchSettings.ANALYSIS_CONFIGURER )
.as(
ElasticsearchAnalysisConfigurer.class,
reference -> beanProvider
.getBean( ElasticsearchAnalysisConfigurer.class, reference )
)
.build();
return analysisConfigurerProperty.get( propertySource )
return ANALYSIS_CONFIGURER.get( propertySource )
.map( beanReference -> beanReference.getBean( beanProvider, ElasticsearchAnalysisConfigurer.class ) )
.map( configurer -> {
ElasticsearchAnalysisDefinitionContainerContextImpl collector
= new ElasticsearchAnalysisDefinitionContainerContextImpl();
Expand Down
Expand Up @@ -32,6 +32,7 @@
import org.hibernate.search.engine.cfg.spi.ConfigurationProperty;
import org.hibernate.search.engine.backend.spi.BackendBuildContext;
import org.hibernate.search.engine.environment.bean.BeanProvider;
import org.hibernate.search.engine.environment.bean.BeanReference;
import org.hibernate.search.util.EventContext;
import org.hibernate.search.engine.logging.spi.EventContexts;
import org.hibernate.search.util.AssertionFailure;
Expand Down Expand Up @@ -69,6 +70,11 @@ public class LuceneBackendFactory implements BackendFactory {
.withDefault( SearchBackendLuceneSettings.Defaults.MULTI_TENANCY_STRATEGY )
.build();

private static final ConfigurationProperty<Optional<BeanReference>> ANALYSIS_CONFIGURER =
ConfigurationProperty.forKey( SearchBackendLuceneSettings.ANALYSIS_CONFIGURER )
.asBeanReference( LuceneAnalysisConfigurer.class )
.build();

@Override
public BackendImplementor<?> create(String name, BackendBuildContext buildContext,
ConfigurationPropertySource propertySource) {
Expand Down Expand Up @@ -158,15 +164,8 @@ private LuceneAnalysisDefinitionRegistry getAnalysisDefinitionRegistry(EventCont
try {
// Apply the user-provided analysis configurer if necessary
final BeanProvider beanProvider = buildContext.getServiceManager().getBeanProvider();
ConfigurationProperty<Optional<LuceneAnalysisConfigurer>> analysisConfigurerProperty =
ConfigurationProperty.forKey( SearchBackendLuceneSettings.ANALYSIS_CONFIGURER )
.as(
LuceneAnalysisConfigurer.class,
reference -> beanProvider
.getBean( LuceneAnalysisConfigurer.class, reference )
)
.build();
return analysisConfigurerProperty.get( propertySource )
return ANALYSIS_CONFIGURER.get( propertySource )
.map( beanReference -> beanReference.getBean( beanProvider, LuceneAnalysisConfigurer.class ) )
.map( configurer -> {
LuceneAnalysisComponentFactory analysisComponentFactory = new LuceneAnalysisComponentFactory(
luceneVersion,
Expand Down
Expand Up @@ -15,6 +15,7 @@
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.hibernate.search.engine.environment.bean.BeanReference;
import org.hibernate.search.engine.logging.impl.Log;
import org.hibernate.search.util.SearchException;
import org.hibernate.search.util.impl.common.LoggerFactory;
Expand Down Expand Up @@ -132,6 +133,29 @@ public static Optional<Long> convertLong(Object value) {
throw log.invalidLongPropertyValue( "", null );
}

public static Optional<BeanReference> convertBeanReference(Class<?> expectedType, Object value) {
try {
if ( expectedType.isInstance( value ) ) {
return Optional.of( BeanReference.ofInstance( expectedType.cast( value ) ) );
}
if ( value instanceof BeanReference ) {
return Optional.of( (BeanReference) value );
}
if ( value instanceof Class ) {
return Optional.of( BeanReference.ofType( (Class<?>) value ) );
}
if ( value instanceof String ) {
return optionalTrimmedNonEmpty( (String) value )
.map( BeanReference::ofName );
}
}
catch (RuntimeException e) {
throw log.invalidBeanReferencePropertyValue( expectedType, e.getMessage(), e );
}

throw log.invalidBeanReferencePropertyValue( expectedType, "", null );
}

public static <T> Optional<List<T>> convertMultiValue(Pattern separatorPattern,
Function<Object, Optional<T>> elementConverter, Object value) {
if ( value instanceof Collection ) {
Expand Down
Expand Up @@ -10,6 +10,7 @@

import org.hibernate.search.engine.cfg.spi.KeyContext;
import org.hibernate.search.engine.cfg.spi.OptionalPropertyContext;
import org.hibernate.search.engine.environment.bean.BeanReference;

public class KeyContextImpl implements KeyContext {

Expand Down Expand Up @@ -39,6 +40,11 @@ public OptionalPropertyContext<Long> asLong() {
return new OptionalPropertyContextImpl<>( key, ConvertUtils::convertLong );
}

@Override
public OptionalPropertyContext<BeanReference> asBeanReference(Class<?> expectedType) {
return new OptionalPropertyContextImpl<>( key, v -> ConvertUtils.convertBeanReference( expectedType, v ) );
}

@Override
public <T> OptionalPropertyContext<T> as(Class<T> expectedType, Function<String, T> parser) {
return new OptionalPropertyContextImpl<>( key, v -> ConvertUtils.convert( expectedType, parser, v ) );
Expand Down
Expand Up @@ -8,6 +8,8 @@

import java.util.function.Function;

import org.hibernate.search.engine.environment.bean.BeanReference;

public interface KeyContext {
OptionalPropertyContext<String> asString();

Expand All @@ -17,5 +19,7 @@ public interface KeyContext {

OptionalPropertyContext<Long> asLong();

OptionalPropertyContext<BeanReference> asBeanReference(Class<?> expectedType);

<T> OptionalPropertyContext<T> as(Class<T> expectedType, Function<String, T> parser);
}
Expand Up @@ -12,6 +12,7 @@

import org.hibernate.search.engine.backend.document.DocumentElement;
import org.hibernate.search.engine.backend.document.model.dsl.spi.IndexSchemaRootNodeBuilder;
import org.hibernate.search.engine.environment.bean.BeanReference;
import org.hibernate.search.engine.mapper.mapping.spi.MappedIndexManager;
import org.hibernate.search.engine.backend.index.spi.IndexManagerBuilder;
import org.hibernate.search.engine.backend.index.spi.IndexManagerImplementor;
Expand All @@ -36,8 +37,8 @@ class IndexManagerBuildingStateHolder {
private static final ConfigurationProperty<Optional<String>> INDEX_BACKEND_NAME =
ConfigurationProperty.forKey( "backend" ).asString().build();

private static final ConfigurationProperty<Optional<String>> BACKEND_TYPE =
ConfigurationProperty.forKey( "type" ).asString().build();
private static final ConfigurationProperty<Optional<BeanReference>> BACKEND_TYPE =
ConfigurationProperty.forKey( "type" ).asBeanReference( BackendFactory.class ).build();

private final RootBuildContext rootBuildContext;
private final ConfigurationPropertySource propertySource;
Expand Down Expand Up @@ -94,11 +95,11 @@ void closeOnFailure(SuppressingCloser closer) {

private BackendBuildingState<?> createBackend(String backendName) {
ConfigurationPropertySource backendPropertySource = propertySource.withMask( "backends." + backendName );
// TODO more checks on the backend type (non-null, non-empty)
String backendType = BACKEND_TYPE.get( backendPropertySource ).get();
// TODO properly check that there is a value before calling get()
BeanReference backendFactoryReference = BACKEND_TYPE.get( backendPropertySource ).get();

BeanProvider beanProvider = rootBuildContext.getServiceManager().getBeanProvider();
BackendFactory backendFactory = beanProvider.getBean( BackendFactory.class, backendType );
BackendFactory backendFactory = backendFactoryReference.getBean( beanProvider, BackendFactory.class );
BackendBuildContext backendBuildContext = new BackendBuildContextImpl( rootBuildContext );

BackendImplementor<?> backend = backendFactory.create( backendName, backendBuildContext, backendPropertySource );
Expand Down
Expand Up @@ -55,4 +55,14 @@ static BeanReference of(Class<?> type, String name) {
return TypeAndNameBeanReference.createLenient( type, name );
}

/**
* Create a {@link BeanReference} referencing a bean instance directly.
*
* @param instance The bean instance. Must not be null.
* @return The corresponding {@link BeanReference}.
*/
static BeanReference ofInstance(Object instance) {
return new InstanceBeanReference( instance );
}

}
@@ -0,0 +1,30 @@
/*
* Hibernate Search, full-text search for your domain model
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.search.engine.environment.bean;

import org.hibernate.search.util.impl.common.Contracts;

final class InstanceBeanReference implements BeanReference {

private final Object instance;

InstanceBeanReference(Object instance) {
Contracts.assertNotNull( instance, "instance" );
this.instance = instance;
}

@Override
public String toString() {
return getClass().getSimpleName() + "[instance=" + instance + "]";
}

@Override
public <T> T getBean(BeanProvider beanProvider, Class<T> expectedType) {
return expectedType.cast( instance );
}

}
Expand Up @@ -239,4 +239,9 @@ SearchException relativeFieldNameCannotContainDot(String relativeFieldName,

@Message(id = ID_OFFSET_2 + 46, value = "Found an infinite IndexedEmbedded recursion involving path '%1$s' on type '%2$s'.")
SearchException indexedEmbeddedCyclicRecursion(String cyclicRecursionPath, @FormatWith(MappableTypeModelFormatter.class) MappableTypeModel parentTypeModel);

@Message(id = ID_OFFSET_2 + 47,
value = "Invalid BeanReference value: expected an instance of '%1$s', BeanReference, String or Class. %2$s")
SearchException invalidBeanReferencePropertyValue(@FormatWith(ClassFormatter.class) Class<?> expectedType,
String nestedErrorMessage, @Cause Exception cause);
}

0 comments on commit 65b2410

Please sign in to comment.