Package org.apache.camel.guice.testing

Source Code of org.apache.camel.guice.testing.InjectorManager$TestModule

/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements.  See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
package org.apache.camel.guice.testing;
import java.lang.reflect.Modifier;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

import com.google.common.base.Preconditions;
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Module;

import org.apache.camel.guice.inject.Injectors;
import org.apache.camel.guice.support.CloseErrors;
import org.apache.camel.guice.support.CloseFailedException;
import org.apache.camel.guice.support.internal.CloseErrorsImpl;
import org.apache.camel.guice.util.CloseableScope;

/**
* Used to manage the injectors for the various injection points
*
*/
public class InjectorManager {
    private static final String NESTED_MODULE_CLASS = "TestModule";

    private Map<Object, Injector> injectors = new ConcurrentHashMap<Object, Injector>();
    private AtomicInteger initializeCounter = new AtomicInteger(0);
    private CloseableScope testScope = new CloseableScope(TestScoped.class);
    private CloseableScope classScope = new CloseableScope(ClassScoped.class);
   
    private boolean closeSingletonsAfterClasses;
    private boolean runFinalizer = true;
    private Class<? extends Module> moduleType;

    public void beforeClasses() {
        int counter = initializeCounter.incrementAndGet();
        if (counter > 1) {
            System.out.println("WARNING! Initialised more than once! Counter: " + counter);
        } else {
            if (runFinalizer) {
                Runtime.getRuntime().addShutdownHook(new Thread() {
                    @Override
                    public void run() {
                        try {
                            closeSingletons();
                        } catch (Throwable e) {
                            System.out.println("Failed to shut down Guice Singletons: " + e);
                            e.printStackTrace();
                        }
                    }
                });
            }
        }

    }

    /** Lets close all of the injectors we have created so far */
    public void afterClasses() throws CloseFailedException {
        Injector injector = injectors.get(moduleType);
        if (injector != null) {
            classScope.close(injector);
        } else {
            System.out.println("Could not close Class scope as there is no Injector for module type "
                               + injector);
        }

        // NOTE that we don't have any good hooks yet to call complete()
        // when the JVM is completed to ensure real singletons shut down
        // correctly
        //
        if (isCloseSingletonsAfterClasses()) {
            closeInjectors();
        }
    }

    public void beforeTest(Object test) throws Exception {
        Preconditions.checkNotNull(test, "test");

        Class<? extends Object> testType = test.getClass();
        moduleType = getModuleForTestClass(testType);

        Injector classInjector;
        synchronized (injectors) {
            classInjector = injectors.get(moduleType);
            if (classInjector == null) {
                classInjector = createInjector(moduleType);
                Preconditions.checkNotNull(classInjector, "classInjector");
                injectors.put(moduleType, classInjector);
            }
        }
        injectors.put(testType, classInjector);

        classInjector.injectMembers(test);
    }

    public void afterTest(Object test) throws Exception {
        Injector injector = injectors.get(test.getClass());
        if (injector == null) {
            System.out.println("Warning - no injector available for: " + test);
        } else {
            testScope.close(injector);
        }
    }

    /**
     * Closes down any JVM level singletons used in this testing JVM
     */
    public void closeSingletons() throws CloseFailedException {
        closeInjectors();
    }

    public boolean isCloseSingletonsAfterClasses() {
        return closeSingletonsAfterClasses;
    }

    public void setCloseSingletonsAfterClasses(boolean closeSingletonsAfterClasses) {
        this.closeSingletonsAfterClasses = closeSingletonsAfterClasses;
    }

    protected class TestModule extends AbstractModule {

        protected void configure() {
            bindScope(ClassScoped.class, classScope);
            bindScope(TestScoped.class, testScope);
        }
    }

    protected void closeInjectors() throws CloseFailedException {
        CloseErrors errors = new CloseErrorsImpl(this);
        Set<Entry<Object, Injector>> entries = injectors.entrySet();
        for (Entry<Object, Injector> entry : entries) {
            // Object key = entry.getKey();
            Injector injector = entry.getValue();
            Injectors.close(injector, errors);
        }
        injectors.clear();
        errors.throwIfNecessary();
    }

    /**
     * Factory method to return the module type that will be used to create an
     * injector.
     *
     * The default implementation will use the system property
     * <code>org.guiceyfruit.modules</code> (see
     * {@link Injectors#MODULE_CLASS_NAMES} otherwise if that is not set it will
     * look for the {@link UseModule} annotation and use the module defined on
     * that otherwise it will try look for the inner public static class
     * "TestModule"
     *
     * @see org.apache.camel.guice.testing.UseModule
     * @see #NESTED_MODULE_CLASS
     */
    @SuppressWarnings("unchecked")
    protected Class<? extends Module> getModuleForTestClass(Class<?> objectType)
        throws IllegalAccessException, InstantiationException, ClassNotFoundException {
        String modules = System.getProperty(Injectors.MODULE_CLASS_NAMES);
        if (modules != null) {
            modules = modules.trim();
            if (modules.length() > 0) {
                System.out.println("Overloading Guice Modules: " + modules);
                return null;
            }
        }
        Class<? extends Module> moduleType;
        UseModule config = objectType.getAnnotation(UseModule.class);
        if (config != null) {
            moduleType = config.value();
        } else {
            String name = objectType.getName() + "$" + NESTED_MODULE_CLASS;
            Class<?> type;
            try {
                type = objectType.getClassLoader().loadClass(name);
            } catch (ClassNotFoundException e) {
                try {
                    type = Thread.currentThread().getContextClassLoader().loadClass(name);
                } catch (ClassNotFoundException e2) {
                    throw new ClassNotFoundException(
                                                     "Class "
                                                         + objectType.getName()
                                                         + " does not have a @UseModule annotation nor does it have a nested class called "
                                                         + NESTED_MODULE_CLASS
                                                         + " available on the classpath. Please see: http://code.google.com/p/guiceyfruit/wiki/Testing"
                                                         + e, e);
                }
            }
            try {
                moduleType = (Class<? extends Module>)type;
            } catch (Exception e) {
                throw new IllegalArgumentException("Class " + type.getName() + " is not a Guice Module!", e);
            }
        }
        int modifiers = moduleType.getModifiers();
        if (Modifier.isAbstract(modifiers) || !Modifier.isPublic(modifiers)) {
            throw new IllegalArgumentException("Class " + moduleType.getName()
                                               + " must be a public class which is non abstract");
        }
        try {
            moduleType.getConstructor();
        } catch (NoSuchMethodException e) {
            throw new IllegalArgumentException("Class " + moduleType.getName()
                                               + " must have a zero argument constructor", e);
        }
        return moduleType;
    }

    /**
     * Creates the injector for the given key
     */
    protected Injector createInjector(Class<? extends Module> moduleType) throws InstantiationException,
        IllegalAccessException, ClassNotFoundException {
        if (moduleType == null) {
            return Injectors.createInjector(System.getProperties(), new TestModule());
        }
        // System.out.println("Creating Guice Injector from module: " +
        // moduleType.getName());
        Module module = moduleType.newInstance();
        return Guice.createInjector(module, new TestModule());
    }
}
TOP

Related Classes of org.apache.camel.guice.testing.InjectorManager$TestModule

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.