/**
* Copyright (C) 2010 Daniel Manzke <daniel.manzke@googlemail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.devsurf.injection.guice.scanner.features;
import java.lang.annotation.Annotation;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.inject.Inject;
import javax.inject.Provider;
import com.google.inject.Binder;
import com.google.inject.Injector;
import com.google.inject.binder.AnnotatedBindingBuilder;
import com.google.inject.binder.LinkedBindingBuilder;
import com.google.inject.binder.ScopedBindingBuilder;
import com.google.inject.util.Providers;
import de.devsurf.injection.guice.configuration.VariableResolver;
import de.devsurf.injection.guice.install.BindingStage;
import de.devsurf.injection.guice.install.BindingTracer;
import de.devsurf.injection.guice.install.InstallationContext;
import de.devsurf.injection.guice.install.InstallationContext.StageableRequest;
import de.devsurf.injection.guice.install.bindjob.BindingJob;
import de.devsurf.injection.guice.install.bindjob.ConstantBindingJob;
import de.devsurf.injection.guice.install.bindjob.ImplementationBindingJob;
import de.devsurf.injection.guice.install.bindjob.InstanceBindingJob;
import de.devsurf.injection.guice.install.bindjob.InterfaceBindingJob;
import de.devsurf.injection.guice.install.bindjob.ProviderBindingJob;
import de.devsurf.injection.guice.scanner.ScannerModule;
/**
* Default Implementation for Annotation Listeners, which should stay informed
* abbout found annotated classes. Due the fact, that we need the Binder of the
* Child Injector, it will be set at runtime by the {@link ScannerModule}.
*
* @author Daniel Manzke
*
*/
public abstract class BindingScannerFeature implements ScannerFeature {
private Logger _logger = Logger.getLogger(BindingScannerFeature.class.getName());
protected Set<String> others = new HashSet<String>();
protected Set<String> qualifiers = new HashSet<String>();
protected Binder _binder;
@Inject
protected Injector injector;
@Inject
protected BindingTracer tracer;
@Inject
protected VariableResolver resolver;
protected InstallationContext context;
public void setBinder(Binder binder) {
_binder = binder;
}
@Inject
public void configure(InstallationContext context) {
this.context = context;
}
@Override
public void found(final Class<Object> annotatedClass, final Map<String, Annotation> annotations) {
final BindingStage stage = accept(annotatedClass, annotations);
if (stage != BindingStage.IGNORE) {
context.add(new StageableRequest() {
private Class<Object> _annotatedClass = annotatedClass;
private Map<String, Annotation> _annotations = new HashMap<String, Annotation>(
annotations);
@Override
public Void call() throws Exception {
process(_annotatedClass, _annotations);
return null;
}
@Override
public BindingStage getExecutionStage() {
return stage;
}
});
}
}
public abstract BindingStage accept(Class<Object> annotatedClass,
Map<String, Annotation> annotations);
public abstract void process(Class<Object> annotatedClass, Map<String, Annotation> annotations);
protected <T, V extends T> void bindProvider(final Provider<V> provider, Class<T> interf,
Annotation annotation, Class<? extends Annotation> scope) {
BindingJob job = new ProviderBindingJob(scope, provider.getClass(), annotation, interf.getName());
if (!tracer.contains(job)) {
LinkedBindingBuilder<T> builder;
synchronized (_binder) {
builder = _binder.bind(interf);
if (annotation != null) {
builder = ((AnnotatedBindingBuilder<T>) builder).annotatedWith(annotation);
}
ScopedBindingBuilder scopedBuilder = builder.toProvider(Providers.guicify(provider));
if (scope != null) {
scopedBuilder.in(scope);
}
}
tracer.add(job);
} else {
if (_logger.isLoggable(Level.INFO)) {
_logger.log(Level.INFO, "Ignoring BindingJob \"" + job.toString()
+ "\", because it was already bound.", new Exception());
} else if (_logger.isLoggable(Level.WARNING)) {
_logger.log(Level.WARNING, "Ignoring BindingJob \"" + job.toString()
+ "\", because it was already bound.");
}
}
}
protected <T, V extends T> void bindProvider(final Class<? extends Provider<V>> provider, Class<T> interf,
Annotation annotation, Class<? extends Annotation> scope) {
BindingJob job = new ProviderBindingJob(scope, provider, annotation, interf.getName());
if (!tracer.contains(job)) {
LinkedBindingBuilder<T> builder;
synchronized (_binder) {
builder = _binder.bind(interf);
if (annotation != null) {
builder = ((AnnotatedBindingBuilder<T>) builder).annotatedWith(annotation);
}
ScopedBindingBuilder scopedBuilder = builder.toProvider(provider);
if (scope != null) {
scopedBuilder.in(scope);
}
}
tracer.add(job);
} else {
if (_logger.isLoggable(Level.INFO)) {
_logger.log(Level.INFO, "Ignoring BindingJob \"" + job.toString()
+ "\", because it was already bound.", new Exception());
} else if (_logger.isLoggable(Level.WARNING)) {
_logger.log(Level.WARNING, "Ignoring BindingJob \"" + job.toString()
+ "\", because it was already bound.");
}
}
}
protected <T, V extends T> void bindInstance(V implementation, Class<T> interf,
Annotation annotation, Class<? extends Annotation> scope) {
BindingJob job = new InstanceBindingJob(scope, annotation, implementation.getClass().getName(), interf.getName());
if (!tracer.contains(job)) {
LinkedBindingBuilder<T> builder;
synchronized (_binder) {
builder = _binder.bind(interf);
if (annotation != null) {
builder = ((AnnotatedBindingBuilder<T>) builder).annotatedWith(annotation);
}
builder.toInstance(implementation);
}
tracer.add(job);
} else {
if (_logger.isLoggable(Level.INFO)) {
_logger.log(Level.INFO, "Ignoring BindingJob \"" + job.toString()
+ "\", because it was already bound.", new Exception());
} else if (_logger.isLoggable(Level.WARNING)) {
_logger.log(Level.WARNING, "Ignoring BindingJob \"" + job.toString()
+ "\", because it was already bound.");
}
}
}
protected void bindConstant(String value, Annotation annotation) {
BindingJob job = new ConstantBindingJob(annotation, value.getClass().getName());
if (!tracer.contains(job)) {
synchronized (_binder) {
_binder.bindConstant().annotatedWith(annotation).to(value);
}
tracer.add(job);
} else {
if (_logger.isLoggable(Level.INFO)) {
_logger.log(Level.INFO, "Ignoring BindingJob \"" + job.toString()
+ "\", because it was already bound.", new Exception());
} else if (_logger.isLoggable(Level.WARNING)) {
_logger.log(Level.WARNING, "Ignoring BindingJob \"" + job.toString()
+ "\", because it was already bound.");
}
}
}
protected <T, V extends T> void bind(Class<V> implementationClass, Class<T> interf,
Annotation annotation, Class<? extends Annotation> scope) {
BindingJob job = new InterfaceBindingJob(scope, annotation, implementationClass.getName(),interf.getName());
if (!tracer.contains(job)) {
LinkedBindingBuilder<T> builder;
synchronized (_binder) {
builder = _binder.bind(interf);
if (annotation != null) {
builder = ((AnnotatedBindingBuilder<T>) builder).annotatedWith(annotation);
}
ScopedBindingBuilder scopedBindingBuilder = builder.to(implementationClass);
if (scope != null) {
scopedBindingBuilder.in(scope);
}
}
tracer.add(job);
} else {
if (_logger.isLoggable(Level.FINE)) {
_logger.log(Level.FINE, "Ignoring BindingJob \"" + job.toString()
+ "\", because it was already bound.", new Exception("Ignoring BindingJob \"" + job.toString()
+ "\", because it was already bound."));
} else if (_logger.isLoggable(Level.INFO)) {
_logger.log(Level.INFO, "Ignoring BindingJob \"" + job.toString()
+ "\", because it was already bound.");
}
}
}
protected <T> void bind(Class<T> implementationClass, Annotation annotation, Class<? extends Annotation> scope) {
BindingJob job = new ImplementationBindingJob(scope, annotation, implementationClass.getName());
if (!tracer.contains(job)) {
LinkedBindingBuilder<T> builder;
synchronized (_binder) {
builder = _binder.bind(implementationClass);
if (annotation != null) {
builder = ((AnnotatedBindingBuilder<T>) builder).annotatedWith(annotation);
}
if (scope != null) {
builder.in(scope);
}
}
tracer.add(job);
} else {
if (_logger.isLoggable(Level.INFO)) {
_logger.log(Level.INFO, "Ignoring BindingJob \"" + job.toString()
+ "\", because it was already bound.", new Exception());
} else if (_logger.isLoggable(Level.WARNING)) {
_logger.log(Level.WARNING, "Ignoring BindingJob \"" + job.toString()
+ "\", because it was already bound.");
}
}
}
}