All Downloads are FREE. Search and download functionalities are using the official Maven repository.

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 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 bindType; LinkedBindingChainBuilderImpl(final Binder binder, final Class bindType, final LinkedBindingBuilder delegate) { this.binder = binder; this.bindType = bindType; this.delegate = delegate; } public ScopedBindingBuilder to(final Class implementation) { return delegate.to(implementation); } public ScopedBindingBuilder to(final TypeLiteral implementation) { return delegate.to(implementation); } public ScopedBindingBuilder to(final Key targetKey) { return delegate.to(targetKey); } public void toInstance(final T instance) { delegate.toInstance(instance); } public ScopedBindingBuilder toProvider(final Provider provider) { return delegate.toProvider(provider); } public ScopedBindingBuilder toProvider( final Class> providerType) { return delegate.toProvider(providerType); } public ScopedBindingBuilder toProvider( final Key> providerKey) { return delegate.toProvider(providerKey); } public void in(final Class scopeAnnotation) { delegate.in(scopeAnnotation); } public void in(final Scope scope) { delegate.in(scope); } public void asEagerSingleton() { delegate.asEagerSingleton(); } public ChainBuilder toChainStartingWith(final Class clazz) { return new ChainBuilderImpl(binder, bindType, delegate, clazz); } public ChainBuilder toChainStartingWith( final Provider 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 chainType, final LinkedBindingBuilder delegate, final Provider firstProvider) { this.binder = binder; this.chainProvider = new ChainProvider(chainType); chainProvider.add(firstProvider); this.delegate = delegate.toProvider(chainProvider); } ChainBuilderImpl(final Binder binder, final Class chainType, final LinkedBindingBuilder delegate, final Class firstClass) { this(binder, chainType, delegate, binder.getProvider(firstClass)); checkDelegateClass(firstClass); } ChainBuilderImpl(final Binder binder, final Class 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 elemClass) { checkDelegateClass(elemClass); chainProvider.add(binder.getProvider(elemClass)); return this; } public ChainBuilder followedBy(final Provider 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 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 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 chainType; List> providers = new ArrayList>(); T head = null; ChainProvider(final Class chainType) { this.chainType = chainType; } public T get() { if (head == null) { T prevElement = null; for (final Provider 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 provider) { providers.add(provider); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy