component selection still not working...at least, in tests. Needs more work
git-svn-id: https://svn.apache.org/repos/asf/maven/sandbox/trunk/mae@1159745 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/mae-api/src/main/java/org/apache/maven/mae/internal/container/ComponentKey.java b/mae-api/src/main/java/org/apache/maven/mae/internal/container/ComponentKey.java
index 5630ce3..8e24258 100644
--- a/mae-api/src/main/java/org/apache/maven/mae/internal/container/ComponentKey.java
+++ b/mae-api/src/main/java/org/apache/maven/mae/internal/container/ComponentKey.java
@@ -21,6 +21,14 @@
import static org.codehaus.plexus.util.StringUtils.isBlank;
+import java.lang.reflect.Field;
+
+import org.codehaus.plexus.component.annotations.Component;
+import org.codehaus.plexus.component.annotations.Requirement;
+import org.sonatype.guice.plexus.config.Roles;
+
+import com.google.inject.Key;
+
public class ComponentKey<T>
{
@@ -44,6 +52,35 @@
hint = DEFAULT_HINT;
}
+ @SuppressWarnings( "unchecked" )
+ public ComponentKey( final Component comp )
+ {
+ roleClass = (Class<T>) comp.role();
+
+ String h = comp.hint();
+ hint = ( isBlank( h ) || DEFAULT_HINT.equals( h ) ? DEFAULT_HINT : h );
+ }
+
+ @SuppressWarnings( { "unchecked", "rawtypes" } )
+ public ComponentKey( final Requirement req, final Field field )
+ {
+ if ( req.hints() != null && req.hints().length > 0 )
+ {
+ throw new IllegalArgumentException( "Cannot construct ComponentKey for requirement listing multiple hints." );
+ }
+
+ Class role = req.role();
+ if ( role == null || role.equals( Object.class ) )
+ {
+ role = field.getType();
+ }
+
+ roleClass = role;
+
+ String h = req.hint();
+ hint = ( isBlank( h ) || DEFAULT_HINT.equals( h ) ? DEFAULT_HINT : h );
+ }
+
public String getRole()
{
return roleClass.getName();
@@ -56,7 +93,22 @@
public String key()
{
- return roleClass + ( DEFAULT_HINT.equals( hint ) ? "" : "#" + hint );
+ return roleClass.getName() + ( DEFAULT_HINT.equals( hint ) ? "" : "#" + hint );
+ }
+
+ public Key<T> componentKey()
+ {
+ return Roles.componentKey( roleClass, hint );
+ }
+
+ public Key<T> literalComponentKey()
+ {
+ return isLiteral() ? componentKey() : Roles.componentKey( roleClass, hint + LITERAL_SUFFIX );
+ }
+
+ public Key<T> rawComponentKey()
+ {
+ return Roles.componentKey( roleClass, getLiteralHint( hint ) );
}
@Override
@@ -115,6 +167,11 @@
return instance == null ? null : roleClass.cast( instance );
}
+ public boolean isLiteral()
+ {
+ return isLiteral( hint );
+ }
+
public static boolean isLiteral( final String value )
{
return value != null && value.length() > 1 && value.endsWith( LITERAL_SUFFIX );
diff --git a/mae-api/src/main/java/org/apache/maven/mae/internal/container/ComponentSelector.java b/mae-api/src/main/java/org/apache/maven/mae/internal/container/ComponentSelector.java
index 663cab4..cff1227 100644
--- a/mae-api/src/main/java/org/apache/maven/mae/internal/container/ComponentSelector.java
+++ b/mae-api/src/main/java/org/apache/maven/mae/internal/container/ComponentSelector.java
@@ -60,6 +60,11 @@
return remappedComponentHints.isEmpty();
}
+ public boolean hasOverride( final ComponentKey<?> key )
+ {
+ return remappedComponentHints.containsKey( key );
+ }
+
public <T> boolean hasOverride( final Class<T> role, final String hint )
{
final ComponentKey<T> check = new ComponentKey<T>( role, hint );
@@ -121,4 +126,10 @@
return (ComponentKey<T>) remappedComponentHints.get( new ComponentKey<T>( role, hint ) );
}
+ @SuppressWarnings( "unchecked" )
+ public <T> ComponentKey<T> getOverride( final ComponentKey<T> key )
+ {
+ return (ComponentKey<T>) remappedComponentHints.get( key );
+ }
+
}
diff --git a/mae-booter/src/main/java/org/apache/maven/mae/boot/embed/ComponentSelectionModule.java b/mae-booter/src/main/java/org/apache/maven/mae/boot/embed/ComponentSelectionModule.java
index 1f6a6e8..35c3607 100644
--- a/mae-booter/src/main/java/org/apache/maven/mae/boot/embed/ComponentSelectionModule.java
+++ b/mae-booter/src/main/java/org/apache/maven/mae/boot/embed/ComponentSelectionModule.java
@@ -1,23 +1,26 @@
package org.apache.maven.mae.boot.embed;
import java.lang.reflect.Field;
-import java.util.ArrayList;
-import java.util.List;
+import java.security.PrivilegedAction;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
import org.apache.maven.mae.internal.container.ComponentKey;
import org.apache.maven.mae.internal.container.ComponentSelector;
+import org.codehaus.plexus.component.annotations.Component;
import org.codehaus.plexus.component.annotations.Requirement;
-import org.sonatype.guice.plexus.config.Hints;
-import org.sonatype.guice.plexus.config.Roles;
import com.google.inject.Binder;
-import com.google.inject.Inject;
-import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.MembersInjector;
import com.google.inject.Module;
+import com.google.inject.Provider;
import com.google.inject.TypeLiteral;
import com.google.inject.matcher.Matchers;
+import com.google.inject.spi.Dependency;
+import com.google.inject.spi.InjectionListener;
+import com.google.inject.spi.InjectionPoint;
import com.google.inject.spi.TypeEncounter;
import com.google.inject.spi.TypeListener;
@@ -36,7 +39,43 @@
@Override
public void configure( final Binder binder )
{
- binder.bindListener( Matchers.any(), new ComponentSelectingListener( selector ) );
+ // binder.bindListener( Matchers.any(), new SysoutTypeListener() );
+ binder.bindListener( Matchers.any(), new ComponentSelectingListener( selector, binder ) );
+ }
+
+ @SuppressWarnings( "unused" )
+ private static final class SysoutTypeListener
+ implements TypeListener
+ {
+
+ @Override
+ public <I> void hear( final TypeLiteral<I> type, final TypeEncounter<I> encounter )
+ {
+ Set<InjectionPoint> injectionPoints = InjectionPoint.forInstanceMethodsAndFields( type.getRawType() );
+ if ( injectionPoints != null && !injectionPoints.isEmpty() )
+ {
+ System.out.println( type.getRawType().getName() );
+
+ for ( InjectionPoint ip : injectionPoints )
+ {
+ Dependency<?> dep = ip.getDependencies().get( 0 );
+ System.out.printf( "%s --> %s", ip.getMember(), dep.getKey() );
+ }
+ }
+
+ Component comp = type.getRawType().getAnnotation( Component.class );
+ if ( comp != null )
+ {
+ ComponentKey<I> found = new ComponentKey<I>( comp );
+
+ System.out.printf( "%s [Provider: %s]\n", found, encounter.getProvider( found.componentKey() ) );
+ }
+ else
+ {
+ System.out.printf( "RAW: %s\n", type.getRawType().getName() );
+ }
+ }
+
}
private static final class ComponentSelectingListener
@@ -45,93 +84,155 @@
private final ComponentSelector selector;
- public ComponentSelectingListener( final ComponentSelector selector )
+ private final Binder binder;
+
+ public ComponentSelectingListener( final ComponentSelector selector, final Binder binder )
{
this.selector = selector;
+ this.binder = binder;
}
+ @SuppressWarnings( { "unchecked", "rawtypes" } )
@Override
public <I> void hear( final TypeLiteral<I> type, final TypeEncounter<I> encounter )
{
- List<Field> requirementFields = new ArrayList<Field>();
+ Map<Field, Provider<?>> requirementFields = new HashMap<Field, Provider<?>>();
+
+ // Component comp = type.getRawType().getAnnotation( Component.class );
+ // Set<InjectionPoint> injectionPoints = InjectionPoint.forInstanceMethodsAndFields( type.getRawType() );
+ // if ( comp != null || ( injectionPoints != null && !injectionPoints.isEmpty() ) )
+ // {
+ // encounter.register( null )
+ // }
+
for ( Field field : type.getRawType().getDeclaredFields() )
{
- if ( field.getAnnotation( Requirement.class ) != null )
+ Requirement req = field.getAnnotation( Requirement.class );
+ if ( req != null )
{
- requirementFields.add( field );
+ // FIXME: Collections!
+ if ( !field.getType().equals( req.role() ) )
+ {
+ // System.out.printf( "Found collection? %s\n", field );
+ }
+ else
+ {
+ ComponentKey key = new ComponentKey( req, field );
+
+ Key componentKey = key.componentKey();
+ if ( key.isLiteral() )
+ {
+ componentKey = key.rawComponentKey();
+ // System.out.printf( "%s ------> %s\n", field, componentKey );
+ }
+ else if ( selector.hasOverride( key ) )
+ {
+ binder.bind( key.literalComponentKey() ).toProvider( encounter.getProvider( key.componentKey() ) );
+ componentKey = selector.getOverride( key ).componentKey();
+ // System.out.printf( "%s ------> %s\n", field, componentKey );
+ }
+
+ requirementFields.put( field, encounter.getProvider( componentKey ) );
+ }
}
}
if ( !requirementFields.isEmpty() )
{
- encounter.register( new ComponentSelectionInjector<I>( selector, requirementFields ) );
+ final ComponentSelectionInjector<I> injector = new ComponentSelectionInjector<I>( requirementFields );
+ encounter.register( new MembersInjector<I>()
+ {
+ @Override
+ public void injectMembers( final I instance )
+ {
+ injector.inject( instance );
+ }
+ } );
+
+ encounter.register( new InjectionListener<I>()
+ {
+ @Override
+ public void afterInjection( final I instance )
+ {
+ injector.inject( instance );
+ }
+ } );
}
}
}
private static final class ComponentSelectionInjector<T>
- implements MembersInjector<T>
{
- // FIXME: This is NOT being injected!!
- @Inject
- private Injector injector;
+ private final Map<Field, Provider<?>> fields;
- private final ComponentSelector selector;
-
- private final List<Field> fields;
-
- public ComponentSelectionInjector( final ComponentSelector selector, final List<Field> fields )
+ public ComponentSelectionInjector( final Map<Field, Provider<?>> fields )
{
- this.selector = selector;
this.fields = fields;
}
- @SuppressWarnings( { "rawtypes", "unchecked" } )
- @Override
- public void injectMembers( final T instance )
+ public void inject( final T instance )
{
- for ( Field field : fields )
+ for ( Map.Entry<Field, Provider<?>> entry : fields.entrySet() )
{
- Requirement req = field.getAnnotation( Requirement.class );
- Class role = req.role();
- if ( role == null )
+ Field field = entry.getKey();
+ Provider<?> provider = entry.getValue();
+ boolean acc = field.isAccessible();
+ if ( !acc )
{
- role = field.getType();
+ field.setAccessible( true );
}
- // FIXME: What about req.hints() ???
- String hint = req.hint();
- if ( hint == null )
+ try
{
- hint = Hints.DEFAULT_HINT;
+ Object value = provider.get();
+ System.out.printf( "Setting %s to: %s\n", field, value );
+ field.set( instance, value );
+ }
+ catch ( IllegalArgumentException e )
+ {
+ throw new RuntimeException( e );
+ }
+ catch ( IllegalAccessException e )
+ {
+ throw new RuntimeException( e );
+ }
+ finally
+ {
+ field.setAccessible( acc );
}
- ComponentKey key;
- if ( ComponentKey.isLiteral( hint ) )
- {
- key = new ComponentKey( role, ComponentKey.getLiteralHint( hint ) );
- }
- else if ( selector.hasOverride( role, hint ) )
- {
- key = selector.getOverride( role, hint );
- }
- else
- {
- key = new ComponentKey( role, hint );
- }
-
- set( field, instance, key );
+ // FieldSetter setter = new FieldSetter( entry.getKey(), entry.getValue(), instance );
+ // AccessController.doPrivileged( setter );
}
}
- @SuppressWarnings( { "rawtypes", "unchecked" } )
- private void set( final Field field, final Object instance, final ComponentKey key )
+ }
+
+ @SuppressWarnings( "unused" )
+ private static final class FieldSetter<T>
+ implements PrivilegedAction<T>
+ {
+
+ private final Field field;
+
+ private final Provider<?> provider;
+
+ private final T instance;
+
+ FieldSetter( final Field field, final Provider<?> provider, final T instance )
{
- Key componentKey = Roles.componentKey( key.getRoleClass(), key.getHint() );
- Object value = injector.getInstance( componentKey );
+ this.field = field;
+ this.provider = provider;
+ this.instance = instance;
+
+ }
+
+ @Override
+ public T run()
+ {
try
{
- field.set( instance, value );
+ field.set( instance, provider.get() );
}
catch ( IllegalArgumentException e )
{
@@ -141,6 +242,8 @@
{
throw new RuntimeException( e );
}
+
+ return null;
}
}
diff --git a/mae-booter/src/test/java/org/apache/maven/mae/internal/container/MAEApplicationTest.java b/mae-booter/src/test/java/org/apache/maven/mae/internal/container/MAEApplicationTest.java
index 457c6ee..8e1a66b 100644
--- a/mae-booter/src/test/java/org/apache/maven/mae/internal/container/MAEApplicationTest.java
+++ b/mae-booter/src/test/java/org/apache/maven/mae/internal/container/MAEApplicationTest.java
@@ -19,6 +19,7 @@
package org.apache.maven.mae.internal.container;
+import static org.hamcrest.CoreMatchers.instanceOf;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.junit.Assert.assertThat;
@@ -28,6 +29,9 @@
import org.apache.maven.mae.boot.embed.MAEEmbedderBuilder;
import org.apache.maven.mae.internal.container.fixture.ContainerOwner;
import org.apache.maven.mae.internal.container.fixture.DefaultSingletonOwner;
+import org.apache.maven.mae.internal.container.fixture.NonSimplePart;
+import org.apache.maven.mae.internal.container.fixture.Part;
+import org.apache.maven.mae.internal.container.fixture.SimplePart;
import org.apache.maven.mae.internal.container.fixture.SingletonLiteralOwner;
import org.apache.maven.mae.internal.container.fixture.SingletonOwner;
import org.junit.Test;
@@ -91,7 +95,10 @@
throws Throwable
{
ContainerOwner owner = new ContainerOwner();
- new TestApplication().load();
+ new TestApplication().withInstance( owner ).load();
+
+ assertThat( owner.container, notNullValue() );
+
final DefaultSingletonOwner single = owner.container.lookup( DefaultSingletonOwner.class );
assertThat( single.singleton(), notNullValue() );
@@ -102,21 +109,47 @@
throws Throwable
{
ContainerOwner owner = new ContainerOwner();
- new TestApplication().load();
+ new TestApplication().withInstance( owner ).load();
+
+ assertThat( owner.container, notNullValue() );
+
final SingletonOwner single = owner.container.lookup( SingletonOwner.class );
assertThat( single.singleton(), notNullValue() );
}
@Test
+ public void singletonSelectedRequirement()
+ throws Throwable
+ {
+ ContainerOwner owner = new ContainerOwner();
+ new TestApplication().withInstance( owner ).withComponentSelection( new ComponentKey<Part>( Part.class,
+ "simple" ),
+ "non-simple" ).load();
+
+ assertThat( owner.container, notNullValue() );
+
+ final SingletonOwner single = owner.container.lookup( SingletonOwner.class );
+
+ assertThat( single.singleton(), notNullValue() );
+ assertThat( single.singleton(), instanceOf( NonSimplePart.class ) );
+ }
+
+ @Test
public void singletonLiteralRequirement()
throws Throwable
{
ContainerOwner owner = new ContainerOwner();
- new TestApplication().load();
+ new TestApplication().withInstance( owner ).withComponentSelection( new ComponentKey<Part>( Part.class,
+ "simple" ),
+ "non-simple" ).load();
+
+ assertThat( owner.container, notNullValue() );
+
final SingletonLiteralOwner single = owner.container.lookup( SingletonLiteralOwner.class );
assertThat( single.singletonLiteral(), notNullValue() );
+ assertThat( single.singletonLiteral(), instanceOf( SimplePart.class ) );
}
//
@@ -136,11 +169,25 @@
{
private final String name;
+ private ComponentSelector selector;
+
TestApplication()
{
name = new Exception().getStackTrace()[1].getMethodName();
}
+ public synchronized AbstractMAEApplication withComponentSelection( final ComponentKey<?> intercept,
+ final String newHint )
+ {
+ if ( selector == null )
+ {
+ selector = new ComponentSelector();
+ }
+
+ selector.setSelection( intercept, newHint );
+ return this;
+ }
+
public final TestApplication withInstance( final Object instance )
{
withComponentInstance( instance );
@@ -167,6 +214,12 @@
super.configureBuilder( builder );
}
+ @Override
+ public ComponentSelector getComponentSelector()
+ {
+ return selector;
+ }
+
}
}
diff --git a/mae-booter/src/test/java/org/apache/maven/mae/internal/container/fixture/MapOwner.java b/mae-booter/src/test/java/org/apache/maven/mae/internal/container/fixture/MapOwner.java
index eb7809c..141b979 100644
--- a/mae-booter/src/test/java/org/apache/maven/mae/internal/container/fixture/MapOwner.java
+++ b/mae-booter/src/test/java/org/apache/maven/mae/internal/container/fixture/MapOwner.java
@@ -28,10 +28,10 @@
public class MapOwner
{
- @Requirement( role = Child.class )
- private Map<String, Child> members;
+ @Requirement( role = SimplePart.class )
+ private Map<String, SimplePart> members;
- public Map<String, Child> members()
+ public Map<String, SimplePart> members()
{
return members;
}
diff --git a/mae-booter/src/test/java/org/apache/maven/mae/internal/container/fixture/Child.java b/mae-booter/src/test/java/org/apache/maven/mae/internal/container/fixture/NonSimplePart.java
similarity index 83%
copy from mae-booter/src/test/java/org/apache/maven/mae/internal/container/fixture/Child.java
copy to mae-booter/src/test/java/org/apache/maven/mae/internal/container/fixture/NonSimplePart.java
index e752bbe..ab6d34c 100644
--- a/mae-booter/src/test/java/org/apache/maven/mae/internal/container/fixture/Child.java
+++ b/mae-booter/src/test/java/org/apache/maven/mae/internal/container/fixture/NonSimplePart.java
@@ -21,8 +21,15 @@
import org.codehaus.plexus.component.annotations.Component;
-@Component( role = Child.class, hint = "simple" )
-public class Child
+@Component( role = Part.class, hint = "non-simple" )
+public class NonSimplePart
+ implements Part
{
+ @Override
+ public String getType()
+ {
+ return "simple";
+ }
+
}
diff --git a/mae-booter/src/test/java/org/apache/maven/mae/internal/container/fixture/Part.java b/mae-booter/src/test/java/org/apache/maven/mae/internal/container/fixture/Part.java
new file mode 100644
index 0000000..45624b6
--- /dev/null
+++ b/mae-booter/src/test/java/org/apache/maven/mae/internal/container/fixture/Part.java
@@ -0,0 +1,8 @@
+package org.apache.maven.mae.internal.container.fixture;
+
+public interface Part
+{
+
+ String getType();
+
+}
\ No newline at end of file
diff --git a/mae-booter/src/test/java/org/apache/maven/mae/internal/container/fixture/Child.java b/mae-booter/src/test/java/org/apache/maven/mae/internal/container/fixture/SimplePart.java
similarity index 84%
rename from mae-booter/src/test/java/org/apache/maven/mae/internal/container/fixture/Child.java
rename to mae-booter/src/test/java/org/apache/maven/mae/internal/container/fixture/SimplePart.java
index e752bbe..e8a52a1 100644
--- a/mae-booter/src/test/java/org/apache/maven/mae/internal/container/fixture/Child.java
+++ b/mae-booter/src/test/java/org/apache/maven/mae/internal/container/fixture/SimplePart.java
@@ -21,8 +21,15 @@
import org.codehaus.plexus.component.annotations.Component;
-@Component( role = Child.class, hint = "simple" )
-public class Child
+@Component( role = Part.class, hint = "simple" )
+public class SimplePart
+ implements Part
{
+ @Override
+ public String getType()
+ {
+ return "simple";
+ }
+
}
diff --git a/mae-booter/src/test/java/org/apache/maven/mae/internal/container/fixture/SingletonLiteralOwner.java b/mae-booter/src/test/java/org/apache/maven/mae/internal/container/fixture/SingletonLiteralOwner.java
index b984673..c2b330b 100644
--- a/mae-booter/src/test/java/org/apache/maven/mae/internal/container/fixture/SingletonLiteralOwner.java
+++ b/mae-booter/src/test/java/org/apache/maven/mae/internal/container/fixture/SingletonLiteralOwner.java
@@ -26,10 +26,10 @@
public class SingletonLiteralOwner
{
- @Requirement( role = Child.class, hint = "simple_" )
- private Child singletonLiteral;
+ @Requirement( role = Part.class, hint = "simple_" )
+ private Part singletonLiteral;
- public Child singletonLiteral()
+ public Part singletonLiteral()
{
return singletonLiteral;
}
diff --git a/mae-booter/src/test/java/org/apache/maven/mae/internal/container/fixture/SingletonOwner.java b/mae-booter/src/test/java/org/apache/maven/mae/internal/container/fixture/SingletonOwner.java
index 3c4ef93..4b6cc67 100644
--- a/mae-booter/src/test/java/org/apache/maven/mae/internal/container/fixture/SingletonOwner.java
+++ b/mae-booter/src/test/java/org/apache/maven/mae/internal/container/fixture/SingletonOwner.java
@@ -26,10 +26,10 @@
public class SingletonOwner
{
- @Requirement( role = Child.class, hint = "simple" )
- private Child singleton;
+ @Requirement( role = Part.class, hint = "simple" )
+ private Part singleton;
- public Child singleton()
+ public Part singleton()
{
return singleton;
}