/**
* NOTE: This copyright does *not* cover user programs that use HQ
* program services by normal system calls through the application
* program interfaces provided as part of the Hyperic Plug-in Development
* Kit or the Hyperic Client Development Kit - this is merely considered
* normal use of the program, and does *not* fall under the heading of
* "derived work".
*
* Copyright (C) [2009-2012], VMware, Inc.
* This file is part of HQ.
*
* HQ is free software; you can redistribute it and/or modify
* it under the terms version 2 of the GNU General Public License as
* published by the Free Software Foundation. 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 General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA.
*
*/
package org.hyperic.hq.context;
import java.io.File;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.management.ManagementFactory;
import java.lang.reflect.Field;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import javax.management.MBeanServer;
import javax.management.MBeanServerFactory;
import javax.management.ObjectName;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hyperic.hq.common.SystemException;
import org.hyperic.sigar.Sigar;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.support.BeanDefinitionReader;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.MessageSourceResolvable;
import org.springframework.context.NoSuchMessageException;
import org.springframework.context.annotation.AnnotationConfigUtils;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.scheduling.concurrent.ExecutorConfigurationSupport;
import org.springframework.test.context.support.AbstractContextLoader;
import org.springframework.test.context.support.GenericXmlContextLoader;
import org.springframework.util.StringUtils;
public class IntegrationTestContextLoader extends AbstractContextLoader {
protected static final Log logger = LogFactory.getLog(IntegrationTestContextLoader.class);
private static Sigar sigar ;
private static Field platformBeanServerField ;
protected Class<?> testClass ;
private static boolean initializedSysProps ;
private final ExternalizingGenericXmlContextLoader delegateLoader ;
public IntegrationTestContextLoader() {
super();
this.delegateLoader = new ExternalizingGenericXmlContextLoader() ;
}//EOM
public final void setTestClass(final Class<?> testClass) {
this.testClass = testClass ;
}//EOM
public static final void configureSigar(final ApplicationContext context, final Log externalLogger) {
final Log log = (externalLogger == null ? logger : externalLogger) ;
try {
overrideProperties(log) ;
//Find the sigar libs on the test classpath
final File sigarBin = new File(context.getResource("/libsigar-sparc64-solaris.so").getFile().getParent());
log.info("Setting sigar path to : " + sigarBin.getAbsolutePath());
System.setProperty("org.hyperic.sigar.path",sigarBin.getAbsolutePath());
//ensure that the Sigar native libraries are loaded and remain in the classloader's context
sigar = new Sigar() ;
Sigar.load() ;
} catch (Throwable t) {
log.error("Unable to initiailize sigar path",t);
throw new SystemException(t) ;
}//EO catch block
}//EOM
private static final void overrideProperties(final Log log) {
if(initializedSysProps) return ;
final String OVERRIDE_PREFIX = "override." ;
final int OVERRIDE_PREFIX_LENGTH = OVERRIDE_PREFIX.length() ;
final Properties sysProps = System.getProperties() ;
final Map<String,String> newProps = new HashMap<String,String>() ;
String origSysPropName, overrideSysPropName, origSyspropVal, overrideVal ;
int indexOfPrefix ;
for(Entry<Object,Object> syspropEntry : sysProps.entrySet()) {
overrideSysPropName = (String) syspropEntry.getKey() ;
if( (indexOfPrefix = overrideSysPropName.indexOf(OVERRIDE_PREFIX)) == -1 ) continue ;
//first search for an explicitly defined corresponding original sys prop
//and found skip the override.
origSysPropName = overrideSysPropName.substring(OVERRIDE_PREFIX_LENGTH) ;
origSyspropVal = System.getProperty(origSysPropName) ;
if(origSyspropVal != null) continue ;
//else create a new orig sys prop with the override value
overrideVal = (String) syspropEntry.getValue() ;
newProps.put(origSysPropName, overrideVal) ;
log.info("An "+overrideSysPropName+" property value was provided : " + overrideVal + " setting in the " + origSysPropName + " system property") ;
}//EO while there are more system properties
for(Map.Entry<String,String> newPropEntry : newProps.entrySet()) {
System.setProperty(newPropEntry.getKey(), newPropEntry.getValue()) ;
}//EO while there are more new properties
initializedSysProps = true ;
}//EOM
private final void overrideProperties(final String[][] properties, final Log log) {
final int length = properties.length ;
String sysPropName, overrideSysPropName, syspropOrigVal, overrideVal ;
for(int i=0; i < length; i++) {
sysPropName = properties[i][0] ;
syspropOrigVal = System.getProperty(sysPropName) ;
//if the org system property already exists then it was explicitly defined and should
//not be overriden
if(syspropOrigVal != null) continue ;
//else attempt to looukup the overrding property value and if found, define
//a new system proeprty with the orig name and the overriding value
overrideSysPropName = properties[i][1];
overrideVal = System.getProperty(overrideSysPropName) ;
if(overrideVal == null) continue ;
//else there is an override value and not explicitly defined orig value so override
log.info("An "+overrideSysPropName+" property value was provided : " + overrideVal + " setting in the " + sysPropName + " system property") ;
}//EO while there are more properties to potentially override
}//EOM
public ApplicationContext loadContext(final String... locations) throws Exception {
if (logger.isDebugEnabled()) {
logger.debug("Loading ApplicationContext for locations [" +
StringUtils.arrayToCommaDelimitedString(locations) + "].");
}//EO if logger is enabled
final GenericApplicationContext context = new ProxyingGenericApplicationContext();
//verify sigar's resources existence & load native libraries
configureSigar(context, logger) ;
//clean previous application context (if exists) and create a new one
Bootstrap.setAppContext(context) ;
try{
//initialize the application context
delegateLoader.createBeanDefinitionReader(context).loadBeanDefinitions(locations);
AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
context.refresh();
context.registerShutdownHook();
return context;
}catch(Throwable t) {
logger.error("An Error had occured during the applicationContext creation, disposing!") ;
Bootstrap.dispose() ;
throw (Exception) t ;
}//EO catch block
}//EOM
@Override
public final String getResourceSuffix() {
return this.delegateLoader.getResourceSuffix() ;
}//EOM
/**
* Class used to expose the {@link GenericXmlContextLoader#createBeanDefinitionReader} method so that it<br>
* could be delegated to by the encapsulating class
* @author guy
*
*/
private static final class ExternalizingGenericXmlContextLoader extends GenericXmlContextLoader {
@Override
public final BeanDefinitionReader createBeanDefinitionReader(GenericApplicationContext context) {
return super.createBeanDefinitionReader(context);
}
}//EOC ExternalizingGenericXmlContextLoader
private static final class DisposableApplicationContext extends GenericApplicationContext {
@Override
public final void close() {
if(!this.isActive()) {
// Destroy all cached singletons in the context's BeanFactory.
this.destroyBeans();
// Close the state of this context itself.
this.closeBeanFactory();
//close the parent as well
if(this.getParent() != null) ((ConfigurableApplicationContext)this.getParent()).close() ;
}//EO if not active
else {
super.close();
}//EO else normal close
}//EOM
}//EOC DisposableApplicationContext
/**
* Wrapper around an {@link GenericApplicationContext} instance used to control its references.<br>
* the {@link ProxyingGenericApplicationContext#close()} shall clear context resources and ensure that the<br>
* underlying applicationContext instance could be garbage collected so as to prevent memroy leaks.
*
* @author guy
*
*/
protected static final class ProxyingGenericApplicationContext extends GenericApplicationContext {
private AbstractApplicationContext delegate ;
private boolean isDelegateInstanceofGenericAppContext ;
public ProxyingGenericApplicationContext() {
super() ;
this.delegate = new DisposableApplicationContext() ;
this.isDelegateInstanceofGenericAppContext = true ;
}//EOM
public ProxyingGenericApplicationContext(AbstractApplicationContext appcontext) {
super() ;
this.delegate = appcontext ;
this.isDelegateInstanceofGenericAppContext = (appcontext instanceof GenericApplicationContext) ;
}//EOM
@Override
public void setParent(ApplicationContext parent) {
this.delegate.setParent(parent);
}//EOM
@Override
public void setId(String id) {
this.delegate.setId(id);
}//EOM
@Override
public void setAllowBeanDefinitionOverriding(boolean allowBeanDefinitionOverriding) {
if(isDelegateInstanceofGenericAppContext) {
((GenericApplicationContext)this.delegate).setAllowBeanDefinitionOverriding(allowBeanDefinitionOverriding);
}//EO if delegate is generic application context
}//EOM
@Override
public void setAllowCircularReferences(boolean allowCircularReferences) {
if(isDelegateInstanceofGenericAppContext) {
((GenericApplicationContext)this.delegate).setAllowCircularReferences(allowCircularReferences);
}//EO if delegate is generic application context
}//EOM
@Override
public void setResourceLoader(ResourceLoader resourceLoader) {
if(isDelegateInstanceofGenericAppContext) {
((GenericApplicationContext)this.delegate).setResourceLoader(resourceLoader);
}//EO if delegate is generic application context
}//EOM
@Override
public Resource getResource(String location) {
return this.delegate.getResource(location);
}//EOM
@Override
public Resource[] getResources(String locationPattern) throws IOException {
return this.delegate.getResources(locationPattern);
}//EOM
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
if(isDelegateInstanceofGenericAppContext) {
((GenericApplicationContext)this.delegate).registerBeanDefinition(beanName, beanDefinition);
}//EO if delegate is generic application context
}//EOM
@Override
public void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException {
if(isDelegateInstanceofGenericAppContext) {
((GenericApplicationContext)this.delegate).removeBeanDefinition(beanName);
}//EO if delegate is generic application context
}
@Override
public BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException {
if(isDelegateInstanceofGenericAppContext) {
return ((GenericApplicationContext)this.delegate).getBeanDefinition(beanName);
}//EO if delegate is generic application context
else throw new UnsupportedOperationException();
}//EOM
@Override
public boolean isBeanNameInUse(String beanName) {
if(isDelegateInstanceofGenericAppContext) {
return ((GenericApplicationContext)this.delegate).isBeanNameInUse(beanName);
}//EO if delegate is generic application context
else throw new UnsupportedOperationException();
}//EOM
@Override
public void registerAlias(String beanName, String alias) {
if(isDelegateInstanceofGenericAppContext) {
((GenericApplicationContext)this.delegate).registerAlias(beanName, alias);
}//EO if delegate is generic application context
}//EOM
@Override
public void removeAlias(String alias) {
if(isDelegateInstanceofGenericAppContext) {
((GenericApplicationContext)this.delegate).removeAlias(alias);
}//EO if delegate is generic application context
}//EOM
@Override
public boolean isAlias(String beanName) {
if(isDelegateInstanceofGenericAppContext) {
return ((GenericApplicationContext)this.delegate).isAlias(beanName);
}//EO if delegate is generic application context
else throw new UnsupportedOperationException() ;
}//EOM
@Override
public String getId() {
return this.delegate.getId();
}//EOM
@Override
public void setDisplayName(String displayName) {
this.delegate.setDisplayName(displayName);
}//EOM
@Override
public String getDisplayName() {
return this.delegate.getDisplayName();
}//EOM
@Override
public ApplicationContext getParent() {
return this.delegate.getParent();
}//EOM
@Override
public AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException {
return this.delegate.getAutowireCapableBeanFactory();
}//EOM
@Override
public long getStartupDate() {
return this.delegate.getStartupDate();
}//EOM
@Override
public void publishEvent(ApplicationEvent event) {
this.delegate.publishEvent(event);
}//EOM
@Override
public void addBeanFactoryPostProcessor(BeanFactoryPostProcessor beanFactoryPostProcessor) {
this.delegate.addBeanFactoryPostProcessor(beanFactoryPostProcessor);
}//EOM
@Override
public List<BeanFactoryPostProcessor> getBeanFactoryPostProcessors() {
return this.delegate.getBeanFactoryPostProcessors();
}//EOM
@Override
public void addApplicationListener(ApplicationListener listener) {
this.delegate.addApplicationListener(listener);
}//EOM
@Override
public Collection<ApplicationListener> getApplicationListeners() {
return this.delegate.getApplicationListeners();
}//EOM
@Override
public void refresh() throws BeansException, IllegalStateException {
this.delegate.refresh();
}//EOM
@Override
public void registerShutdownHook() {
this.delegate.registerShutdownHook();
}//EOM
@Override
public void destroy() {
this.close() ;
}//EOM
/**
* Severs any hard references between the delegate and client code so that the former could be garbage
* collected.<br>
* Moreover, releases JMX resources otherwise designed to be freed during JVM shutdown.
*/
@Override
public void close() {
if(this.delegate == null) {
return ;
}//EO if already closed
try{
Object scheduler = this.delegate.getBean("scheduler") ;
if(scheduler instanceof ExecutorConfigurationSupport) ((ExecutorConfigurationSupport) scheduler).shutdown() ;
}catch(org.springframework.beans.factory.NoSuchBeanDefinitionException nsbde) {
//swallow exception
}catch(Throwable t) {
t.printStackTrace() ;
}//EO catch block
//Clear the JMX resources
this.resetJMXResources() ;
this.delegate.close() ;
this.delegate = null ;
//"request" GC
final int iNoOfGCRequests = 3 ;
for(int i=0; i < iNoOfGCRequests; i++) {
System.gc() ;
}//EO while there are more tests
}//EOM
/*
* Clears the ManagementFactory's platformBeanServerField member as well as the reference in
* the MBeanServerFactory.
*/
private final void resetJMXResources() {
try{
final String meanServerBeanName = "mbeanServer" ;
if(!this.containsBean(meanServerBeanName)) return ;
//release jmx resources if exist in the spring context scope
final MBeanServer mbeanServer = (MBeanServer) this.getBean(meanServerBeanName) ;
if(mbeanServer == null) return ;
//else
//stop the singleton service (done here instead of the (EE's HaServiceImpl as to minimize
//affected code for release)
final ObjectName o = new ObjectName("hyperic.jmx:type=Service,name=EEHAService-HASingletonController");
if(mbeanServer.isRegistered(o)) {
System.out.println(mbeanServer.invoke(o, "stop", new Object[] {}, new String[] {})) ;
}//EO if the singleton exists
if(platformBeanServerField == null) {
platformBeanServerField = ManagementFactory.class.getDeclaredField("platformMBeanServer") ;
platformBeanServerField.setAccessible(true) ;
}//EO if the platformBeanServerField was not yet initialized
//set the value to null
platformBeanServerField.set(null/*instance*/, null/*value*/) ;
//clear the mbean server cache from the mbean server factory
MBeanServerFactory.releaseMBeanServer(mbeanServer) ;
}catch(Throwable t) {
throw new SystemException(t) ;
}//EO catch block
}//EOM
@Override
public boolean isActive() {
return this.delegate.isActive();
}//EOM
@Override
public Object getBean(String name) throws BeansException {
return this.delegate.getBean(name);
}//EOM
@Override
public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
return this.delegate.getBean(name, requiredType);
}//EOM
@Override
public <T> T getBean(Class<T> requiredType) throws BeansException {
return this.delegate.getBean(requiredType);
}//EOM
@Override
public Object getBean(String name, Object... args) throws BeansException {
return this.delegate.getBean(name, args);
}//EOM
@Override
public boolean containsBean(String name) {
return this.delegate.containsBean(name);
}//EOM
@Override
public boolean isSingleton(String name) throws NoSuchBeanDefinitionException {
return this.delegate.isSingleton(name);
}//EOM
@Override
public boolean isPrototype(String name) throws NoSuchBeanDefinitionException {
return this.delegate.isPrototype(name);
}//EOM
@Override
public boolean isTypeMatch(String name, Class targetType) throws NoSuchBeanDefinitionException {
return this.delegate.isTypeMatch(name, targetType);
}//EOM
@Override
public Class<?> getType(String name) throws NoSuchBeanDefinitionException {
return this.delegate.getType(name);
}//EOM
@Override
public String[] getAliases(String name) {
return this.delegate.getAliases(name);
}//EOM
@Override
public boolean containsBeanDefinition(String beanName) {
return this.delegate.containsBeanDefinition(beanName);
}//EOM
@Override
public int getBeanDefinitionCount() {
return this.delegate.getBeanDefinitionCount();
}//EOM
@Override
public String[] getBeanDefinitionNames() {
return this.delegate.getBeanDefinitionNames();
}//EOM
@Override
public String[] getBeanNamesForType(Class type) {
return this.delegate.getBeanNamesForType(type);
}//EOM
@Override
public String[] getBeanNamesForType(Class type, boolean includeNonSingletons, boolean allowEagerInit) {
return this.delegate.getBeanNamesForType(type, includeNonSingletons, allowEagerInit);
}//EOM
@Override
public <T> Map<String, T> getBeansOfType(Class<T> type) throws BeansException {
return this.delegate.getBeansOfType(type);
}//EOM
@Override
public <T> Map<String, T> getBeansOfType(Class<T> type, boolean includeNonSingletons, boolean allowEagerInit)
throws BeansException {
return this.delegate.getBeansOfType(type, includeNonSingletons, allowEagerInit);
}//EOM
@Override
public Map<String, Object> getBeansWithAnnotation(Class<? extends Annotation> annotationType)
throws BeansException {
return this.delegate.getBeansWithAnnotation(annotationType);
}//EOM
@Override
public <A extends Annotation> A findAnnotationOnBean(String beanName, Class<A> annotationType) {
return this.delegate.findAnnotationOnBean(beanName, annotationType);
}//EOM
@Override
public BeanFactory getParentBeanFactory() {
return this.delegate.getParentBeanFactory();
}//EOM
@Override
public boolean containsLocalBean(String name) {
return this.delegate.containsLocalBean(name);
}//EOM
@Override
public String getMessage(String code, Object[] args, String defaultMessage, Locale locale) {
return this.delegate.getMessage(code, args, defaultMessage, locale);
}//EOM
@Override
public String getMessage(String code, Object[] args, Locale locale) throws NoSuchMessageException {
return this.delegate.getMessage(code, args, locale);
}//EOM
@Override
public String getMessage(MessageSourceResolvable resolvable, Locale locale) throws NoSuchMessageException {
return this.delegate.getMessage(resolvable, locale);
}//EOM
@Override
public void start() {
this.delegate.start();
}//EOM
@Override
public void stop() {
this.delegate.stop();
}//EOM
@Override
public boolean isRunning() {
return this.delegate.isRunning();
}//EOM
@Override
public String toString() {
return this.delegate.toString();
}//EOM
@Override
public void setClassLoader(ClassLoader classLoader) {
this.delegate.setClassLoader(classLoader);
}//EOM
@Override
public ClassLoader getClassLoader() {
return this.delegate.getClassLoader();
}//EOM
}//EOC ProxyingGenericApplicationContext
public static void main(String[] args) throws Throwable {
overrideProperties(logger) ;
}//EOM
}//EOC