package com.google.inject.internal;
import com.google.common.base.Objects;
import com.google.inject.Key;
import com.google.inject.Provider;
import com.google.inject.Scope;
import com.google.inject.Scopes;
import com.google.inject.Singleton;
import com.google.inject.Stage;
import com.google.inject.binder.ScopedBindingBuilder;
import com.google.inject.spi.BindingScopingVisitor;
import com.google.inject.spi.ScopeBinding;
import java.lang.annotation.Annotation;
public abstract class Scoping {
public static final Scoping UNSCOPED =
new Scoping() {
@Override
public <V> V acceptVisitor(BindingScopingVisitor<V> visitor) {
return visitor.visitNoScoping();
}
@Override
public Scope getScopeInstance() {
return Scopes.NO_SCOPE;
}
@Override
public String toString() {
return Scopes.NO_SCOPE.toString();
}
@Override
public void applyTo(ScopedBindingBuilder scopedBindingBuilder) {
}
};
private static final Scoping EXPLICITLY_UNSCOPED =
new Scoping() {
@Override
public <V> V acceptVisitor(BindingScopingVisitor<V> visitor) {
return visitor.visitNoScoping();
}
@Override
public Scope getScopeInstance() {
return Scopes.NO_SCOPE;
}
@Override
public String toString() {
return Scopes.NO_SCOPE.toString();
}
@Override
public void applyTo(ScopedBindingBuilder scopedBindingBuilder) {
scopedBindingBuilder.in(Scopes.NO_SCOPE);
}
};
public static final Scoping SINGLETON_ANNOTATION =
new Scoping() {
@Override
public <V> V acceptVisitor(BindingScopingVisitor<V> visitor) {
return visitor.visitScopeAnnotation(Singleton.class);
}
@Override
public Class<? extends Annotation> getScopeAnnotation() {
return Singleton.class;
}
@Override
public String toString() {
return Singleton.class.getName();
}
@Override
public void applyTo(ScopedBindingBuilder scopedBindingBuilder) {
scopedBindingBuilder.in(Singleton.class);
}
};
public static final Scoping SINGLETON_INSTANCE =
new Scoping() {
@Override
public <V> V acceptVisitor(BindingScopingVisitor<V> visitor) {
return visitor.visitScope(Scopes.SINGLETON);
}
@Override
public Scope getScopeInstance() {
return Scopes.SINGLETON;
}
@Override
public String toString() {
return Scopes.SINGLETON.toString();
}
@Override
public void applyTo(ScopedBindingBuilder scopedBindingBuilder) {
scopedBindingBuilder.in(Scopes.SINGLETON);
}
};
public static final Scoping EAGER_SINGLETON =
new Scoping() {
@Override
public <V> V acceptVisitor(BindingScopingVisitor<V> visitor) {
return visitor.visitEagerSingleton();
}
@Override
public Scope getScopeInstance() {
return Scopes.SINGLETON;
}
@Override
public String toString() {
return "eager singleton";
}
@Override
public void applyTo(ScopedBindingBuilder scopedBindingBuilder) {
scopedBindingBuilder.asEagerSingleton();
}
};
public static Scoping forAnnotation(final Class<? extends Annotation> scopingAnnotation) {
if (scopingAnnotation == Singleton.class || scopingAnnotation == javax.inject.Singleton.class) {
return SINGLETON_ANNOTATION;
}
return new Scoping() {
@Override
public <V> V acceptVisitor(BindingScopingVisitor<V> visitor) {
return visitor.visitScopeAnnotation(scopingAnnotation);
}
@Override
public Class<? extends Annotation> getScopeAnnotation() {
return scopingAnnotation;
}
@Override
public String toString() {
return scopingAnnotation.getName();
}
@Override
public void applyTo(ScopedBindingBuilder scopedBindingBuilder) {
scopedBindingBuilder.in(scopingAnnotation);
}
};
}
public static Scoping forInstance(final Scope scope) {
if (scope == Scopes.SINGLETON) {
return SINGLETON_INSTANCE;
} else if (scope == Scopes.NO_SCOPE) {
return EXPLICITLY_UNSCOPED;
}
return new Scoping() {
@Override
public <V> V acceptVisitor(BindingScopingVisitor<V> visitor) {
return visitor.visitScope(scope);
}
@Override
public Scope getScopeInstance() {
return scope;
}
@Override
public String toString() {
return scope.toString();
}
@Override
public void applyTo(ScopedBindingBuilder scopedBindingBuilder) {
scopedBindingBuilder.in(scope);
}
};
}
public boolean isExplicitlyScoped() {
return this != UNSCOPED;
}
public boolean isNoScope() {
return getScopeInstance() == Scopes.NO_SCOPE;
}
public boolean isEagerSingleton(Stage stage) {
if (this == EAGER_SINGLETON) {
return true;
}
if (stage == Stage.PRODUCTION) {
return this == SINGLETON_ANNOTATION || this == SINGLETON_INSTANCE;
}
return false;
}
public Scope getScopeInstance() {
return null;
}
public Class<? extends Annotation> getScopeAnnotation() {
return null;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof Scoping) {
Scoping o = (Scoping) obj;
return Objects.equal(getScopeAnnotation(), o.getScopeAnnotation())
&& Objects.equal(getScopeInstance(), o.getScopeInstance());
} else {
return false;
}
}
@Override
public int hashCode() {
return Objects.hashCode(getScopeAnnotation(), getScopeInstance());
}
public abstract <V> V acceptVisitor(BindingScopingVisitor<V> visitor);
public abstract void applyTo(ScopedBindingBuilder scopedBindingBuilder);
private Scoping() {}
static <T> InternalFactory<? extends T> scope(
Key<T> key,
InjectorImpl injector,
InternalFactory<? extends T> creator,
Object source,
Scoping scoping) {
if (scoping.isNoScope()) {
return creator;
}
Scope scope = scoping.getScopeInstance();
Provider<T> scoped =
scope.scope(key, new ProviderToInternalFactoryAdapter<T>(injector, creator));
return new InternalFactoryToProviderAdapter<T>(scoped, source);
}
static Scoping makeInjectable(Scoping scoping, InjectorImpl injector, Errors errors) {
Class<? extends Annotation> scopeAnnotation = scoping.getScopeAnnotation();
if (scopeAnnotation == null) {
return scoping;
}
ScopeBinding scope = injector.state.getScopeBinding(scopeAnnotation);
if (scope != null) {
return forInstance(scope.getScope());
}
errors.scopeNotFound(scopeAnnotation);
return UNSCOPED;
}
}