// Copyright 2012 Citrix Systems, Inc. Licensed under the
// Apache License, Version 2.0 (the "License"); you may not use this
// file except in compliance with the License. Citrix Systems, Inc.
// reserves all rights not expressly granted by 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.
//
// Automatically generated by addcopyright.py at 04/03/2012
package com.cloud.utils.component;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import javax.ejb.Local;
import javax.management.InstanceAlreadyExistsException;
import javax.management.MBeanRegistrationException;
import javax.management.MalformedObjectNameException;
import javax.management.NotCompliantMBeanException;
import javax.naming.ConfigurationException;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.CallbackFilter;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.Factory;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import net.sf.cglib.proxy.NoOp;
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
import org.apache.log4j.xml.DOMConfigurator;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import com.cloud.utils.Pair;
import com.cloud.utils.PropertiesUtil;
import com.cloud.utils.db.DatabaseCallback;
import com.cloud.utils.db.DatabaseCallbackFilter;
import com.cloud.utils.db.GenericDao;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.utils.mgmt.JmxUtil;
import com.cloud.utils.mgmt.ManagementBean;
/**
* ComponentLocator manages all of the adapters within a system. It operates on
* top of an components.xml and uses reflection to instantiate all of the
* adapters. It also supports rereading of all of the adapters.
*
**/
@SuppressWarnings("unchecked")
public class ComponentLocator implements ComponentLocatorMBean {
protected static final Logger s_logger = Logger.getLogger(ComponentLocator.class);
protected static final ThreadLocal<ComponentLocator> s_tl = new ThreadLocal<ComponentLocator>();
protected static final ConcurrentHashMap<Class<?>, Singleton> s_singletons = new ConcurrentHashMap<Class<?>, Singleton>(111);
protected static final HashMap<String, ComponentLocator> s_locators = new HashMap<String, ComponentLocator>();
protected static final HashMap<Class<?>, InjectInfo> s_factories = new HashMap<Class<?>, InjectInfo>();
protected static Boolean s_once = false;
protected static Boolean _hasCheckerRun = false;
protected static Callback[] s_callbacks = new Callback[] { NoOp.INSTANCE, new DatabaseCallback()};
protected static CallbackFilter s_callbackFilter = new DatabaseCallbackFilter();
protected static final List<AnnotationInterceptor<?>> s_interceptors = new ArrayList<AnnotationInterceptor<?>>();
protected static CleanupThread s_janitor = null;
protected HashMap<String, Adapters<? extends Adapter>> _adapterMap;
protected HashMap<String, ComponentInfo<Manager>> _managerMap;
protected LinkedHashMap<String, ComponentInfo<SystemIntegrityChecker>> _checkerMap;
protected LinkedHashMap<String, ComponentInfo<GenericDao<?, ? extends Serializable>>> _daoMap;
protected String _serverName;
protected Object _component;
protected HashMap<Class<?>, Class<?>> _factories;
protected HashMap<String, ComponentInfo<PluggableService>> _pluggableServicesMap;
static {
if (s_janitor == null) {
s_janitor = new CleanupThread();
Runtime.getRuntime().addShutdownHook(new CleanupThread());
}
}
public ComponentLocator(String server) {
_serverName = server;
if (s_janitor == null) {
s_janitor = new CleanupThread();
Runtime.getRuntime().addShutdownHook(new CleanupThread());
}
}
public String getLocatorName() {
return _serverName;
}
@Override
public String getName() {
return getLocatorName();
}
protected Pair<XmlHandler, HashMap<String, List<ComponentInfo<Adapter>>>> parse2(String filename) {
try {
SAXParserFactory spfactory = SAXParserFactory.newInstance();
SAXParser saxParser = spfactory.newSAXParser();
_daoMap = new LinkedHashMap<String, ComponentInfo<GenericDao<?, ? extends Serializable>>>();
_managerMap = new LinkedHashMap<String, ComponentInfo<Manager>>();
_checkerMap = new LinkedHashMap<String, ComponentInfo<SystemIntegrityChecker>>();
_adapterMap = new HashMap<String, Adapters<? extends Adapter>>();
_factories = new HashMap<Class<?>, Class<?>>();
_pluggableServicesMap = new LinkedHashMap<String, ComponentInfo<PluggableService>>();
File file = PropertiesUtil.findConfigFile(filename);
if (file == null) {
s_logger.info("Unable to find " + filename);
return null;
}
s_logger.info("Config file found at " + file.getAbsolutePath() + ". Configuring " + _serverName);
XmlHandler handler = new XmlHandler(_serverName);
saxParser.parse(file, handler);
HashMap<String, List<ComponentInfo<Adapter>>> adapters = new HashMap<String, List<ComponentInfo<Adapter>>>();
if (handler.parent != null) {
String[] tokens = handler.parent.split(":");
String parentFile = filename;
String parentName = handler.parent;
if (tokens.length > 1) {
parentFile = tokens[0];
parentName = tokens[1];
}
ComponentLocator parentLocator = new ComponentLocator(parentName);
adapters.putAll(parentLocator.parse2(parentFile).second());
_daoMap.putAll(parentLocator._daoMap);
_managerMap.putAll(parentLocator._managerMap);
_factories.putAll(parentLocator._factories);
_pluggableServicesMap.putAll(parentLocator._pluggableServicesMap);
}
ComponentLibrary library = null;
if (handler.library != null) {
Class<?> clazz = Class.forName(handler.library);
library = (ComponentLibrary)clazz.newInstance();
_daoMap.putAll(library.getDaos());
_managerMap.putAll(library.getManagers());
adapters.putAll(library.getAdapters());
_factories.putAll(library.getFactories());
_pluggableServicesMap.putAll(library.getPluggableServices());
}
_daoMap.putAll(handler.daos);
_managerMap.putAll(handler.managers);
_checkerMap.putAll(handler.checkers);
adapters.putAll(handler.adapters);
_pluggableServicesMap.putAll(handler.pluggableServices);
return new Pair<XmlHandler, HashMap<String, List<ComponentInfo<Adapter>>>>(handler, adapters);
} catch (ParserConfigurationException e) {
s_logger.error("Unable to load " + _serverName + " due to errors while parsing " + filename, e);
System.exit(1);
} catch (SAXException e) {
s_logger.error("Unable to load " + _serverName + " due to errors while parsing " + filename, e);
System.exit(1);
} catch (IOException e) {
s_logger.error("Unable to load " + _serverName + " due to errors while reading from " + filename, e);
System.exit(1);
} catch (CloudRuntimeException e) {
s_logger.error("Unable to load configuration for " + _serverName + " from " + filename, e);
System.exit(1);
} catch (Exception e) {
s_logger.error("Unable to load configuration for " + _serverName + " from " + filename, e);
System.exit(1);
}
return null;
}
protected void parse(String filename) {
Pair<XmlHandler, HashMap<String, List<ComponentInfo<Adapter>>>> result = parse2(filename);
if (result == null) {
s_logger.info("Skipping configuration using " + filename);
return;
}
XmlHandler handler = result.first();
HashMap<String, List<ComponentInfo<Adapter>>> adapters = result.second();
try {
runCheckers();
startDaos(); // daos should not be using managers and adapters.
instantiateAdapters(adapters);
instantiateManagers();
if (handler.componentClass != null) {
_component = createInstance(handler.componentClass, true, true);
}
configureManagers();
configureAdapters();
startManagers();
startAdapters();
//TODO do we need to follow the instantiate -> inject -> configure -> start -> stop flow of singletons like managers/adapters?
//TODO do we need to expose pluggableServices to MBean (provide getNames?)
instantiatePluggableServices();
} catch (CloudRuntimeException e) {
s_logger.error("Unable to load configuration for " + _serverName + " from " + filename, e);
System.exit(1);
} catch (Exception e) {
s_logger.error("Unable to load configuration for " + _serverName + " from " + filename, e);
System.exit(1);
}
}
protected void runCheckers() {
Set<Map.Entry<String, ComponentInfo<SystemIntegrityChecker>>> entries = _checkerMap.entrySet();
for (Map.Entry<String, ComponentInfo<SystemIntegrityChecker>> entry : entries) {
ComponentInfo<SystemIntegrityChecker> info = entry.getValue();
try {
info.instance = (SystemIntegrityChecker)createInstance(info.clazz, false, info.singleton);
info.instance.check();
} catch (Exception e) {
s_logger.error("Problems with running checker:" + info.name, e);
System.exit(1);
}
}
}
/**
* Daos should not refer to any other components so it is safe to start them
* here.
*/
protected void startDaos() {
Set<Map.Entry<String, ComponentInfo<GenericDao<?, ? extends Serializable>>>> entries = _daoMap.entrySet();
for (Map.Entry<String, ComponentInfo<GenericDao<?, ?>>> entry : entries) {
ComponentInfo<GenericDao<?, ?>> info = entry.getValue();
try {
info.instance = (GenericDao<?, ?>)createInstance(info.clazz, true, info.singleton);
if (info.singleton) {
s_logger.info("Starting singleton DAO: " + info.name);
Singleton singleton = s_singletons.get(info.clazz);
if (singleton.state == Singleton.State.Instantiated) {
inject(info.clazz, info.instance);
singleton.state = Singleton.State.Injected;
}
if (singleton.state == Singleton.State.Injected) {
if (!info.instance.configure(info.name, info.params)) {
s_logger.error("Unable to configure DAO: " + info.name);
System.exit(1);
}
singleton.state = Singleton.State.Started;
}
} else {
s_logger.info("Starting DAO: " + info.name);
inject(info.clazz, info.instance);
if (!info.instance.configure(info.name, info.params)) {
s_logger.error("Unable to configure DAO: " + info.name);
System.exit(1);
}
}
} catch (ConfigurationException e) {
s_logger.error("Unable to configure DAO: " + info.name, e);
System.exit(1);
} catch (Exception e) {
s_logger.error("Problems while configuring DAO: " + info.name, e);
System.exit(1);
}
if (info.instance instanceof ManagementBean) {
registerMBean((ManagementBean) info.instance);
}
}
}
private static Object createInstance(Class<?> clazz, boolean inject, boolean singleton, Object... args) {
Factory factory = null;
Singleton entity = null;
synchronized(s_factories) {
if (singleton) {
entity = s_singletons.get(clazz);
if (entity != null) {
s_logger.debug("Found singleton instantiation for " + clazz.toString());
return entity.singleton;
}
}
InjectInfo info = s_factories.get(clazz);
if (info == null) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(clazz);
enhancer.setCallbackFilter(s_callbackFilter);
enhancer.setCallbacks(s_callbacks);
factory = (Factory)enhancer.create();
info = new InjectInfo(enhancer, factory);
s_factories.put(clazz, info);
} else {
factory = info.factory;
}
}
Class<?>[] argTypes = null;
if (args != null && args.length > 0) {
Constructor<?>[] constructors = clazz.getConstructors();
for (Constructor<?> constructor : constructors) {
Class<?>[] paramTypes = constructor.getParameterTypes();
if (paramTypes.length == args.length) {
boolean found = true;
for (int i = 0; i < paramTypes.length; i++) {
if (!paramTypes[i].isAssignableFrom(args[i].getClass()) && !paramTypes[i].isPrimitive()) {
found = false;
break;
}
}
if (found) {
argTypes = paramTypes;
break;
}
}
}
if (argTypes == null) {
throw new CloudRuntimeException("Unable to find constructor to match parameters given: " + clazz.getName());
}
entity = new Singleton(factory.newInstance(argTypes, args, s_callbacks));
} else {
entity = new Singleton(factory.newInstance(s_callbacks));
}
if (inject) {
inject(clazz, entity.singleton);
entity.state = Singleton.State.Injected;
}
if (singleton) {
synchronized(s_factories) {
s_singletons.put(clazz, entity);
}
}
return entity.singleton;
}
protected ComponentInfo<GenericDao<?, ?>> getDao(String name) {
ComponentInfo<GenericDao<?, ?>> info = _daoMap.get(name);
if (info == null) {
throw new CloudRuntimeException("Unable to find DAO " + name);
}
return info;
}
public static synchronized Object getComponent(String componentName) {
synchronized(_hasCheckerRun) {
/* System Integrity checker will run before all components really loaded */
if (!_hasCheckerRun && !componentName.equalsIgnoreCase(SystemIntegrityChecker.Name)) {
ComponentLocator.getComponent(SystemIntegrityChecker.Name);
_hasCheckerRun = true;
}
}
ComponentLocator locator = s_locators.get(componentName);
if (locator == null) {
locator = ComponentLocator.getLocator(componentName);
}
return locator._component;
}
public <T extends GenericDao<?, ? extends Serializable>> T getDao(Class<T> clazz) {
ComponentInfo<GenericDao<?, ?>> info = getDao(clazz.getName());
return info != null ? (T)info.instance : null;
}
protected void instantiateManagers() {
Set<Map.Entry<String, ComponentInfo<Manager>>> entries = _managerMap.entrySet();
for (Map.Entry<String, ComponentInfo<Manager>> entry : entries) {
ComponentInfo<Manager> info = entry.getValue();
if (info.instance == null) {
s_logger.info("Instantiating Manager: " + info.name);
info.instance = (Manager)createInstance(info.clazz, false, info.singleton);
}
}
}
protected void configureManagers() {
Set<Map.Entry<String, ComponentInfo<Manager>>> entries = _managerMap.entrySet();
for (Map.Entry<String, ComponentInfo<Manager>> entry : entries) {
ComponentInfo<Manager> info = entry.getValue();
if (info.singleton) {
Singleton s = s_singletons.get(info.clazz);
if (s.state == Singleton.State.Instantiated) {
s_logger.debug("Injecting singleton Manager: " + info.name);
inject(info.clazz, info.instance);
s.state = Singleton.State.Injected;
}
} else {
s_logger.info("Injecting Manager: " + info.name);
inject(info.clazz, info.instance);
}
}
for (Map.Entry<String, ComponentInfo<Manager>> entry : entries) {
ComponentInfo<Manager> info = entry.getValue();
if (info.singleton) {
Singleton s = s_singletons.get(info.clazz);
if (s.state == Singleton.State.Injected) {
s_logger.info("Configuring singleton Manager: " + info.name);
try {
info.instance.configure(info.name, info.params);
} catch (ConfigurationException e) {
s_logger.error("Unable to configure manager: " + info.name, e);
System.exit(1);
}
s.state = Singleton.State.Configured;
}
} else {
s_logger.info("Configuring Manager: " + info.name);
try {
info.instance.configure(info.name, info.params);
} catch (ConfigurationException e) {
s_logger.error("Unable to configure manager: " + info.name, e);
System.exit(1);
}
}
}
}
protected static void inject(Class<?> clazz, Object entity) {
ComponentLocator locator = ComponentLocator.getCurrentLocator();
do {
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
Inject inject = field.getAnnotation(Inject.class);
if (inject == null) {
continue;
}
Class<?> fc = field.getType();
Object instance = null;
if (Manager.class.isAssignableFrom(fc)) {
s_logger.trace("Manager: " + fc.getName());
instance = locator.getManager(fc);
} else if (GenericDao.class.isAssignableFrom(fc)) {
s_logger.trace("Dao:" + fc.getName());
instance = locator.getDao((Class<? extends GenericDao<?, ? extends Serializable>>)fc);
} else if (Adapters.class.isAssignableFrom(fc)) {
s_logger.trace("Adapter" + fc.getName());
instance = locator.getAdapters(inject.adapter());
} else {
s_logger.trace("Other:" + fc.getName());
instance = locator.getManager(fc);
}
if (instance == null) {
throw new CloudRuntimeException("Unable to inject " + fc.getSimpleName() + " in " + clazz.getSimpleName());
}
try {
field.setAccessible(true);
field.set(entity, instance);
} catch (IllegalArgumentException e) {
throw new CloudRuntimeException("hmmm....is it really illegal?", e);
} catch (IllegalAccessException e) {
throw new CloudRuntimeException("what! what ! what!", e);
}
}
clazz = clazz.getSuperclass();
} while (clazz != Object.class && clazz != null);
}
protected void startManagers() {
Set<Map.Entry<String, ComponentInfo<Manager>>> entries = _managerMap.entrySet();
for (Map.Entry<String, ComponentInfo<Manager>> entry : entries) {
ComponentInfo<Manager> info = entry.getValue();
if (info.singleton) {
Singleton s = s_singletons.get(info.clazz);
if (s.state == Singleton.State.Configured) {
s_logger.info("Starting singleton Manager: " + info.name);
if (!info.instance.start()) {
throw new CloudRuntimeException("Incorrect Configuration: " + info.name);
}
if (info.instance instanceof ManagementBean) {
registerMBean((ManagementBean) info.instance);
}
s_logger.info("Started Manager: " + info.name);
s.state = Singleton.State.Started;
}
} else {
s_logger.info("Starting Manager: " + info.name);
if (!info.instance.start()) {
throw new CloudRuntimeException("Incorrect Configuration: " + info.name);
}
if (info.instance instanceof ManagementBean) {
registerMBean((ManagementBean) info.instance);
}
s_logger.info("Started Manager: " + info.name);
}
}
}
protected void registerMBean(ManagementBean mbean) {
try {
JmxUtil.registerMBean(mbean);
} catch (MalformedObjectNameException e) {
s_logger.warn("Unable to register MBean: " + mbean.getName(), e);
} catch (InstanceAlreadyExistsException e) {
s_logger.warn("Unable to register MBean: " + mbean.getName(), e);
} catch (MBeanRegistrationException e) {
s_logger.warn("Unable to register MBean: " + mbean.getName(), e);
} catch (NotCompliantMBeanException e) {
s_logger.warn("Unable to register MBean: " + mbean.getName(), e);
}
s_logger.info("Registered MBean: " + mbean.getName());
}
protected ComponentInfo<Manager> getManager(String name) {
ComponentInfo<Manager> mgr = _managerMap.get(name);
return mgr;
}
public <T> T getManager(Class<T> clazz) {
ComponentInfo<Manager> info = getManager(clazz.getName());
if (info == null) {
return null;
}
if (info.instance == null) {
info.instance = (Manager)createInstance(info.clazz, false, info.singleton);
}
return (T)info.instance;
}
protected void configureAdapters() {
for (Adapters<? extends Adapter> adapters : _adapterMap.values()) {
List<ComponentInfo<Adapter>> infos = adapters._infos;
for (ComponentInfo<Adapter> info : infos) {
try {
if (info.singleton) {
Singleton singleton = s_singletons.get(info.clazz);
if (singleton.state == Singleton.State.Instantiated) {
s_logger.info("Injecting singleton Adapter: " + info.getName());
inject(info.clazz, info.instance);
singleton.state = Singleton.State.Injected;
}
if (singleton.state == Singleton.State.Injected) {
s_logger.info("Configuring singleton Adapter: " + info.getName());
if (!info.instance.configure(info.name, info.params)) {
s_logger.error("Unable to configure adapter: " + info.name);
System.exit(1);
}
singleton.state = Singleton.State.Configured;
}
} else {
s_logger.info("Injecting Adapter: " + info.getName());
inject(info.clazz, info.instance);
s_logger.info("Configuring singleton Adapter: " + info.getName());
if (!info.instance.configure(info.name, info.params)) {
s_logger.error("Unable to configure adapter: " + info.name);
System.exit(1);
}
}
} catch (ConfigurationException e) {
s_logger.error("Unable to configure adapter: " + info.name, e);
System.exit(1);
} catch (Exception e) {
s_logger.error("Unable to configure adapter: " + info.name, e);
System.exit(1);
}
}
}
}
protected void populateAdapters(Map<String, List<ComponentInfo<Adapter>>> map) {
Set<Map.Entry<String, List<ComponentInfo<Adapter>>>> entries = map.entrySet();
for (Map.Entry<String, List<ComponentInfo<Adapter>>> entry : entries) {
for (ComponentInfo<Adapter> info : entry.getValue()) {
s_logger.info("Instantiating Adapter: " + info.name);
info.instance = (Adapter)createInstance(info.clazz, false, info.singleton);
}
Adapters<Adapter> adapters = new Adapters<Adapter>(entry.getKey(), entry.getValue());
_adapterMap.put(entry.getKey(), adapters);
}
}
protected void instantiateAdapters(Map<String, List<ComponentInfo<Adapter>>> map) {
Set<Map.Entry<String, List<ComponentInfo<Adapter>>>> entries = map.entrySet();
for (Map.Entry<String, List<ComponentInfo<Adapter>>> entry : entries) {
for (ComponentInfo<Adapter> info : entry.getValue()) {
s_logger.info("Instantiating Adapter: " + info.name);
info.instance = (Adapter)createInstance(info.clazz, false, info.singleton);
}
Adapters<Adapter> adapters = new Adapters<Adapter>(entry.getKey(), entry.getValue());
_adapterMap.put(entry.getKey(), adapters);
}
}
protected void startAdapters() {
for (Map.Entry<String, Adapters<? extends Adapter>> entry : _adapterMap.entrySet()) {
for (ComponentInfo<Adapter> adapter : entry.getValue()._infos) {
if (adapter.singleton) {
Singleton s = s_singletons.get(adapter.clazz);
if (s.state == Singleton.State.Configured) {
s_logger.info("Starting singleton Adapter: " + adapter.getName());
if (!adapter.instance.start()) {
throw new CloudRuntimeException("Unable to start adapter: " + adapter.getName());
}
if (adapter.instance instanceof ManagementBean) {
registerMBean((ManagementBean)adapter.instance);
}
s_logger.info("Started Adapter: " + adapter.instance.getName());
}
s.state = Singleton.State.Started;
} else {
s_logger.info("Starting Adapter: " + adapter.getName());
if (!adapter.instance.start()) {
throw new CloudRuntimeException("Unable to start adapter: " + adapter.getName());
}
if (adapter.instance instanceof ManagementBean) {
registerMBean((ManagementBean)adapter.instance);
}
s_logger.info("Started Adapter: " + adapter.instance.getName());
}
}
}
}
protected void instantiatePluggableServices() {
Set<Map.Entry<String, ComponentInfo<PluggableService>>> entries = _pluggableServicesMap.entrySet();
for (Map.Entry<String, ComponentInfo<PluggableService>> entry : entries) {
ComponentInfo<PluggableService> info = entry.getValue();
if (info.instance == null) {
s_logger.info("Instantiating PluggableService: " + info.name);
info.instance = (PluggableService)createInstance(info.clazz, false, info.singleton);
}
}
}
protected ComponentInfo<PluggableService> getPluggableService(String name) {
ComponentInfo<PluggableService> mgr = _pluggableServicesMap.get(name);
return mgr;
}
public <T> T getPluggableService(Class<T> clazz) {
ComponentInfo<PluggableService> info = getPluggableService(clazz.getName());
if (info == null) {
return null;
}
if (info.instance == null) {
info.instance = (PluggableService)createInstance(info.clazz, false, info.singleton);
}
return (T)info.instance;
}
public <T> List<T> getAllPluggableServices() {
List<T> services = new ArrayList<T>();
Set<Map.Entry<String, ComponentInfo<PluggableService>>> entries = _pluggableServicesMap.entrySet();
for (Map.Entry<String, ComponentInfo<PluggableService>> entry : entries) {
ComponentInfo<PluggableService> info = entry.getValue();
if (info.instance == null) {
s_logger.info("Instantiating PluggableService: " + info.name);
info.instance = (PluggableService)createInstance(info.clazz, false, info.singleton);
}
services.add((T) info.instance);
}
return services;
}
public static <T> T inject(Class<T> clazz) {
return (T)createInstance(clazz, true, false);
}
public <T> T createInstance(Class<T> clazz) {
Class<? extends T> impl = (Class<? extends T>)_factories.get(clazz);
if (impl == null) {
throw new CloudRuntimeException("Unable to find a factory for " + clazz);
}
return inject(impl);
}
public static <T> T inject(Class<T> clazz, Object... args) {
return (T)createInstance(clazz, true, false, args);
}
@Override
public Map<String, List<String>> getAdapterNames() {
HashMap<String, List<String>> result = new HashMap<String, List<String>>();
for (Map.Entry<String, Adapters<? extends Adapter>> entry : _adapterMap.entrySet()) {
Adapters<? extends Adapter> adapters = entry.getValue();
Enumeration<? extends Adapter> en = adapters.enumeration();
List<String> lst = new ArrayList<String>();
while (en.hasMoreElements()) {
Adapter adapter = en.nextElement();
lst.add(adapter.getName() + "-" + adapter.getClass().getName());
}
result.put(entry.getKey(), lst);
}
return result;
}
public Map<String, List<String>> getAllAccessibleAdapters() {
Map<String, List<String>> parentResults = new HashMap<String, List<String>>();
Map<String, List<String>> results = getAdapterNames();
parentResults.putAll(results);
return parentResults;
}
@Override
public Collection<String> getManagerNames() {
Collection<String> names = new HashSet<String>();
for (Map.Entry<String, ComponentInfo<Manager>> entry : _managerMap.entrySet()) {
names.add(entry.getValue().name);
}
return names;
}
@Override
public Collection<String> getDaoNames() {
Collection<String> names = new HashSet<String>();
for (Map.Entry<String, ComponentInfo<GenericDao<?, ?>>> entry : _daoMap.entrySet()) {
names.add(entry.getValue().name);
}
return names;
}
public <T extends Adapter> Adapters<T> getAdapters(Class<T> clazz) {
return (Adapters<T>)getAdapters(clazz.getName());
}
public Adapters<? extends Adapter> getAdapters(String key) {
Adapters<? extends Adapter> adapters = _adapterMap.get(key);
if (adapters != null) {
return adapters;
}
return new Adapters<Adapter>(key, new ArrayList<ComponentInfo<Adapter>>());
}
protected void resetInterceptors(InterceptorLibrary library) {
library.addInterceptors(s_interceptors);
if (s_interceptors.size() > 0) {
s_callbacks = new Callback[s_interceptors.size() + 2];
int i = 0;
s_callbacks[i++] = NoOp.INSTANCE;
s_callbacks[i++] = new InterceptorDispatcher();
for (AnnotationInterceptor<?> interceptor : s_interceptors) {
s_callbacks[i++] = interceptor.getCallback();
}
s_callbackFilter = new InterceptorFilter();
}
}
protected static ComponentLocator getLocatorInternal(String server, boolean setInThreadLocal, String configFileName, String log4jFilename) {
synchronized(s_once) {
if (!s_once) {
File file = PropertiesUtil.findConfigFile(log4jFilename + ".xml");
if (file != null) {
s_logger.info("log4j configuration found at " + file.getAbsolutePath());
DOMConfigurator.configureAndWatch(file.getAbsolutePath());
} else {
file = PropertiesUtil.findConfigFile(log4jFilename + ".properties");
if (file != null) {
s_logger.info("log4j configuration found at " + file.getAbsolutePath());
PropertyConfigurator.configureAndWatch(file.getAbsolutePath());
}
}
s_once = true;
}
}
ComponentLocator locator;
synchronized (s_locators) {
locator = s_locators.get(server);
if (locator == null) {
locator = new ComponentLocator(server);
s_locators.put(server, locator);
if (setInThreadLocal) {
s_tl.set(locator);
}
locator.parse(configFileName);
} else {
if (setInThreadLocal) {
s_tl.set(locator);
}
}
}
return locator;
}
public static ComponentLocator getLocator(String server, String configFileName, String log4jFilename) {
return getLocatorInternal(server, true, configFileName, log4jFilename);
}
public static ComponentLocator getLocator(String server) {
String configFile = null;
try {
final File propsFile = PropertiesUtil.findConfigFile("environment.properties");
if (propsFile == null) {
s_logger.debug("environment.properties could not be opened");
} else {
final FileInputStream finputstream = new FileInputStream(propsFile);
final Properties props = new Properties();
props.load(finputstream);
finputstream.close();
configFile = props.getProperty("cloud-stack-components-specification");
}
} catch (IOException e) {
s_logger.debug("environment.properties could not be loaded:" + e.toString());
}
if (configFile == null || PropertiesUtil.findConfigFile(configFile) == null) {
configFile = "components.xml";
if (PropertiesUtil.findConfigFile(configFile) == null){
s_logger.debug("Can not find components.xml");
}
}
return getLocatorInternal(server, true, configFile, "log4j-cloud");
}
public static ComponentLocator getCurrentLocator() {
return s_tl.get();
}
public static class ComponentInfo<T> {
Class<?> clazz;
HashMap<String, Object> params = new HashMap<String, Object>();
String name;
List<String> keys = new ArrayList<String>();
T instance;
boolean singleton = true;
protected ComponentInfo() {
}
public List<String> getKeys() {
return keys;
}
public String getName() {
return name;
}
public ComponentInfo(String name, Class<? extends T> clazz) {
this(name, clazz, new ArrayList<Pair<String, Object>>(0));
}
public ComponentInfo(String name, Class<? extends T> clazz, T instance) {
this(name, clazz);
this.instance = instance;
}
public ComponentInfo(String name, Class<? extends T> clazz, List<Pair<String, Object>> params) {
this(name, clazz, params, true);
}
public ComponentInfo(String name, Class<? extends T> clazz, List<Pair<String, Object>> params, boolean singleton) {
this.name = name;
this.clazz = clazz;
this.singleton = singleton;
for (Pair<String, Object> param : params) {
this.params.put(param.first(), param.second());
}
fillInfo();
}
protected void fillInfo() {
String clazzName = clazz.getName();
Local local = clazz.getAnnotation(Local.class);
if (local == null) {
throw new CloudRuntimeException("Unable to find Local annotation for class " + clazzName);
}
// Verify that all interfaces specified in the Local annotation is implemented by the class.
Class<?>[] classes = local.value();
for (int i = 0; i < classes.length; i++) {
if (!classes[i].isInterface()) {
throw new CloudRuntimeException(classes[i].getName() + " is not an interface");
}
if (classes[i].isAssignableFrom(clazz)) {
keys.add(classes[i].getName());
s_logger.info("Found component: " + classes[i].getName() + " in " + clazzName + " - " + name);
} else {
throw new CloudRuntimeException(classes[i].getName() + " is not implemented by " + clazzName);
}
}
}
public void addParameter(String name, String value) {
params.put(name, value);
}
}
/**
* XmlHandler is used by AdapterManager to handle the SAX parser callbacks.
* It builds a hash map of lists of adapters and a hash map of managers.
**/
protected class XmlHandler extends DefaultHandler {
public HashMap<String, List<ComponentInfo<Adapter>>> adapters;
public HashMap<String, ComponentInfo<Manager>> managers;
public LinkedHashMap<String, ComponentInfo<SystemIntegrityChecker>> checkers;
public LinkedHashMap<String, ComponentInfo<GenericDao<?, ?>>> daos;
public HashMap<String, ComponentInfo<PluggableService>> pluggableServices;
public String parent;
public String library;
List<ComponentInfo<Adapter>> lst;
String paramName;
StringBuilder value;
String serverName;
boolean parse;
ComponentInfo<?> currentInfo;
Class<?> componentClass;
public XmlHandler(String serverName) {
this.serverName = serverName;
parse = false;
adapters = new HashMap<String, List<ComponentInfo<Adapter>>>();
managers = new HashMap<String, ComponentInfo<Manager>>();
checkers = new LinkedHashMap<String, ComponentInfo<SystemIntegrityChecker>>();
daos = new LinkedHashMap<String, ComponentInfo<GenericDao<?, ?>>>();
pluggableServices = new HashMap<String, ComponentInfo<PluggableService>>();
value = null;
parent = null;
}
protected void fillInfo(Attributes atts, Class<?> interphace, ComponentInfo<?> info) {
String clazzName = getAttribute(atts, "class");
if (clazzName == null) {
throw new CloudRuntimeException("Missing class attribute for " + interphace.getName());
}
info.name = getAttribute(atts, "name");
if (info.name == null) {
throw new CloudRuntimeException("Missing name attribute for " + interphace.getName());
}
s_logger.debug("Looking for class " + clazzName);
try {
info.clazz = Class.forName(clazzName);
} catch (ClassNotFoundException e) {
throw new CloudRuntimeException("Unable to find class: " + clazzName);
} catch (Throwable e) {
throw new CloudRuntimeException("Caught throwable: ", e);
}
if (!interphace.isAssignableFrom(info.clazz)) {
throw new CloudRuntimeException("Class " + info.clazz.toString() + " does not implment " + interphace);
}
String singleton = getAttribute(atts, "singleton");
if (singleton != null) {
info.singleton = Boolean.parseBoolean(singleton);
}
info.fillInfo();
}
@Override
public void startElement(String namespaceURI, String localName, String qName, Attributes atts)
throws SAXException {
if (qName.equals("interceptor") && s_interceptors.size() == 0) {
synchronized(s_interceptors){
if (s_interceptors.size() == 0) {
String libraryName = getAttribute(atts, "library");
try {
Class<?> libraryClazz = Class.forName(libraryName);
InterceptorLibrary library = (InterceptorLibrary)libraryClazz.newInstance();
resetInterceptors(library);
} catch (ClassNotFoundException e) {
throw new CloudRuntimeException("Unable to find " + libraryName, e);
} catch (InstantiationException e) {
throw new CloudRuntimeException("Unable to instantiate " + libraryName, e);
} catch (IllegalAccessException e) {
throw new CloudRuntimeException("Illegal access " + libraryName, e);
}
}
}
}
if (!parse) {
if (qName.equals(_serverName)) {
parse = true;
parent = getAttribute(atts, "extends");
String implementationClass = getAttribute(atts, "class");
if (implementationClass != null) {
try {
componentClass = Class.forName(implementationClass);
} catch (ClassNotFoundException e) {
throw new CloudRuntimeException("Unable to find " + implementationClass, e);
}
}
library = getAttribute(atts, "library");
}
} else if (qName.equals("adapters")) {
lst = new ArrayList<ComponentInfo<Adapter>>();
String key = getAttribute(atts, "key");
if (key == null) {
throw new CloudRuntimeException("Missing key attribute for adapters");
}
adapters.put(key, lst);
} else if (qName.equals("adapter")) {
ComponentInfo<Adapter> info = new ComponentInfo<Adapter>();
fillInfo(atts, Adapter.class, info);
lst.add(info);
currentInfo = info;
} else if (qName.equals("manager")) {
ComponentInfo<Manager> info = new ComponentInfo<Manager>();
fillInfo(atts, Manager.class, info);
s_logger.info("Adding Manager: " + info.name);
for (String key : info.keys) {
s_logger.info("Linking " + key + " to " + info.name);
managers.put(key, info);
}
currentInfo = info;
} else if (qName.equals("param")) {
paramName = getAttribute(atts, "name");
value = new StringBuilder();
} else if (qName.equals("dao")) {
ComponentInfo<GenericDao<?, ?>> info = new ComponentInfo<GenericDao<?, ?>>();
fillInfo(atts, GenericDao.class, info);
for (String key : info.keys) {
daos.put(key, info);
}
currentInfo = info;
} else if (qName.equals("checker")) {
ComponentInfo<SystemIntegrityChecker> info = new ComponentInfo<SystemIntegrityChecker>();
fillInfo(atts, SystemIntegrityChecker.class, info);
checkers.put(info.name, info);
s_logger.info("Adding system integrity checker: " + info.name);
currentInfo = info;
} else if (qName.equals("pluggableservice")) {
ComponentInfo<PluggableService> info = new ComponentInfo<PluggableService>();
fillInfo(atts, PluggableService.class, info);
s_logger.info("Adding PluggableService: " + info.name);
String key = getAttribute(atts, "key");
if (key == null) {
throw new CloudRuntimeException("Missing key attribute for pluggableservice: "+info.name);
}
s_logger.info("Linking " + key + " to " + info.name);
pluggableServices.put(key, info);
currentInfo = info;
} else {
// ignore
}
}
protected String getAttribute(Attributes atts, String name) {
for (int att = 0; att < atts.getLength(); att++) {
String attName = atts.getQName(att);
if (attName.equals(name)) {
return atts.getValue(att);
}
}
return null;
}
@Override
public void endElement(String namespaceURI, String localName, String qName) throws SAXException {
if (!parse) {
return;
}
if (qName.equals(_serverName)) {
parse = false;
} else if (qName.equals("adapters")) {
} else if (qName.equals("adapter")) {
} else if (qName.equals("manager")) {
} else if (qName.equals("dao")) {
} else if (qName.equals("pluggableservice")) {
} else if (qName.equals("param")) {
currentInfo.params.put(paramName, value.toString());
paramName = null;
value = null;
} else {
// ignore
}
}
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
if (parse && value != null) {
value.append(ch, start, length);
}
}
}
protected static class InjectInfo {
public Factory factory;
public Enhancer enhancer;
public InjectInfo(Enhancer enhancer, Factory factory) {
this.factory = factory;
this.enhancer = enhancer;
}
}
protected static class CleanupThread extends Thread {
@Override
public void run() {
synchronized (CleanupThread.class) {
for (ComponentLocator locator : s_locators.values()) {
Iterator<Adapters<? extends Adapter>> itAdapters = locator._adapterMap.values().iterator();
while (itAdapters.hasNext()) {
Adapters<? extends Adapter> adapters = itAdapters.next();
itAdapters.remove();
for (ComponentInfo<Adapter> adapter : adapters._infos) {
if (adapter.singleton) {
Singleton singleton = s_singletons.get(adapter.clazz);
if (singleton.state == Singleton.State.Started) {
s_logger.info("Asking " + adapter.getName() + " to shutdown.");
adapter.instance.stop();
singleton.state = Singleton.State.Stopped;
} else {
s_logger.debug("Skippng " + adapter.getName() + " because it has already stopped");
}
} else {
s_logger.info("Asking " + adapter.getName() + " to shutdown.");
adapter.instance.stop();
}
}
}
}
for (ComponentLocator locator : s_locators.values()) {
Iterator<ComponentInfo<Manager>> itManagers = locator._managerMap.values().iterator();
while (itManagers.hasNext()) {
ComponentInfo<Manager> manager = itManagers.next();
itManagers.remove();
if (manager.singleton == true) {
Singleton singleton = s_singletons.get(manager.clazz);
if (singleton != null && singleton.state == Singleton.State.Started) {
s_logger.info("Asking Manager " + manager.getName() + " to shutdown.");
manager.instance.stop();
singleton.state = Singleton.State.Stopped;
} else {
s_logger.info("Skipping Manager " + manager.getName() + " because it is not in a state to shutdown.");
}
}
}
}
}
}
}
static class Singleton {
public enum State {
Instantiated,
Injected,
Configured,
Started,
Stopped
}
public Object singleton;
public State state;
public Singleton(Object singleton) {
this.singleton = singleton;
this.state = State.Instantiated;
}
}
protected class InterceptorDispatcher implements MethodInterceptor {
@Override
public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
ArrayList<Pair<AnnotationInterceptor<Object>, Object>> interceptors = new ArrayList<Pair<AnnotationInterceptor<Object>, Object>>();
for (AnnotationInterceptor<?> interceptor : s_interceptors) {
if (interceptor.needToIntercept(method)) {
Object obj = interceptor.interceptStart(method);
interceptors.add(new Pair<AnnotationInterceptor<Object>, Object>((AnnotationInterceptor<Object>)interceptor, obj));
}
}
boolean success = false;
try {
Object obj = methodProxy.invokeSuper(object, args);
success = true;
return obj;
} finally {
for (Pair<AnnotationInterceptor<Object>, Object> interceptor : interceptors) {
if (success) {
interceptor.first().interceptComplete(method, interceptor.second());
} else {
interceptor.first().interceptException(method, interceptor.second());
}
}
}
}
}
protected static class InterceptorFilter implements CallbackFilter {
@Override
public int accept(Method method) {
int index = 0;
for (int i = 2; i < s_callbacks.length; i++) {
AnnotationInterceptor<?> interceptor = (AnnotationInterceptor<?>)s_callbacks[i];
if (interceptor.needToIntercept(method)) {
if (index == 0) {
index = i;
} else {
return 1;
}
}
}
return index;
}
}
}