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

org.sakaiproject.component.cover.TestComponentManagerContainer Maven / Gradle / Ivy

/**********************************************************************************
 * $URL$
 * $Id$
 ***********************************************************************************
 *
 * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008 Sakai Foundation
 *
 * Licensed under the Educational Community 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.opensource.org/licenses/ECL-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.sakaiproject.component.cover;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.sakaiproject.component.impl.SpringCompMgr;
import org.springframework.beans.factory.config.PropertyOverrideConfigurer;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

/**
 * A container for a Test Component Manager that can be configured with one of more components.
 *
 */
public class TestComponentManagerContainer {

	/**
	 * The logger
	 */
	private static final Log log = LogFactory.getLog(TestComponentManagerContainer.class);
	
	/**
	 * The current component manager
	 */
	private SpringCompMgr componentManager;


	public TestComponentManagerContainer(String configPaths) throws IOException {
		this(configPaths, null);
	}

	/**
	 * create a component manager based on a list of component.xml
	 * @param configPaths a ';' seperated list of xml bean config files
	 * @throws IOException
	 */
	public TestComponentManagerContainer(String configPaths, Properties props)  throws IOException {
		// we assume that all the jars are in the same classloader, so this will
		// not check for
		// incorrect bindings and will not fully replicate the tomcat
		// experience, but is an easier environment
		// to work within for kernel testing.
		// For a more complex structure we could use the kernel poms in the repo
		// to generate the dep list.
		if ( ComponentManager.m_componentManager != null ) {
			log.info("Closing existing Component Manager ");
			/*			
 			try {
				ComponentManager.m_componentManager.close();
			} catch ( Throwable t ) {
				log.warn("Close Failed with message, safe to ignore "+t.getMessage());
			}
			*/
			log.info("Closing Complete ");
			ComponentManager.m_componentManager = null;
		}
		
		log.info("Starting Component Manager with ["+configPaths+"]");
		ComponentManager.setLateRefresh(true);

		 componentManager = (SpringCompMgr) ComponentManager
				.getInstance();
		ConfigurableApplicationContext ac = componentManager
				.getApplicationContext();
		ClassLoader classLoader = Thread.currentThread()
				.getContextClassLoader();
		// Supply any additional configuration.
		if (props != null) {
			PropertyOverrideConfigurer beanFactoryPostProcessor = new PropertyOverrideConfigurer();
			beanFactoryPostProcessor.setBeanNameSeparator("@");
			beanFactoryPostProcessor.setProperties(props);
			ac.addBeanFactoryPostProcessor(beanFactoryPostProcessor);
		}

		// we could take the kernel bootstrap from from the classpath in future
		// rather than from
		// the filesystem

		List config = new ArrayList();
		String[] configPath = configPaths.split(";");
		for ( String p : configPath) {
			File xml = new File(p);
			config.add(new FileSystemResource(xml.getCanonicalPath()));
		}
		loadComponent(ac, config, classLoader);
		
		ac.refresh();

		// SAK-20908 - band-aid for TLM sync issues causing tests to fail
		// This sleep shouldn't be needed but it seems these tests are starting before ThreadLocalManager has finished its startup.
        try {
            Thread.sleep(500); // 1/2 second
            log.debug("Finished starting the component manager");
        } catch (InterruptedException e) {
            log.error("Component manager startup interrupted...");
        }
	}

	/**
	 * Load the application context using a single classloader
	 * @param ac The spring application context
	 * @param config a list of configurations represented as List of resources
	 * @param loader the classloader to use
	 */
	public void loadComponent(ConfigurableApplicationContext ac,
			List config, ClassLoader loader) {
		ClassLoader current = Thread.currentThread().getContextClassLoader();

		Thread.currentThread().setContextClassLoader(loader);

		try {

			// make a reader
			XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(
					(BeanDefinitionRegistry) ac.getBeanFactory());

			// In Spring 2, classes aren't loaded during bean parsing unless
			// this
			// classloader property is set.
			reader.setBeanClassLoader(loader);

			reader.loadBeanDefinitions(config.toArray(new Resource[0]));
		} catch (Throwable t) {
			log.warn("loadComponentPackage: exception loading: " + config
					+ " : " + t, t);
		} finally {
			// restore the context loader
			Thread.currentThread().setContextClassLoader(current);
		}

	}

	/**
	 * get the current component manager
	 * @return
	 */
	public org.sakaiproject.component.api.ComponentManager getComponentManager() {
		return componentManager;
	}

	/**
	 * Convenience method to create a somewhat unique site id for testing.  Useful
	 * in tests that need to create a site to run tests upon.
	 * 
	 * @return A string suitable for using as a site id.
	 */
	protected String generateSiteId() {
		return "site-" + getClass().getName() + "-" + Math.floor(Math.random()*100000);
	}
	
	/**
	 * Returns a dynamic proxy for a service interface.  Useful for testing with
	 * customized service implementations without needing to write custom stubs.
	 * 
	 * @param clazz The service interface class
	 * @param handler The invocation handler that defines how the dynamic proxy should behave
	 * 
	 * @return The dynamic proxy to use as a collaborator
	 */
	public static final Object getServiceProxy(Class clazz, InvocationHandler handler) {
		return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class[] {clazz}, handler);
	}
	
	public static void setSakaiHome(String sakaiHome) {
		System.setProperty("sakai.home", sakaiHome);
	}

	/**
	 * Convenience method to get a service bean from the Sakai component manager.
	 * 
	 * @param beanId The id of the service
	 * 
	 * @return The service, or null if the ID is not registered
	 */
	public Object getService(String beanId) {
		try {			
			return componentManager.get(beanId);
		} catch (Exception e) {
			log.error(e);
			return null;
		}
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy