blob: d678b6e40a2360f7b6e4c2d8dafb6dd5271e7fea [file] [log] [blame]
//
// 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 com.cloud.utils.component;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import javax.management.InstanceAlreadyExistsException;
import javax.management.MBeanRegistrationException;
import javax.management.MalformedObjectNameException;
import javax.management.NotCompliantMBeanException;
import javax.naming.ConfigurationException;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
import org.springframework.aop.framework.Advised;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Primary;
import com.cloud.utils.mgmt.JmxUtil;
import com.cloud.utils.mgmt.ManagementBean;
/**
*
* ComponentContext.setApplication() and ComponentContext.getApplication()
* are not recommended to be used outside, they exist to help wire Spring Framework
*
*/
@SuppressWarnings("unchecked")
public class ComponentContext implements ApplicationContextAware {
protected static Logger LOGGER = LogManager.getLogger(ComponentContext.class);
private static ApplicationContext s_appContext;
private static Map<Class<?>, ApplicationContext> s_appContextDelegates;
private static boolean s_initializeBeans = true;
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
LOGGER.info("Setup Spring Application context");
s_appContext = applicationContext;
}
public static ApplicationContext getApplicationContext() {
return s_appContext;
}
public static void initComponentsLifeCycle() {
if (!s_initializeBeans)
return;
AutowireCapableBeanFactory beanFactory = s_appContext.getAutowireCapableBeanFactory();
Map<String, ComponentMethodInterceptable> interceptableComponents = getApplicationContext().getBeansOfType(ComponentMethodInterceptable.class);
for (Map.Entry<String, ComponentMethodInterceptable> entry : interceptableComponents.entrySet()) {
try {
Object bean = getTargetObject(entry.getValue());
beanFactory.configureBean(bean, entry.getKey());
} catch (BeansException e){
LOGGER.error(String.format("Could not load bean due to: [%s]. The service will be stopped. Please investigate the cause of the error or contact your support team.", e.getMessage()), e);
System.exit(1);
}
}
Map<String, ComponentLifecycle> lifecycleComponents = getApplicationContext().getBeansOfType(ComponentLifecycle.class);
Map<String, ComponentLifecycle>[] classifiedComponents = new Map[ComponentLifecycle.MAX_RUN_LEVELS];
for (int i = 0; i < ComponentLifecycle.MAX_RUN_LEVELS; i++) {
classifiedComponents[i] = new HashMap<String, ComponentLifecycle>();
}
for (Map.Entry<String, ComponentLifecycle> entry : lifecycleComponents.entrySet()) {
classifiedComponents[entry.getValue().getRunLevel()].put(entry.getKey(), entry.getValue());
}
// Run the SystemIntegrityCheckers first
Map<String, SystemIntegrityChecker> integrityCheckers = getApplicationContext().getBeansOfType(SystemIntegrityChecker.class);
for (Entry<String, SystemIntegrityChecker> entry : integrityCheckers.entrySet()) {
LOGGER.info("Running SystemIntegrityChecker " + entry.getKey());
try {
entry.getValue().check();
} catch (Throwable e) {
LOGGER.error("System integrity check failed. Refuse to startup", e);
System.exit(1);
}
}
// configuration phase
Map<String, String> avoidMap = new HashMap<String, String>();
for (int i = 0; i < ComponentLifecycle.MAX_RUN_LEVELS; i++) {
for (Map.Entry<String, ComponentLifecycle> entry : classifiedComponents[i].entrySet()) {
ComponentLifecycle component = entry.getValue();
String implClassName = ComponentContext.getTargetClass(component).getName();
LOGGER.info("Configuring " + implClassName);
if (avoidMap.containsKey(implClassName)) {
LOGGER.info("Skip configuration of " + implClassName + " as it is already configured");
continue;
}
try {
component.configure(component.getName(), component.getConfigParams());
} catch (ConfigurationException e) {
LOGGER.error("Unhandled exception", e);
throw new RuntimeException("Unable to configure " + implClassName, e);
}
avoidMap.put(implClassName, implClassName);
}
}
// starting phase
avoidMap.clear();
for (int i = 0; i < ComponentLifecycle.MAX_RUN_LEVELS; i++) {
for (Map.Entry<String, ComponentLifecycle> entry : classifiedComponents[i].entrySet()) {
ComponentLifecycle component = entry.getValue();
String implClassName = ComponentContext.getTargetClass(component).getName();
LOGGER.info("Starting " + implClassName);
if (avoidMap.containsKey(implClassName)) {
LOGGER.info("Skip configuration of " + implClassName + " as it is already configured");
continue;
}
try {
component.start();
if (getTargetObject(component) instanceof ManagementBean)
registerMBean((ManagementBean)getTargetObject(component));
} catch (Exception e) {
LOGGER.error("Unhandled exception", e);
throw new RuntimeException("Unable to start " + implClassName, e);
}
avoidMap.put(implClassName, implClassName);
}
}
}
static void registerMBean(ManagementBean mbean) {
try {
JmxUtil.registerMBean(mbean);
} catch (MalformedObjectNameException e) {
LOGGER.warn("Unable to register MBean: " + mbean.getName(), e);
} catch (InstanceAlreadyExistsException e) {
LOGGER.warn("Unable to register MBean: " + mbean.getName(), e);
} catch (MBeanRegistrationException e) {
LOGGER.warn("Unable to register MBean: " + mbean.getName(), e);
} catch (NotCompliantMBeanException e) {
LOGGER.warn("Unable to register MBean: " + mbean.getName(), e);
}
LOGGER.info("Registered MBean: " + mbean.getName());
}
public static <T> T getComponent(String name) {
assert (s_appContext != null);
return (T)s_appContext.getBean(name);
}
public static <T> T getComponent(Class<T> beanType) {
assert (s_appContext != null);
Map<String, T> matchedTypes = getComponentsOfType(beanType);
if (matchedTypes.size() > 0) {
for (Map.Entry<String, T> entry : matchedTypes.entrySet()) {
Primary primary = getTargetClass(entry.getValue()).getAnnotation(Primary.class);
if (primary != null)
return entry.getValue();
}
if (matchedTypes.size() > 1) {
LOGGER.warn("Unable to uniquely locate bean type " + beanType.getName());
for (Map.Entry<String, T> entry : matchedTypes.entrySet()) {
LOGGER.warn("Candidate " + getTargetClass(entry.getValue()).getName());
}
}
return (T)matchedTypes.values().toArray()[0];
}
throw new NoSuchBeanDefinitionException(beanType.getName());
}
public static <T> Map<String, T> getComponentsOfType(Class<T> beanType) {
return s_appContext.getBeansOfType(beanType);
}
public static Class<?> getTargetClass(Object instance) {
while (instance instanceof Advised) {
try {
instance = ((Advised)instance).getTargetSource().getTarget();
} catch (Exception e) {
return instance.getClass();
}
}
return instance.getClass();
}
public static <T> T getTargetObject(Object instance) {
while (instance instanceof Advised) {
try {
instance = ((Advised)instance).getTargetSource().getTarget();
} catch (Exception e) {
return (T)instance;
}
}
return (T)instance;
}
public static <T> T inject(Class<T> clz) {
T instance;
try {
instance = clz.newInstance();
return inject(instance);
} catch (InstantiationException e) {
LOGGER.error("Unhandled InstantiationException", e);
throw new RuntimeException("Unable to instantiate object of class " + clz.getName() + ", make sure it has public constructor");
} catch (IllegalAccessException e) {
LOGGER.error("Unhandled IllegalAccessException", e);
throw new RuntimeException("Unable to instantiate object of class " + clz.getName() + ", make sure it has public constructor");
}
}
public static <T> T inject(Object instance) {
// autowire dynamically loaded object
AutowireCapableBeanFactory beanFactory = getApplicationContext(instance).getAutowireCapableBeanFactory();
beanFactory.autowireBean(instance);
return (T)instance;
}
private static ApplicationContext getApplicationContext(Object instance) {
ApplicationContext result = null;
synchronized (s_appContextDelegates) {
if (instance != null && s_appContextDelegates != null) {
result = s_appContextDelegates.get(instance.getClass());
}
}
return result == null ? s_appContext : result;
}
public static synchronized void addDelegateContext(Class<?> clazz, ApplicationContext context) {
if (s_appContextDelegates == null) {
s_appContextDelegates = new HashMap<Class<?>, ApplicationContext>();
}
s_appContextDelegates.put(clazz, context);
}
public static synchronized void removeDelegateContext(Class<?> clazz) {
if (s_appContextDelegates != null) {
s_appContextDelegates.remove(clazz);
}
}
public boolean isInitializeBeans() {
return s_initializeBeans;
}
public void setInitializeBeans(boolean initializeBeans) {
initInitializeBeans(initializeBeans);
}
private static synchronized void initInitializeBeans(boolean initializeBeans) {
s_initializeBeans = initializeBeans;
}
}