/**
 * Copyright (c) 2009 Sonatype, Inc. All rights reserved.
 *
 * This program is licensed to you under the Apache License Version 2.0,
 * and you may not use this file except in compliance with the Apache License Version 2.0.
 * You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0.
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the Apache License Version 2.0 is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
 */
package org.sonatype.guice.plexus.binders;

import java.lang.annotation.Annotation;

import org.codehaus.plexus.component.annotations.Component;
import org.sonatype.guice.bean.binders.QualifiedTypeBinder;
import org.sonatype.guice.bean.reflect.DeferredClass;
import org.sonatype.guice.bean.reflect.LoadedClass;
import org.sonatype.guice.bean.scanners.QualifiedTypeListener;
import org.sonatype.guice.plexus.config.Roles;
import org.sonatype.guice.plexus.config.Strategies;
import org.sonatype.guice.plexus.scanners.PlexusTypeListener;

import com.google.inject.Binder;
import com.google.inject.Key;
import com.google.inject.Scopes;
import com.google.inject.binder.ScopedBindingBuilder;

public final class PlexusTypeBinder
    implements PlexusTypeListener
{
    // ----------------------------------------------------------------------
    // Implementation fields
    // ----------------------------------------------------------------------

    private final Binder guiceBinder;

    private final QualifiedTypeListener qualifiedTypeBinder;

    // ----------------------------------------------------------------------
    // Constructors
    // ----------------------------------------------------------------------

    public PlexusTypeBinder( final Binder binder )
    {
        guiceBinder = binder;

        qualifiedTypeBinder = new QualifiedTypeBinder( binder );
    }

    // ----------------------------------------------------------------------
    // Public methods
    // ----------------------------------------------------------------------

    public void hear( final Annotation qualifier, final Class<?> qualifiedType )
    {
        qualifiedTypeBinder.hear( qualifier, qualifiedType );
    }

    @SuppressWarnings( "unchecked" )
    public void hear( final Component component, final DeferredClass<?> clazz )
    {
        final Key roleKey = Roles.componentKey( component );
        final String strategy = component.instantiationStrategy();
        final ScopedBindingBuilder sbb;

        final Binder binder = componentBinder( component.description() );

        // simple case when role and implementation are identical
        if ( component.role().getName().equals( clazz.getName() ) )
        {
            if ( roleKey.getAnnotation() != null )
            {
                // wire annotated role to the plain role type
                sbb = binder.bind( roleKey ).to( component.role() );
            }
            else
            {
                // simple wire to self
                sbb = binder.bind( roleKey );
            }
        }
        else if ( Strategies.LOAD_ON_START.equals( strategy ) || clazz instanceof LoadedClass<?> )
        {
            sbb = binder.bind( roleKey ).to( clazz.load() ); // no need to defer
        }
        else
        {
            sbb = binder.bind( roleKey ).toProvider( clazz.asProvider() );
        }

        if ( Strategies.LOAD_ON_START.equals( strategy ) )
        {
            sbb.asEagerSingleton();
        }
        else if ( !Strategies.PER_LOOKUP.equals( strategy ) )
        {
            sbb.in( Scopes.SINGLETON );
        }
    }

    // ----------------------------------------------------------------------
    // Implementation methods
    // ----------------------------------------------------------------------

    private Binder componentBinder( final String source )
    {
        return null != source && source.length() > 0 ? guiceBinder.withSource( source ) : guiceBinder;
    }
}

@@ -2326,32 +2326,225 @@
 iedType )%0A    %7B%0A
+        if ( Component.class == qualifier.annotationType() )%0A        %7B%0A            hear( (Component) qualifier, new LoadedClass%3CObject%3E( qualifiedType ) );%0A        %7D%0A        else%0A        %7B%0A    
         qualifie
@@ -2585,24 +2585,34 @@
 fiedType );%0A
+        %7D%0A
     %7D%0A%0A    @
@@ -2853,24 +2853,69 @@
 Strategy();%0A
+        final Class role = component.role();%0A
         fina
@@ -3030,21 +3030,22 @@
     // s
-imple
+pecial
  case wh
@@ -3052,19 +3052,22 @@
 en role 
-and
+is the
  impleme
@@ -3077,22 +3077,8 @@
 tion
- are identical
 %0A   
@@ -3087,32 +3087,20 @@
    if ( 
-component.
 role
-()
 .getName
@@ -3209,70 +3209,8 @@
   %7B%0A
-                // wire annotated role to the plain role type%0A
     
@@ -3254,32 +3254,20 @@
 y ).to( 
-component.
 role
-()
  );%0A    
@@ -3311,47 +3311,8 @@
   %7B%0A
-                // simple wire to self%0A
     

Add the ability to process @Component types as qualifiers