package org.nnsoft.guice.autobind.scanner.features; /* * Copyright 2012 The 99 Software Foundation * * 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. */ import static java.lang.String.format; import static java.util.logging.Level.FINE; import static java.util.logging.Level.INFO; import static java.util.logging.Logger.getLogger; 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.Logger; import javax.inject.Inject; import javax.inject.Provider; import org.nnsoft.guice.autobind.install.BindingStage; import org.nnsoft.guice.autobind.install.BindingTracer; import org.nnsoft.guice.autobind.install.InstallationContext; import org.nnsoft.guice.autobind.install.InstallationContext.StageableRequest; import org.nnsoft.guice.autobind.install.bindjob.BindingJob; import org.nnsoft.guice.autobind.install.bindjob.ConstantBindingJob; import org.nnsoft.guice.autobind.install.bindjob.ImplementationBindingJob; import org.nnsoft.guice.autobind.install.bindjob.InstanceBindingJob; import org.nnsoft.guice.autobind.install.bindjob.InterfaceBindingJob; import org.nnsoft.guice.autobind.install.bindjob.ProviderBindingJob; import org.nnsoft.guice.autobind.scanner.ScannerModule; import org.nnsoft.guice.autobind.utils.VariableResolver; 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; /** * 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}. */ public abstract class BindingScannerFeature implements ScannerFeature { private final Logger _logger = getLogger( getClass().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 { String message = format( "Ignoring BindingJob \"%s\", because it was already bound.", job ); if ( _logger.isLoggable( FINE ) ) { _logger.log( FINE, message, new Exception( message ) ); } else if ( _logger.isLoggable( INFO ) ) { _logger.log( INFO, message ); } } } 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 { String message = format( "Ignoring BindingJob \"%s\", because it was already bound.", job ); if ( _logger.isLoggable( FINE ) ) { _logger.log( FINE, message, new Exception( message ) ); } else if ( _logger.isLoggable( INFO ) ) { _logger.log( INFO, message ); } } } 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 { String message = format( "Ignoring BindingJob \"%s\", because it was already bound.", job ); if ( _logger.isLoggable( FINE ) ) { _logger.log( FINE, message, new Exception( message ) ); } else if ( _logger.isLoggable( INFO ) ) { _logger.log( INFO, message ); } } } 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 { String message = format( "Ignoring BindingJob \"%s\", because it was already bound.", job ); if ( _logger.isLoggable( FINE ) ) { _logger.log( FINE, message, new Exception( message ) ); } else if ( _logger.isLoggable( INFO ) ) { _logger.log( INFO, message ); } } } 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 { String message = format( "Ignoring BindingJob \"%s\", because it was already bound.", job ); if ( _logger.isLoggable( FINE ) ) { _logger.log( FINE, message, new Exception( message ) ); } else if ( _logger.isLoggable( INFO ) ) { _logger.log( INFO, message ); } } } 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 { String message = format( "Ignoring BindingJob \"%s\", because it was already bound.", job ); if ( _logger.isLoggable( FINE ) ) { _logger.log( FINE, message, new Exception( message ) ); } else if ( _logger.isLoggable( INFO ) ) { _logger.log( INFO, message ); } } } }