trip.spi.DefaultServiceProvider Maven / Gradle / Ivy
package trip.spi;
import static trip.spi.helpers.filter.Filter.filter;
import static trip.spi.helpers.filter.Filter.first;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.ServiceConfigurationError;
import trip.spi.helpers.EmptyIterable;
import trip.spi.helpers.EmptyProviderContext;
import trip.spi.helpers.FieldQualifierExtractor;
import trip.spi.helpers.ProducerFactoryMap;
import trip.spi.helpers.ProvidableClass;
import trip.spi.helpers.QualifierExtractor;
import trip.spi.helpers.ServiceLoader;
import trip.spi.helpers.SingleObjectIterable;
import trip.spi.helpers.filter.AnyObject;
import trip.spi.helpers.filter.Condition;
@SuppressWarnings( { "rawtypes", "unchecked" } )
public class DefaultServiceProvider implements ServiceProvider {
final Map, Iterable>> implementedClasses = new HashMap<>();
final SingletonContext singletonContext = new SingletonContext();
final Map, Iterable>> providers;
final ProducerFactoryMap producers;
public DefaultServiceProvider() {
this.providers = createDefaultProvidedData();
singletonContext.setQualifierExtractor( createQualifierExtractor() );
runHookBeforeProducersAreReady();
this.producers = loadAllProducers();
runAllStartupListeners();
}
private QualifierExtractor createQualifierExtractor() {
final Iterable extractors = loadAll(FieldQualifierExtractor.class);
return new QualifierExtractor( extractors );
}
private void runHookBeforeProducersAreReady() {
final Iterable startupListeners = loadAll( StartupListener.class );
for ( final StartupListener listener : startupListeners )
listener.beforeProducersReady( this );
}
private void runAllStartupListeners() {
final Iterable startupListeners = loadAll( StartupListener.class );
for ( final StartupListener listener : startupListeners )
listener.onStartup( this );
}
protected Map, Iterable>> createDefaultProvidedData() {
final Map, Iterable>> injectables = new HashMap, Iterable>>();
injectables.put( ServiceProvider.class, new SingleObjectIterable( this ) );
return injectables;
}
protected ProducerFactoryMap loadAllProducers() {
return ProducerFactoryMap.from( loadAll( ProducerFactory.class ) );
}
@Override
public T load( final Class interfaceClazz ) {
return load( interfaceClazz, AnyObject.instance() );
}
@Override
public T load( final Class interfaceClazz, final Condition condition ) {
return load( interfaceClazz, condition, EmptyProviderContext.INSTANCE );
}
@Override
public T load( final Class interfaceClazz, final ProviderContext context ) {
return load( interfaceClazz, AnyObject.instance(), context );
}
@Override
public T load( final Class interfaceClazz, final Condition condition, final ProviderContext context )
throws ServiceProviderException {
final T produced = produceFromFactory( interfaceClazz, condition, context );
if ( produced != null )
return produced;
return first( loadAll( interfaceClazz, condition ), condition );
}
@Override
public Iterable loadAll( final Class interfaceClazz, final Condition condition ) {
return filter( loadAll( interfaceClazz ), condition );
}
@Override
public Iterable loadAll( final Class interfaceClazz ) {
Iterable iterable = (Iterable)this.providers.get( interfaceClazz );
if ( iterable == null )
synchronized ( providers ) {
iterable = (Iterable)this.providers.get( interfaceClazz );
if ( iterable == null )
iterable = loadAllServicesImplementingTheInterface( interfaceClazz );
}
return iterable;
}
private Iterable loadAllServicesImplementingTheInterface( final Class interfaceClazz ) {
try {
return loadServiceFor( interfaceClazz );
} catch ( final StackOverflowError cause ) {
throw new ServiceConfigurationError(
"Could not load implementations of " + interfaceClazz.getCanonicalName() +
": Recursive dependency injection detected." );
}
}
private Iterable loadServiceFor( final Class interfaceClazz ) {
final List> iterableInterfaces = loadClassesImplementing( interfaceClazz );
Iterable instances = null;
if ( !iterableInterfaces.isEmpty() ){
instances = singletonContext.instantiate( iterableInterfaces );
provideOn( instances );
providerFor( interfaceClazz, instances );
} else {
final T instance = singletonContext.instantiate( interfaceClazz );
instances = instance == null ? EmptyIterable.instance() : new SingleObjectIterable<>( instance );
provideOn( instances );
}
return instances;
}
public List> loadClassesImplementing( final Class interfaceClazz ) {
List> implementations = (List)implementedClasses.get( interfaceClazz );
if ( implementations == null )
synchronized ( implementedClasses ) {
implementations = (List)implementedClasses.get( interfaceClazz );
if ( implementations == null ) {
implementations = ServiceLoader.loadImplementationsFor( interfaceClazz );
implementedClasses.put( (Class)interfaceClazz, (Iterable)implementations );
}
}
return implementations;
}
@Override
public void providerFor( final Class interfaceClazz, final ProducerFactory provider ) {
this.producers.memorizeProviderForClazz( provider, interfaceClazz );
}
@Override
public void providerFor( final Class interfaceClazz, final T object ) {
providerFor( interfaceClazz, new SingleObjectIterable( object ) );
}
protected void providerFor( final Class interfaceClazz, final Iterable iterable ) {
this.providers.put( interfaceClazz, iterable );
}
@Override
public void provideOn( final Iterable iterable ) {
for ( final T object : iterable )
provideOn( object );
}
@Override
public void provideOn( final Object object ) {
try {
final ProvidableClass> providableClass = singletonContext.retrieveProvidableClass( object.getClass() );
providableClass.provide( object, this );
} catch ( final Exception cause ) {
throw new ServiceProviderException( cause );
}
}
private T produceFromFactory( final Class interfaceClazz, final Condition condition, final ProviderContext context )
{
final ProducerFactory provider = getProviderFor( interfaceClazz, condition );
if ( provider != null )
return provider.provide( context );
return null;
}
public ProducerFactory getProviderFor( final Class interfaceClazz, final Condition condition ) {
if ( this.producers == null )
return null;
return (ProducerFactory)this.producers.get( interfaceClazz, condition );
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy