
org.ow2.mind.inject.AbstractMindModule Maven / Gradle / Ivy
The newest version!
/**
* Copyright (C) 2010 STMicroelectronics
*
* This file is part of "Mind Compiler" is free software: you can redistribute
* it and/or modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*
* Contact: [email protected]
*
* Authors: Matthieu Leclercq
* Contributors:
*/
package org.ow2.mind.inject;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import com.google.inject.AbstractModule;
import com.google.inject.Binder;
import com.google.inject.Key;
import com.google.inject.Provider;
import com.google.inject.Scope;
import com.google.inject.TypeLiteral;
import com.google.inject.binder.AnnotatedBindingBuilder;
import com.google.inject.binder.LinkedBindingBuilder;
import com.google.inject.binder.ScopedBindingBuilder;
import com.google.inject.spi.Message;
import com.google.inject.util.Providers;
/**
* Extends default Google Guice {@link AbstractModule} and adds API to create
* delegation chains. A delegation chain is a list of objects where each object
* implements the same interface and may delegate its processing to the next
* object in the chain. To do so, each object in the chain (expect the last one)
* contains a field that is injected to the reference of the next object in the
* chain. This field must be annotated with the {@link InjectDelegate}
* annotation.
* This class provides an extension to the Google Guide Binding EDSL to
* define such delegation chain. For example :
*
*
* bind(MyService.class).toChainStartingWith(MyFirstDelegate.class)
* .followedBy(MySecondDelegate.class).endingWith(MyServiceImpl.class);
*
*
* Moreover, this {@link AbstractModule} provides a standard implementation of
* the {@link AbstractModule#configure()} method that calls (using reflection)
* every non-static methods whose name starts with configure
and
* that has no parameter. So sub-classes can implement the configuration logic
* in several configure methods which can then be overridden
* independently.
*/
public abstract class AbstractMindModule extends AbstractModule {
private static final String CONFIGURE_METHOD_PREFIX = "configure";
@Override
protected void configure() {
Class> clazz = this.getClass();
final Set calledMeths = new HashSet();
do {
for (final Method meth : clazz.getDeclaredMethods()) {
if (meth.getName().startsWith(CONFIGURE_METHOD_PREFIX)
&& meth.getName().length() > CONFIGURE_METHOD_PREFIX.length()
&& meth.getParameterTypes().length == 0
&& calledMeths.add(meth.getName())) {
try {
meth.setAccessible(true);
meth.invoke(this);
} catch (final IllegalArgumentException e) {
throw new RuntimeException(e);
} catch (final IllegalAccessException e) {
throw new RuntimeException(e);
} catch (final InvocationTargetException e) {
throw new RuntimeException(e);
}
}
}
} while ((clazz = clazz.getSuperclass()) != null);
}
@Override
protected AnnotatedBindingChainBuilder bind(final Class clazz) {
final Binder binder = binder().skipSources(AbstractMindModule.class);
return new AnnotatedBindingChainBuilderImpl(binder, clazz,
binder.bind(clazz));
}
@Override
protected LinkedBindingChainBuilder bind(final Key key) {
return new LinkedBindingChainBuilderImpl(binder().skipSources(
AbstractMindModule.class), key.getTypeLiteral().getRawType(),
super.bind(key));
}
static class AnnotatedBindingChainBuilderImpl
extends
LinkedBindingChainBuilderImpl
implements
AnnotatedBindingChainBuilder {
final AnnotatedBindingBuilder delegate;
AnnotatedBindingChainBuilderImpl(final Binder binder,
final Class bindType, final AnnotatedBindingBuilder delegate) {
super(binder, bindType, delegate);
this.delegate = delegate;
}
public LinkedBindingChainBuilder annotatedWith(
final Class extends Annotation> annotationType) {
delegate.annotatedWith(annotationType);
return this;
}
public LinkedBindingChainBuilder annotatedWith(
final Annotation annotation) {
delegate.annotatedWith(annotation);
return this;
}
}
static class LinkedBindingChainBuilderImpl
implements
LinkedBindingChainBuilder {
final Binder binder;
final LinkedBindingBuilder delegate;
final Class super T> bindType;
LinkedBindingChainBuilderImpl(final Binder binder,
final Class super T> bindType, final LinkedBindingBuilder delegate) {
this.binder = binder;
this.bindType = bindType;
this.delegate = delegate;
}
public ScopedBindingBuilder to(final Class extends T> implementation) {
return delegate.to(implementation);
}
public ScopedBindingBuilder to(final TypeLiteral extends T> implementation) {
return delegate.to(implementation);
}
public ScopedBindingBuilder to(final Key extends T> targetKey) {
return delegate.to(targetKey);
}
public void toInstance(final T instance) {
delegate.toInstance(instance);
}
public ScopedBindingBuilder toProvider(final Provider extends T> provider) {
return delegate.toProvider(provider);
}
public ScopedBindingBuilder toProvider(
final Class extends Provider extends T>> providerType) {
return delegate.toProvider(providerType);
}
public ScopedBindingBuilder toProvider(
final Key extends Provider extends T>> providerKey) {
return delegate.toProvider(providerKey);
}
public void in(final Class extends Annotation> scopeAnnotation) {
delegate.in(scopeAnnotation);
}
public void in(final Scope scope) {
delegate.in(scope);
}
public void asEagerSingleton() {
delegate.asEagerSingleton();
}
public ChainBuilder toChainStartingWith(final Class extends T> clazz) {
return new ChainBuilderImpl(binder, bindType, delegate, clazz);
}
public ChainBuilder toChainStartingWith(
final Provider extends T> provider) {
return new ChainBuilderImpl(binder, bindType, delegate, provider);
}
public ChainBuilder toChainStartingWith(final T instance) {
return new ChainBuilderImpl(binder, bindType, delegate, instance);
}
}
static class ChainBuilderImpl implements ChainBuilder {
final ScopedBindingBuilder delegate;
final ChainProvider chainProvider;
final Binder binder;
ChainBuilderImpl(final Binder binder, final Class super T> chainType,
final LinkedBindingBuilder delegate,
final Provider extends T> firstProvider) {
this.binder = binder;
this.chainProvider = new ChainProvider(chainType);
chainProvider.add(firstProvider);
this.delegate = delegate.toProvider(chainProvider);
}
ChainBuilderImpl(final Binder binder, final Class super T> chainType,
final LinkedBindingBuilder delegate,
final Class extends T> firstClass) {
this(binder, chainType, delegate, binder.getProvider(firstClass));
checkDelegateClass(firstClass);
}
ChainBuilderImpl(final Binder binder, final Class super T> chainType,
final LinkedBindingBuilder delegate, final T firstInstance) {
this(binder, chainType, delegate, Providers.of(firstInstance));
checkDelegateClass(firstInstance.getClass());
}
void checkDelegateClass(final Class> elemClass) {
boolean delegateFound = false;
Class> clazz = elemClass;
topLoop : do {
for (final Field f : clazz.getDeclaredFields()) {
if (f.getAnnotation(InjectDelegate.class) != null
&& f.getType().isAssignableFrom(chainProvider.chainType)) {
delegateFound = true;
break topLoop;
}
}
} while ((clazz = clazz.getSuperclass()) != null);
if (!delegateFound) {
binder.addError(new Message(elemClass,
"Invalid delegate class : the class does not have a field of type "
+ chainProvider.chainType + " annotated with @InjectDelegate"));
}
}
public ChainBuilder followedBy(final Class extends T> elemClass) {
checkDelegateClass(elemClass);
chainProvider.add(binder.getProvider(elemClass));
return this;
}
public ChainBuilder followedBy(final Provider extends T> elemProvider) {
chainProvider.add(elemProvider);
return this;
}
public ChainBuilder followedBy(final T elem) {
checkDelegateClass(elem.getClass());
chainProvider.add(Providers.of(elem));
return this;
}
public ChainBuilder followedBy(final Key elemKey) {
checkDelegateClass(elemKey.getTypeLiteral().getRawType());
chainProvider.add(binder.getProvider(elemKey));
return this;
}
public ScopedBindingBuilder endingWith(final Class extends T> elemClass) {
chainProvider.add(binder.getProvider(elemClass));
return delegate;
}
public ScopedBindingBuilder endingWith(final Provider elemProvider) {
chainProvider.add(elemProvider);
return delegate;
}
public ScopedBindingBuilder endingWith(final T elem) {
chainProvider.add(Providers.of(elem));
return delegate;
}
public ScopedBindingBuilder endingWith(final Key elemKey) {
chainProvider.add(binder.getProvider(elemKey));
return delegate;
}
public void in(final Class extends Annotation> scopeAnnotation) {
delegate.in(scopeAnnotation);
}
public void in(final Scope scope) {
delegate.in(scope);
}
public void asEagerSingleton() {
delegate.asEagerSingleton();
}
}
protected static class ChainProvider implements Provider {
final Class super T> chainType;
List> providers = new ArrayList>();
T head = null;
ChainProvider(final Class super T> chainType) {
this.chainType = chainType;
}
public T get() {
if (head == null) {
T prevElement = null;
for (final Provider extends T> provider : providers) {
final T elem = provider.get();
if (prevElement != null) {
// inject delegate
Class> clazz = prevElement.getClass();
do {
for (final Field f : clazz.getDeclaredFields()) {
if (f.getAnnotation(InjectDelegate.class) != null
&& f.getType().isAssignableFrom(chainType)) {
f.setAccessible(true);
try {
f.set(prevElement, elem);
} catch (final IllegalArgumentException e) {
throw new RuntimeException(e);
} catch (final IllegalAccessException e) {
throw new RuntimeException(e);
}
}
}
} while ((clazz = clazz.getSuperclass()) != null);
} else {
head = elem;
}
prevElement = elem;
}
}
return head;
}
void add(final Provider extends T> provider) {
providers.add(provider);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy