org.jboss.arquillian.spring.integration.lifecycle.AbstractApplicationContextLifecycleHandler Maven / Gradle / Ivy
Show all versions of arquillian-service-integration-spring Show documentation
/*
* JBoss, Home of Professional Open Source
* Copyright 2013, Red Hat Middleware LLC, and individual contributors
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* Licensed 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.jboss.arquillian.spring.integration.lifecycle;
import org.jboss.arquillian.core.api.Event;
import org.jboss.arquillian.core.api.Instance;
import org.jboss.arquillian.core.api.annotation.Inject;
import org.jboss.arquillian.core.api.annotation.Observes;
import org.jboss.arquillian.core.spi.ServiceLoader;
import org.jboss.arquillian.spring.integration.context.ApplicationContextDestroyer;
import org.jboss.arquillian.spring.integration.context.ApplicationContextProducer;
import org.jboss.arquillian.spring.integration.context.TestScopeApplicationContext;
import org.jboss.arquillian.spring.integration.event.ApplicationContextCreatedEvent;
import org.jboss.arquillian.spring.integration.event.ApplicationContextDestroyedEvent;
import org.jboss.arquillian.spring.integration.event.ApplicationContextEvent;
import org.jboss.arquillian.spring.integration.test.annotation.ContextLifeCycle;
import org.jboss.arquillian.spring.integration.test.annotation.ContextLifeCycleMode;
import org.jboss.arquillian.test.spi.TestClass;
import org.jboss.arquillian.test.spi.event.suite.After;
import org.jboss.arquillian.test.spi.event.suite.AfterSuite;
import org.jboss.arquillian.test.spi.event.suite.Before;
import org.jboss.arquillian.test.spi.event.suite.BeforeClass;
import java.util.Collection;
/**
* The application context lifecycle handler, which is responsible for instantiating the application context prior
* the test and destroying it as soon as it's not needed any longer.
*
* Currently the application context can be created once for whole test case or separately for each individual test.
* The strategy on how the application context is being instantiated is being determined from the {@link
* ContextLifeCycle} annotation defined on the test class. By default all the tests in the same test case share the same
* instance of application context.
*
* @param the type of {@link ApplicationContextProducer} that can provide specific type
* @param the type of application context instance
*
* @author Jakub Narloch
* @see ApplicationContextProducer
* @see ContextLifeCycle
* @see ContextLifeCycleMode
*/
public abstract class AbstractApplicationContextLifecycleHandler,
T extends TestScopeApplicationContext> {
/**
* Represents the default ApplicationContext life cycle mode.
*/
private static final ContextLifeCycleMode DEFAULT_LIFE_CYCLE_MODE = ContextLifeCycleMode.TEST_CASE;
/**
* Represents the instance of {@link ServiceLoader}.
*/
@Inject
private Instance serviceLoaderInstance;
/**
* Represents the application context created event.
*/
@Inject
private Event applicationContextEvent;
/**
* Retrieves the application context.
*
* @return the application context
*/
protected abstract T getApplicationContext();
/**
* Sets the application context instance.
*
* @param applicationContext the application context instance
*/
protected abstract void setApplicationContext(T applicationContext);
/**
* Retrieves the {@link ApplicationContextProducer} instance.
*
* @return the {@link ApplicationContextProducer} instance
*/
protected abstract Class getProducerClass();
/**
* The before class event handler.
*
* Delegates to the registered {@link ApplicationContextProducer} instances in order to create the application
* context.
*
* @param event the before class event
*/
public void beforeClass(@Observes BeforeClass event) {
createTestApplicationContext(event.getTestClass());
}
/**
* The before test event handler.
*
* Delegates to the registered {@link ApplicationContextProducer} instances in order to create the application
* context.
*
* @param event the before test event
*/
public void beforeTest(@Observes Before event) {
createTestApplicationContext(event.getTestClass());
}
/**
* The after test event handler.
*
* Delegates to the registered {@link ApplicationContextProducer} instances in order to create the application
* context.
*
* @param event the after test event
*/
public void afterTest(@Observes After event) {
ContextLifeCycleMode mode = getContextLifeCycleMode(event.getTestClass());
if (mode == ContextLifeCycleMode.TEST) {
destroyTestApplicationContext();
}
}
/**
* The before test event handler.
*
* Delegates to the registered {@link ApplicationContextProducer} instances in order to create the application
* context.
*
* @param event the after suite event
*/
public void afterSuite(@Observes AfterSuite event) {
destroyTestApplicationContext();
}
/**
* Instantiates the application context if needed base on the meta data provided on the test class.
*
* The actual instances creation is being delegated to the registered
*
* @param testClass the instance of the test class
*/
private void createTestApplicationContext(TestClass testClass) {
if (getApplicationContext() != null &&
getApplicationContext().getTestClass().getJavaClass().equals(testClass.getJavaClass())) {
return;
}
// creates the application context instance
T applicationContext = createApplicationContext(testClass);
if (applicationContext != null) {
// triggers the application context created event
applicationContextEvent.fire(new ApplicationContextCreatedEvent(applicationContext));
setApplicationContext(applicationContext);
}
}
/**
* Creates the application context. The application context creation is being delegates to the registered
* instances of {@link ApplicationContextProducer}.
*
* @param testClass the test class
*
* @return the application context
*/
private T createApplicationContext(TestClass testClass) {
ServiceLoader serviceLoader = serviceLoaderInstance.get();
// retrieves the list of all registered application context producers
Collection applicationContextProducers = serviceLoader.all(getProducerClass());
for (TProd applicationContextProducer : applicationContextProducers) {
if (applicationContextProducer.supports(testClass)) {
return applicationContextProducer.createApplicationContext(testClass);
}
}
// the given test is not supported
return null;
}
/**
* Destroys the application context if it exists.
*/
private void destroyTestApplicationContext() {
T applicationContext = getApplicationContext();
if (applicationContext != null) {
destroyApplicationContext(applicationContext);
// triggers the application context destroyed event
applicationContextEvent.fire(new ApplicationContextDestroyedEvent(applicationContext));
}
}
/**
* Destroys the application context.
*
* The implementation by default delegates to the registered {@link ApplicationContextDestroyer} to perform the
* application context clean up.
*
* @param applicationContext the application context to be destroyed
*/
private void destroyApplicationContext(TestScopeApplicationContext applicationContext) {
// single service is expected
getService(ApplicationContextDestroyer.class).destroyApplicationContext(applicationContext);
}
/**
* Retrieves the context life cycle mode.
*
* @param testClass the test class
*
* @return the {@link ContextLifeCycleMode} defined for the test
*/
private ContextLifeCycleMode getContextLifeCycleMode(TestClass testClass) {
ContextLifeCycle contextLifeCycle = testClass.getAnnotation(ContextLifeCycle.class);
if (contextLifeCycle != null) {
return contextLifeCycle.value();
}
return DEFAULT_LIFE_CYCLE_MODE;
}
/**
* Retrieves the service by it's type.
The implementation uses {@link ServiceLoader} in order to retrieve
* first instance of specified kind. Any other registered instance in given scope is being discarded.
*
* @param clazz the class of the service
* @param the service type
*
* @return the service instance
*/
private T getService(Class clazz) {
Collection collection = serviceLoaderInstance.get().all(clazz);
return collection.iterator().next();
}
}