Skip to content

Commit

Permalink
Fix issue about module scopes
Browse files Browse the repository at this point in the history
  • Loading branch information
dlemures committed May 2, 2016
1 parent b188bec commit feeec1d
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 115 deletions.
Expand Up @@ -8,7 +8,7 @@
*
* @param <T> the class of the instances provided by this provider.
*/
public class UnScopedProviderImpl<T> {
public class InternalProviderImpl<T> {
private T instance;
private Factory<T> factory;
private Class<T> factoryClass;
Expand All @@ -17,24 +17,24 @@ public class UnScopedProviderImpl<T> {
private Factory<Provider<T>> providerFactory;
private Class<Provider<T>> providerFactoryClass;

public UnScopedProviderImpl(T instance) {
public InternalProviderImpl(T instance) {
this.instance = instance;
}

public UnScopedProviderImpl(Provider<? extends T> providerInstance, boolean isLazy) {
public InternalProviderImpl(Provider<? extends T> providerInstance, boolean isLazy) {
this.providerInstance = providerInstance;
this.isLazy = isLazy;
}

public UnScopedProviderImpl(Factory<?> factory, boolean isProviderFactory) {
public InternalProviderImpl(Factory<?> factory, boolean isProviderFactory) {
if (isProviderFactory) {
this.providerFactory = (Factory<Provider<T>>) factory;
} else {
this.factory = (Factory<T>) factory;
}
}

public UnScopedProviderImpl(Class<?> factoryKeyClass, boolean isProviderFactoryClass) {
public InternalProviderImpl(Class<?> factoryKeyClass, boolean isProviderFactoryClass) {
if (isProviderFactoryClass) {
this.providerFactoryClass = (Class<Provider<T>>) factoryKeyClass;
} else {
Expand Down Expand Up @@ -69,7 +69,8 @@ public synchronized T get(Scope scope) {
if (!factory.hasScopeAnnotation()) {
return factory.createInstance(scope);
}
instance = factory.createInstance(scope);
Scope targetScope = factory.getTargetScope(scope);
instance = factory.createInstance(targetScope);
//gc
factory = null;
return instance;
Expand All @@ -89,7 +90,8 @@ public synchronized T get(Scope scope) {
return instance;
}
if (providerFactory.hasScopeAnnotation()) {
providerInstance = providerFactory.createInstance(scope);
Scope targetScope = providerFactory.getTargetScope(scope);
providerInstance = providerFactory.createInstance(targetScope);
//gc
providerFactory = null;
return providerInstance.get();
Expand Down
121 changes: 55 additions & 66 deletions toothpick-runtime/src/main/java/toothpick/ScopeImpl.java
Expand Up @@ -26,14 +26,14 @@
* </p>
*/
public class ScopeImpl extends Scope {
private static IdentityHashMap<Class, UnScopedProviderImpl> mapClassesToUnScopedProviders = new IdentityHashMap<>();
protected IdentityHashMap<Class, UnNamedAndNamedProviders> mapClassesToAllProviders = new IdentityHashMap<>();
private static IdentityHashMap<Class, InternalProviderImpl> mapClassesToUnScopedProviders = new IdentityHashMap<>();
private IdentityHashMap<Class, UnNamedAndNamedProviders> mapClassesToAllProviders = new IdentityHashMap<>();
private boolean hasTestModules;

public ScopeImpl(Object name) {
super(name);
//it's always possible to get access to the scope that contains an injected object.
installScopedProvider(Scope.class, null, new ScopedProviderImpl<>(this));
installScopedProvider(Scope.class, null, new InternalProviderImpl<>(this));
}

@Override
Expand All @@ -48,25 +48,25 @@ public <T> T getInstance(Class<T> clazz, String name) {

@Override
public <T> Provider<T> getProvider(Class<T> clazz) {
UnScopedProviderImpl<? extends T> provider = getProviderInternal(clazz, null);
InternalProviderImpl<? extends T> provider = getProviderInternal(clazz, null);
return new ThreadSafeProviderImpl<>(this, provider, false);
}

@Override
public <T> Provider<T> getProvider(Class<T> clazz, String name) {
UnScopedProviderImpl<? extends T> provider = getProviderInternal(clazz, name);
InternalProviderImpl<? extends T> provider = getProviderInternal(clazz, name);
return new ThreadSafeProviderImpl<>(this, provider, false);
}

@Override
public <T> Lazy<T> getLazy(Class<T> clazz) {
UnScopedProviderImpl<? extends T> provider = getProviderInternal(clazz, null);
InternalProviderImpl<? extends T> provider = getProviderInternal(clazz, null);
return new ThreadSafeProviderImpl<>(this, provider, true);
}

@Override
public <T> Lazy<T> getLazy(Class<T> clazz, String name) {
UnScopedProviderImpl<? extends T> provider = getProviderInternal(clazz, name);
InternalProviderImpl<? extends T> provider = getProviderInternal(clazz, name);
return new ThreadSafeProviderImpl<>(this, provider, true);
}

Expand Down Expand Up @@ -149,7 +149,7 @@ private void installModule(Module module) {
synchronized (clazz) {
String bindingName = binding.getName();
if (!hasTestModules || getScopedProvider(clazz, bindingName) == null) {
ScopedProviderImpl provider = toProvider(binding);
InternalProviderImpl provider = toProvider(binding);
installScopedProvider(clazz, bindingName, provider);
}
}
Expand All @@ -161,22 +161,22 @@ private void installModule(Module module) {
//make the APIs very unstable as you could not get any instance of the
//implementation class via an scope, it would fail but be syntactically valid.
//only creating an instance of the interface is valid with this syntax.
/*VisibleForTesting*/ <T> ScopedProviderImpl<T> toProvider(Binding<T> binding) {
/*VisibleForTesting*/ <T> InternalProviderImpl<T> toProvider(Binding<T> binding) {
if (binding == null) {
throw new IllegalStateException("null binding are not allowed. Should not happen unless getBindingSet is overridden.");
}
switch (binding.getMode()) {
case SIMPLE:
return new ScopedProviderImpl<>(this, binding.getKey(), false);
return new InternalProviderImpl<>(binding.getKey(), false);
case CLASS:
return new ScopedProviderImpl<>(this, binding.getImplementationClass(), false);
return new InternalProviderImpl<>(binding.getImplementationClass(), false);
case INSTANCE:
return new ScopedProviderImpl<>(binding.getInstance());
return new InternalProviderImpl<>(binding.getInstance());
case PROVIDER_INSTANCE:
//to ensure providers do not have to deal with concurrency, we wrap them in a thread safe provider
return new ScopedProviderImpl<>(binding.getProviderInstance(), false);
return new InternalProviderImpl<>(binding.getProviderInstance(), false);
case PROVIDER_CLASS:
return new ScopedProviderImpl<>(this, binding.getProviderClass(), true);
return new InternalProviderImpl<>(binding.getProviderClass(), true);

//JACOCO:OFF
default:
Expand All @@ -195,34 +195,34 @@ private void installModule(Module module) {
* it will be added to the pool of un-scoped providers.
* Note that
*
* @param clazz the {@link Class} of {@code T} for which we lookup an {@link UnScopedProviderImpl}.
* @param clazz the {@link Class} of {@code T} for which we lookup an {@link InternalProviderImpl}.
* @param name the potential name of the provider when it was bound (which means we always returned a scoped provider if
* name is not null).
* @param <T> the type for which we lookup an {@link UnScopedProviderImpl}.
* @return a provider associated to the {@code T}. The returned provider is un-scoped (remember that {@link ScopedProviderImpl} is a subclass of
* {@link UnScopedProviderImpl}). The returned provider will be scoped by the public methods to use the current scope.
* @param <T> the type for which we lookup an {@link InternalProviderImpl}.
* @return a provider associated to the {@code T}. The returned provider is un-scoped.
* The returned provider will be scoped by the public methods to use the current scope.
*/
private <T> UnScopedProviderImpl<? extends T> getProviderInternal(Class<T> clazz, String name) {
private <T> InternalProviderImpl<? extends T> getProviderInternal(Class<T> clazz, String name) {
if (clazz == null) {
throw new IllegalArgumentException("TP can't get an instance of a null class.");
}
synchronized (clazz) {
ScopedProviderImpl<? extends T> scopedProvider = getScopedProvider(clazz, name);
InternalProviderImpl<? extends T> scopedProvider = getScopedProvider(clazz, name);
if (scopedProvider != null) {
return scopedProvider;
}
Iterator<Scope> iterator = parentScopes.iterator();
while (iterator.hasNext()) {
Scope parentScope = iterator.next();
ScopeImpl parentScopeImpl = (ScopeImpl) parentScope;
ScopedProviderImpl<? extends T> parentScopedProvider = parentScopeImpl.getScopedProvider(clazz, name);
InternalProviderImpl<? extends T> parentScopedProvider = parentScopeImpl.getScopedProvider(clazz, name);
if (parentScopedProvider != null) {
return parentScopedProvider;
}
}

//check if we have a cached un-scoped provider
UnScopedProviderImpl unScopedProviderInPool = mapClassesToUnScopedProviders.get(clazz);
InternalProviderImpl<T> unScopedProviderInPool = mapClassesToUnScopedProviders.get(clazz);
if (unScopedProviderInPool != null) {
return unScopedProviderInPool;
}
Expand All @@ -232,22 +232,20 @@ private <T> UnScopedProviderImpl<? extends T> getProviderInternal(Class<T> clazz
//we need to know whether they are scoped or not, if so we scope them
//if not, they are place in the pool
Factory<T> factory = FactoryRegistryLocator.getFactory(clazz);
InternalProviderImpl<T> newProvider = new InternalProviderImpl<>(factory, false);

Scope targetScope = factory.getTargetScope(this);
ScopeImpl targetScopeImpl = (ScopeImpl) targetScope;
if (factory.hasScopeAnnotation()) {
//the new provider will have to work in the current scope
final ScopedProviderImpl<T> newProvider = new ScopedProviderImpl<>(targetScope, factory, false);
//it is bound to its target scope only if it has a scope annotation.
ScopeImpl targetScopeImpl = (ScopeImpl) factory.getTargetScope(this);
targetScopeImpl.installScopedProvider(clazz, name, newProvider);
return newProvider;
} else {
//the provider is but in a pool of unbound providers for later reuse
final UnScopedProviderImpl<T> newProvider = new UnScopedProviderImpl<>(factory, false);
//the pool is static as it is accessible from all scopes
installUnScopedProvider(clazz, newProvider);
return newProvider;
}

return newProvider;
}
}

Expand All @@ -262,7 +260,7 @@ private <T> UnScopedProviderImpl<? extends T> getProviderInternal(Class<T> clazz
* @return the scoped provider of this scope for class {@code clazz} and {@code bindingName},
* if one is scoped, {@code null} otherwise.
*/
private <T> ScopedProviderImpl<? extends T> getScopedProvider(Class<T> clazz, String bindingName) {
private <T> InternalProviderImpl<? extends T> getScopedProvider(Class<T> clazz, String bindingName) {
synchronized (clazz) {
UnNamedAndNamedProviders<T> unNamedAndNamedProviders = mapClassesToAllProviders.get(clazz);
if (unNamedAndNamedProviders == null) {
Expand All @@ -272,69 +270,60 @@ private <T> ScopedProviderImpl<? extends T> getScopedProvider(Class<T> clazz, St
return unNamedAndNamedProviders.unNamedProvider;
}

Map<String, ScopedProviderImpl<? extends T>> mapNameToProvider = unNamedAndNamedProviders.getMapNameToProvider();
if (mapNameToProvider == null) {
if (unNamedAndNamedProviders.mapNameToProvider == null) {
return null;
}
return mapNameToProvider.get(bindingName);
return unNamedAndNamedProviders.mapNameToProvider.get(bindingName);
}
}

/**
* Install the provider of the class {@code clazz} and name {@code bindingName}
* Install the unScopedProvider of the class {@code clazz}
* in the pool of unscoped providers.
*
* @param clazz the class for which to install the unscoped unScopedProvider.
* @param <T> the type of {@code clazz}.
*/
private <T> void installUnScopedProvider(Class<T> clazz, InternalProviderImpl<? extends T> unScopedProvider) {
synchronized (clazz) {
mapClassesToUnScopedProviders.put(clazz, unScopedProvider);
}
}

/**
* Install the provider {@code provider} of the class {@code clazz} and name {@code bindingName}
* in the current scope.
*
* @param clazz the class for which to install the scoped provider of this scope.
* @param bindingName the name, possibly {@code null}, for which to install the scoped provider.
* @param provider the provider that will be used to obtain the injected instances.
* @param <T> the type of {@code clazz}.
*/
private <T> void installScopedProvider(Class<T> clazz, String bindingName, ScopedProviderImpl<? extends T> provider) {
private <T> void installScopedProvider(Class<T> clazz, String bindingName, InternalProviderImpl<? extends T> provider) {
synchronized (clazz) {
UnNamedAndNamedProviders<T> unNamedAndNamedProviders = mapClassesToAllProviders.get(clazz);
if (unNamedAndNamedProviders == null) {
unNamedAndNamedProviders = new UnNamedAndNamedProviders<>();
mapClassesToAllProviders.put(clazz, unNamedAndNamedProviders);
}

if (bindingName == null) {
unNamedAndNamedProviders.setUnNamedProvider(provider);
unNamedAndNamedProviders.unNamedProvider = provider;
} else {
Map<String, ScopedProviderImpl<? extends T>> mapNameToProvider = unNamedAndNamedProviders.getMapNameToProvider();
if (mapNameToProvider == null) {
mapNameToProvider = new HashMap<>();
unNamedAndNamedProviders.setMapNameToProvider(mapNameToProvider);
}
mapNameToProvider.put(bindingName, provider);
unNamedAndNamedProviders.putNamedProvider(bindingName, provider);
}
}
}

/**
* Install the unScopedProvider of the class {@code clazz}
* in the pool of unscoped providers.
*
* @param clazz the class for which to install the unscoped unScopedProvider.
* @param <T> the type of {@code clazz}.
*/
private <T> void installUnScopedProvider(Class<T> clazz, UnScopedProviderImpl<? extends T> unScopedProvider) {
synchronized (clazz) {
mapClassesToUnScopedProviders.put(clazz, unScopedProvider);
}
}

private static class UnNamedAndNamedProviders<T> {
private ScopedProviderImpl<? extends T> unNamedProvider;
private Map<String, ScopedProviderImpl<? extends T>> mapNameToProvider;

public Map<String, ScopedProviderImpl<? extends T>> getMapNameToProvider() {
return mapNameToProvider;
}
private InternalProviderImpl<? extends T> unNamedProvider;
private Map<String, InternalProviderImpl<? extends T>> mapNameToProvider;

public void setMapNameToProvider(Map<String, ScopedProviderImpl<? extends T>> mapNameToProvider) {
this.mapNameToProvider = mapNameToProvider;
}

public void setUnNamedProvider(ScopedProviderImpl<? extends T> unNamedProvider) {
this.unNamedProvider = unNamedProvider;
private void putNamedProvider(String name, InternalProviderImpl<? extends T> provider) {
if (mapNameToProvider == null) {
mapNameToProvider = new HashMap<>();
}
mapNameToProvider.put(name, provider);
}
}
}
40 changes: 0 additions & 40 deletions toothpick-runtime/src/main/java/toothpick/ScopedProviderImpl.java

This file was deleted.

Expand Up @@ -9,10 +9,10 @@
public class ThreadSafeProviderImpl<T> implements Provider<T>, Lazy<T> {
private volatile T instance;
private Scope scope;
private UnScopedProviderImpl<? extends T> providerInstance;
private InternalProviderImpl<? extends T> providerInstance;
private boolean isLazy;

public ThreadSafeProviderImpl(Scope scope, UnScopedProviderImpl<? extends T> providerInstance, boolean isLazy) {
public ThreadSafeProviderImpl(Scope scope, InternalProviderImpl<? extends T> providerInstance, boolean isLazy) {
this.scope = scope;
this.providerInstance = providerInstance;
this.isLazy = isLazy;
Expand Down

0 comments on commit feeec1d

Please sign in to comment.