mirror of https://github.com/apache/cloudstack.git
NAAS: APIServer changes to introduce framework to read commands from pluggable components having separate commands.properties file
Changes: - Added a new interface 'PluggableService' - Any component that can be packaged separately from cloudstack, can implement this interface and provide its own property file listing the API commands the component supports - As an example have made VirtualNetworkApplianceService pluggable and a new configureRouter command is added - ComponentLocator reads all the pluggable service from componentLibrary or from components.xml and instantiates the services. - As an example, DefaultComponentLibrary adds the pluggable service 'VirtualNetworkApplianceService' - Also components.xml.in has an entry to show how a pluggable service can be added, but it is commented out. - APIServer now reads the commands for each pluggable service and when a command for such a service is called, APIServer sets the required instance of the pluggable service in the coomand. - To do this a new annotation '@PlugService' is added that is processed by APIServer. This eliminates the dependency on the BaseCmd to instantiate the service instances.
This commit is contained in:
parent
b2a007dc3c
commit
8570b25506
|
|
@ -25,7 +25,7 @@ import com.cloud.utils.component.Adapter;
|
|||
import com.cloud.utils.component.ComponentLibraryBase;
|
||||
import com.cloud.utils.component.ComponentLocator.ComponentInfo;
|
||||
import com.cloud.utils.component.Manager;
|
||||
import com.cloud.utils.component.SystemIntegrityChecker;
|
||||
import com.cloud.utils.component.PluggableService;
|
||||
import com.cloud.utils.db.GenericDao;
|
||||
|
||||
|
||||
|
|
@ -63,5 +63,17 @@ public class AgentComponentLibraryBase extends ComponentLibraryBase {
|
|||
protected void populateAdapters() {
|
||||
|
||||
}
|
||||
|
||||
protected void populateServices() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, ComponentInfo<PluggableService>> getPluggableServices() {
|
||||
if (_pluggableServices.size() == 0) {
|
||||
populateServices();
|
||||
}
|
||||
return _pluggableServices;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,32 @@
|
|||
/**
|
||||
* Copyright (C) 2010 Cloud.com, Inc. All rights reserved.
|
||||
*
|
||||
* This software is licensed under the GNU General Public License v3 or later.
|
||||
*
|
||||
* It is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or any later version.
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package com.cloud.api;
|
||||
|
||||
import static java.lang.annotation.ElementType.FIELD;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import com.cloud.utils.component.PluggableService;
|
||||
|
||||
@Target(FIELD)
|
||||
@Retention(RUNTIME)
|
||||
public @interface PlugService {
|
||||
Class<? extends PluggableService> pluggableService() default PluggableService.class;
|
||||
}
|
||||
|
|
@ -0,0 +1,120 @@
|
|||
/**
|
||||
* Copyright (C) 2010 Cloud.com, Inc. All rights reserved.
|
||||
*
|
||||
* This software is licensed under the GNU General Public License v3 or later.
|
||||
*
|
||||
* It is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or any later version.
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.cloud.api.commands;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import com.cloud.api.ApiConstants;
|
||||
import com.cloud.api.BaseAsyncCmd;
|
||||
import com.cloud.api.BaseCmd;
|
||||
import com.cloud.api.Implementation;
|
||||
import com.cloud.api.Parameter;
|
||||
import com.cloud.api.PlugService;
|
||||
import com.cloud.api.ServerApiException;
|
||||
import com.cloud.api.response.DomainRouterResponse;
|
||||
import com.cloud.async.AsyncJob;
|
||||
import com.cloud.event.EventTypes;
|
||||
import com.cloud.exception.ConcurrentOperationException;
|
||||
import com.cloud.exception.InsufficientCapacityException;
|
||||
import com.cloud.exception.ResourceUnavailableException;
|
||||
import com.cloud.network.VirtualNetworkApplianceService;
|
||||
import com.cloud.network.router.VirtualRouter;
|
||||
import com.cloud.user.Account;
|
||||
import com.cloud.user.UserContext;
|
||||
|
||||
|
||||
|
||||
@Implementation(responseObject=DomainRouterResponse.class, description="Configures a router.")
|
||||
public class ConfigureRouterCmd extends BaseAsyncCmd {
|
||||
public static final Logger s_logger = Logger.getLogger(ConfigureRouterCmd.class.getName());
|
||||
private static final String s_name = "configurerouterresponse";
|
||||
|
||||
@PlugService
|
||||
private static VirtualNetworkApplianceService _myrouterService;
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
//////////////// API parameters /////////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
|
||||
@Parameter(name=ApiConstants.ID, type=CommandType.LONG, required=true, description="the ID of the router")
|
||||
private Long id;
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////////// Accessors ///////////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////// API Implementation///////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public String getCommandName() {
|
||||
return s_name;
|
||||
}
|
||||
|
||||
public static String getResultObjectName() {
|
||||
return "router";
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getEntityOwnerId() {
|
||||
VirtualRouter router = _entityMgr.findById(VirtualRouter.class, getId());
|
||||
if (router != null) {
|
||||
return router.getAccountId();
|
||||
}
|
||||
|
||||
return Account.ACCOUNT_ID_SYSTEM; // no account info given, parent this command to SYSTEM so ERROR events are tracked
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEventType() {
|
||||
return EventTypes.EVENT_ROUTER_START;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEventDescription() {
|
||||
return "configuring router: " + getId();
|
||||
}
|
||||
|
||||
public AsyncJob.Type getInstanceType() {
|
||||
return AsyncJob.Type.DomainRouter;
|
||||
}
|
||||
|
||||
public Long getInstanceId() {
|
||||
return getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException{
|
||||
UserContext.current().setEventDetails("Router Id: "+getId());
|
||||
//This should call the configure API. Calling startRouter for now.
|
||||
VirtualRouter result = _myrouterService.startRouter(id);
|
||||
if (result != null){
|
||||
DomainRouterResponse routerResponse = _responseGenerator.createDomainRouterResponse(result);
|
||||
routerResponse.setResponseName(getCommandName());
|
||||
this.setResponseObject(routerResponse);
|
||||
} else {
|
||||
throw new ServerApiException(BaseCmd.INTERNAL_ERROR, "Failed to start router");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -22,8 +22,9 @@ import com.cloud.exception.ConcurrentOperationException;
|
|||
import com.cloud.exception.InsufficientCapacityException;
|
||||
import com.cloud.exception.ResourceUnavailableException;
|
||||
import com.cloud.network.router.VirtualRouter;
|
||||
import com.cloud.utils.component.PluggableService;
|
||||
|
||||
public interface VirtualNetworkApplianceService{
|
||||
public interface VirtualNetworkApplianceService extends PluggableService{
|
||||
/**
|
||||
* Starts domain router
|
||||
* @param cmd the command specifying router's id
|
||||
|
|
|
|||
|
|
@ -107,6 +107,7 @@
|
|||
<adapter name="ClusterBasedAgentLbPlanner" class="com.cloud.cluster.agentlb.ClusterBasedAgentLoadBalancerPlanner"/>
|
||||
</adapters>
|
||||
|
||||
<!-- pluggableservice name="VirtualRouterService" key="com.cloud.network.VirtualNetworkApplianceService" class="com.cloud.network.router.VirtualNetworkApplianceManagerImpl"/ -->
|
||||
</management-server>
|
||||
|
||||
<configuration-server class="com.cloud.server.ConfigurationServerImpl">
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
### bitmap of permissions at the end of each classname, 1 = ADMIN, 2 = RESOURCE_DOMAIN_ADMIN, 4 = DOMAIN_ADMIN, 8 = USER
|
||||
### Please standardize naming conventions to camel-case (even for acronyms).
|
||||
|
||||
#### router commands
|
||||
configureRouter=com.cloud.api.commands.ConfigureRouterCmd;7
|
||||
|
|
@ -45,6 +45,7 @@ import com.cloud.user.Account;
|
|||
import com.cloud.user.UserContext;
|
||||
import com.cloud.utils.DateUtil;
|
||||
import com.cloud.utils.component.ComponentLocator;
|
||||
import com.cloud.utils.component.PluggableService;
|
||||
import com.cloud.utils.exception.CloudRuntimeException;
|
||||
|
||||
/**
|
||||
|
|
@ -71,6 +72,7 @@ public class ApiDispatcher {
|
|||
public void dispatchCreateCmd(BaseAsyncCreateCmd cmd, Map<String, String> params) {
|
||||
|
||||
setupParameters(cmd, params);
|
||||
plugService(cmd);
|
||||
|
||||
try {
|
||||
UserContext ctx = UserContext.current();
|
||||
|
|
@ -113,6 +115,7 @@ public class ApiDispatcher {
|
|||
|
||||
public void dispatch(BaseCmd cmd, Map<String, String> params) {
|
||||
setupParameters(cmd, params);
|
||||
ApiDispatcher.plugService(cmd);
|
||||
try {
|
||||
UserContext ctx = UserContext.current();
|
||||
ctx.setAccountId(cmd.getEntityOwnerId());
|
||||
|
|
@ -329,4 +332,44 @@ public class ApiDispatcher {
|
|||
cal.set(Calendar.SECOND, second);
|
||||
return cal.getTime();
|
||||
}
|
||||
|
||||
public static void plugService(BaseCmd cmd) {
|
||||
|
||||
if(!ApiServer.isPluggableServiceCommand(cmd.getClass().getName())){
|
||||
return;
|
||||
}
|
||||
Class<?> clazz = cmd.getClass();
|
||||
ComponentLocator locator = ComponentLocator.getLocator(ManagementServer.Name);
|
||||
do {
|
||||
Field[] fields = clazz.getDeclaredFields();
|
||||
for (Field field : fields) {
|
||||
PlugService plugService = field.getAnnotation(PlugService.class);
|
||||
if (plugService == null) {
|
||||
continue;
|
||||
}
|
||||
Class<?> fc = field.getType();
|
||||
Object instance = null;
|
||||
if (PluggableService.class.isAssignableFrom(fc)) {
|
||||
instance = locator.getPluggableService(fc);
|
||||
}
|
||||
|
||||
if (instance == null) {
|
||||
throw new CloudRuntimeException("Unable to plug service " + fc.getSimpleName() + " in command " + clazz.getSimpleName());
|
||||
}
|
||||
|
||||
try {
|
||||
field.setAccessible(true);
|
||||
field.set(cmd, instance);
|
||||
} catch (IllegalArgumentException e) {
|
||||
s_logger.error("IllegalArgumentException at plugService for command " + cmd.getCommandName() + ", field " + field.getName());
|
||||
throw new CloudRuntimeException("Internal error at plugService for command " + cmd.getCommandName() + " [Illegal argumet at field " + field.getName() + "]");
|
||||
} catch (IllegalAccessException e) {
|
||||
s_logger.error("Error at plugService for command " + cmd.getCommandName() + ", field " + field.getName() + " is not accessible.");
|
||||
throw new CloudRuntimeException("Internal error at plugService for command " + cmd.getCommandName() + " [field " + field.getName() + " is not accessible]");
|
||||
}
|
||||
}
|
||||
clazz = clazz.getSuperclass();
|
||||
} while (clazz != Object.class && clazz != null);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -107,6 +107,7 @@ import com.cloud.user.UserContext;
|
|||
import com.cloud.utils.Pair;
|
||||
import com.cloud.utils.PropertiesUtil;
|
||||
import com.cloud.utils.component.ComponentLocator;
|
||||
import com.cloud.utils.component.PluggableService;
|
||||
import com.cloud.utils.concurrency.NamedThreadFactory;
|
||||
import com.cloud.utils.db.SearchCriteria;
|
||||
import com.cloud.utils.db.Transaction;
|
||||
|
|
@ -138,6 +139,7 @@ public class ApiServer implements HttpRequestHandler {
|
|||
private static List<String> s_adminCommands = null;
|
||||
private static List<String> s_resourceDomainAdminCommands = null;
|
||||
private static List<String> s_allCommands = null;
|
||||
private static List<String> s_pluggableServiceCommands = null;
|
||||
private static final DateFormat _dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
|
||||
|
||||
private static ExecutorService _executor = new ThreadPoolExecutor(10, 150, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(), new NamedThreadFactory("ApiServer"));
|
||||
|
|
@ -148,6 +150,7 @@ public class ApiServer implements HttpRequestHandler {
|
|||
s_adminCommands = new ArrayList<String>();
|
||||
s_resourceDomainAdminCommands = new ArrayList<String>();
|
||||
s_allCommands = new ArrayList<String>();
|
||||
s_pluggableServiceCommands = new ArrayList<String>();
|
||||
}
|
||||
|
||||
private ApiServer() {
|
||||
|
|
@ -168,12 +171,32 @@ public class ApiServer implements HttpRequestHandler {
|
|||
public Properties get_apiCommands() {
|
||||
return _apiCommands;
|
||||
}
|
||||
|
||||
public static boolean isPluggableServiceCommand(String cmdClassName){
|
||||
if(s_pluggableServiceCommands != null){
|
||||
if(s_pluggableServiceCommands.contains(cmdClassName)){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void init(String[] apiConfig) {
|
||||
try {
|
||||
BaseCmd.setComponents(new ApiResponseHelper());
|
||||
BaseListCmd.configure();
|
||||
_apiCommands = new Properties();
|
||||
private String[] getPluggableServicesApiConfigs(){
|
||||
List<String> pluggableServicesApiConfigs = new ArrayList<String>();
|
||||
|
||||
ComponentLocator locator = ComponentLocator.getLocator(ManagementServer.Name);
|
||||
List<PluggableService> services = locator.getAllPluggableServices();
|
||||
for(PluggableService service : services){
|
||||
pluggableServicesApiConfigs.add(service.getPropertiesFile());
|
||||
}
|
||||
return pluggableServicesApiConfigs.toArray(new String[0]);
|
||||
}
|
||||
|
||||
private void processConfigFiles(String[] apiConfig, boolean pluggableServicesConfig){
|
||||
try{
|
||||
if(_apiCommands == null){
|
||||
_apiCommands = new Properties();
|
||||
}
|
||||
Properties preProcessedCommands = new Properties();
|
||||
if (apiConfig != null) {
|
||||
for (String configFile : apiConfig) {
|
||||
|
|
@ -184,6 +207,11 @@ public class ApiServer implements HttpRequestHandler {
|
|||
String preProcessedCommand = preProcessedCommands.getProperty((String) key);
|
||||
String[] commandParts = preProcessedCommand.split(";");
|
||||
_apiCommands.put(key, commandParts[0]);
|
||||
|
||||
if(pluggableServicesConfig){
|
||||
s_pluggableServiceCommands.add(commandParts[0]);
|
||||
}
|
||||
|
||||
if (commandParts.length > 1) {
|
||||
try {
|
||||
short cmdPermissions = Short.parseShort(commandParts[1]);
|
||||
|
|
@ -204,7 +232,7 @@ public class ApiServer implements HttpRequestHandler {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
s_allCommands.addAll(s_adminCommands);
|
||||
s_allCommands.addAll(s_resourceDomainAdminCommands);
|
||||
s_allCommands.addAll(s_userCommands);
|
||||
|
|
@ -215,6 +243,16 @@ public class ApiServer implements HttpRequestHandler {
|
|||
} catch (IOException ioex) {
|
||||
s_logger.error("Exception loading properties file", ioex);
|
||||
}
|
||||
}
|
||||
|
||||
public void init(String[] apiConfig) {
|
||||
BaseCmd.setComponents(new ApiResponseHelper());
|
||||
BaseListCmd.configure();
|
||||
processConfigFiles(apiConfig, false);
|
||||
|
||||
//get commands for all pluggable services
|
||||
String[] pluggableServicesApiConfigs = getPluggableServicesApiConfigs();
|
||||
processConfigFiles(pluggableServicesApiConfigs, true);
|
||||
|
||||
ComponentLocator locator = ComponentLocator.getLocator(ManagementServer.Name);
|
||||
_accountMgr = locator.getManager(AccountManager.class);
|
||||
|
|
@ -400,6 +438,7 @@ public class ApiServer implements HttpRequestHandler {
|
|||
params.put("id", objectId.toString());
|
||||
} else {
|
||||
ApiDispatcher.setupParameters(cmdObj, params);
|
||||
ApiDispatcher.plugService(cmdObj);
|
||||
}
|
||||
|
||||
BaseAsyncCmd asyncCmd = (BaseAsyncCmd) cmdObj;
|
||||
|
|
|
|||
|
|
@ -70,6 +70,7 @@ import com.cloud.keystore.KeystoreManagerImpl;
|
|||
import com.cloud.maint.UpgradeManagerImpl;
|
||||
import com.cloud.maint.dao.AgentUpgradeDaoImpl;
|
||||
import com.cloud.network.NetworkManagerImpl;
|
||||
import com.cloud.network.VirtualNetworkApplianceService;
|
||||
import com.cloud.network.dao.FirewallRulesCidrsDaoImpl;
|
||||
import com.cloud.network.dao.FirewallRulesDaoImpl;
|
||||
import com.cloud.network.dao.IPAddressDaoImpl;
|
||||
|
|
@ -153,6 +154,7 @@ import com.cloud.utils.component.ComponentLibrary;
|
|||
import com.cloud.utils.component.ComponentLibraryBase;
|
||||
import com.cloud.utils.component.ComponentLocator.ComponentInfo;
|
||||
import com.cloud.utils.component.Manager;
|
||||
import com.cloud.utils.component.PluggableService;
|
||||
import com.cloud.utils.db.GenericDao;
|
||||
import com.cloud.vm.ClusteredVirtualMachineManagerImpl;
|
||||
import com.cloud.vm.ItWorkDaoImpl;
|
||||
|
|
@ -363,4 +365,16 @@ public class DefaultComponentLibrary extends ComponentLibraryBase implements Com
|
|||
factories.put(EntityManager.class, EntityManagerImpl.class);
|
||||
return factories;
|
||||
}
|
||||
|
||||
protected void populateServices() {
|
||||
addService("VirtualRouterService", VirtualNetworkApplianceService.class, VirtualNetworkApplianceManagerImpl.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized Map<String, ComponentInfo<PluggableService>> getPluggableServices() {
|
||||
if (_pluggableServices.size() == 0) {
|
||||
populateServices();
|
||||
}
|
||||
return _pluggableServices;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2742,4 +2742,10 @@ public class VirtualNetworkApplianceManagerImpl implements VirtualNetworkApplian
|
|||
public boolean processTimeout(long agentId, long seq) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPropertiesFile() {
|
||||
return "virtualrouter_commands.properties";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,4 +51,9 @@ public interface ComponentLibrary {
|
|||
|
||||
Map<Class<?>, Class<?>> getFactories();
|
||||
|
||||
/**
|
||||
* @return all the services
|
||||
*
|
||||
*/
|
||||
Map<String, ComponentInfo<PluggableService>> getPluggableServices();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ public abstract class ComponentLibraryBase implements ComponentLibrary {
|
|||
|
||||
protected Map<String, ComponentInfo<Manager>> _managers = new LinkedHashMap<String, ComponentInfo<Manager>>();
|
||||
protected Map<String, List<ComponentInfo<Adapter>>> _adapters = new LinkedHashMap<String, List<ComponentInfo<Adapter>>>();
|
||||
protected Map<String, ComponentInfo<PluggableService>> _pluggableServices = new LinkedHashMap<String, ComponentInfo<PluggableService>>();
|
||||
|
||||
protected ComponentInfo<Manager> addManager(String name, Class<? extends Manager> clazz, List<Pair<String, Object>> params, boolean singleton) {
|
||||
ComponentInfo<Manager> info = new ComponentInfo<Manager>(name, clazz, params, singleton);
|
||||
|
|
@ -85,4 +86,15 @@ public abstract class ComponentLibraryBase implements ComponentLibrary {
|
|||
adapters.add(new Pair<String, Class<? extends T>>(name, adapterClass));
|
||||
return addAdapterChain(interphace, adapters).get(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected <T> ComponentInfo<PluggableService> addService(String name, Class<T> serviceInterphace, Class<? extends PluggableService> clazz, List<Pair<String, Object>> params, boolean singleton) {
|
||||
ComponentInfo<PluggableService> info = new ComponentInfo<PluggableService>(name, clazz, params, singleton);
|
||||
_pluggableServices.put(serviceInterphace.getName(), info);
|
||||
return info;
|
||||
}
|
||||
|
||||
protected <T> ComponentInfo<PluggableService> addService(String name, Class<T> serviceInterphace, Class<? extends PluggableService> clazz) {
|
||||
return addService(name, serviceInterphace, clazz, new ArrayList<Pair<String, Object>>(), true);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -64,7 +64,6 @@ import org.xml.sax.helpers.DefaultHandler;
|
|||
|
||||
import com.cloud.utils.Pair;
|
||||
import com.cloud.utils.PropertiesUtil;
|
||||
import com.cloud.utils.Ternary;
|
||||
import com.cloud.utils.db.DatabaseCallback;
|
||||
import com.cloud.utils.db.DatabaseCallbackFilter;
|
||||
import com.cloud.utils.db.GenericDao;
|
||||
|
|
@ -100,6 +99,7 @@ public class ComponentLocator implements ComponentLocatorMBean {
|
|||
protected String _serverName;
|
||||
protected Object _component;
|
||||
protected HashMap<Class<?>, Class<?>> _factories;
|
||||
protected HashMap<String, ComponentInfo<PluggableService>> _pluggableServicesMap;
|
||||
|
||||
static {
|
||||
if (s_janitor == null) {
|
||||
|
|
@ -134,6 +134,7 @@ public class ComponentLocator implements ComponentLocatorMBean {
|
|||
_checkerMap = new HashMap<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);
|
||||
|
|
@ -157,6 +158,7 @@ public class ComponentLocator implements ComponentLocatorMBean {
|
|||
_daoMap.putAll(parentLocator._daoMap);
|
||||
_managerMap.putAll(parentLocator._managerMap);
|
||||
_factories.putAll(parentLocator._factories);
|
||||
_pluggableServicesMap.putAll(parentLocator._pluggableServicesMap);
|
||||
}
|
||||
|
||||
ComponentLibrary library = null;
|
||||
|
|
@ -167,12 +169,14 @@ public class ComponentLocator implements ComponentLocatorMBean {
|
|||
_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) {
|
||||
|
|
@ -215,6 +219,9 @@ public class ComponentLocator implements ComponentLocatorMBean {
|
|||
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);
|
||||
|
|
@ -634,6 +641,47 @@ public class ComponentLocator implements ComponentLocatorMBean {
|
|||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
@ -868,6 +916,7 @@ public class ComponentLocator implements ComponentLocatorMBean {
|
|||
public HashMap<String, ComponentInfo<Manager>> managers;
|
||||
public HashMap<String, ComponentInfo<SystemIntegrityChecker>> checkers;
|
||||
public LinkedHashMap<String, ComponentInfo<GenericDao<?, ?>>> daos;
|
||||
public HashMap<String, ComponentInfo<PluggableService>> pluggableServices;
|
||||
public String parent;
|
||||
public String library;
|
||||
|
||||
|
|
@ -886,6 +935,7 @@ public class ComponentLocator implements ComponentLocatorMBean {
|
|||
managers = new HashMap<String, ComponentInfo<Manager>>();
|
||||
checkers = new HashMap<String, ComponentInfo<SystemIntegrityChecker>>();
|
||||
daos = new LinkedHashMap<String, ComponentInfo<GenericDao<?, ?>>>();
|
||||
pluggableServices = new HashMap<String, ComponentInfo<PluggableService>>();
|
||||
value = null;
|
||||
parent = null;
|
||||
}
|
||||
|
|
@ -992,6 +1042,17 @@ public class ComponentLocator implements ComponentLocatorMBean {
|
|||
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
|
||||
}
|
||||
|
|
@ -1019,6 +1080,7 @@ public class ComponentLocator implements ComponentLocatorMBean {
|
|||
} 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;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,31 @@
|
|||
/**
|
||||
* Copyright (C) 2010 Cloud.com, Inc. All rights reserved.
|
||||
*
|
||||
* This software is licensed under the GNU General Public License v3 or later.
|
||||
*
|
||||
* It is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or any later version.
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package com.cloud.utils.component;
|
||||
|
||||
|
||||
/**
|
||||
* This interface defines methods for pluggable code within the Cloud Stack.
|
||||
*/
|
||||
public interface PluggableService {
|
||||
|
||||
/**
|
||||
* The config file name that lists API commands supported by this pluggable service
|
||||
*/
|
||||
String getPropertiesFile();
|
||||
|
||||
}
|
||||
|
|
@ -18,7 +18,6 @@
|
|||
package com.cloud.utils.component;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
|
|
@ -28,8 +27,6 @@ import net.sf.cglib.proxy.Callback;
|
|||
import net.sf.cglib.proxy.NoOp;
|
||||
|
||||
import com.cloud.utils.Pair;
|
||||
import com.cloud.utils.Ternary;
|
||||
import com.cloud.utils.component.ComponentLocator.ComponentInfo;
|
||||
import com.cloud.utils.db.DatabaseCallback;
|
||||
import com.cloud.utils.db.DatabaseCallbackFilter;
|
||||
import com.cloud.utils.db.GenericDao;
|
||||
|
|
@ -62,6 +59,10 @@ public class MockComponentLocator extends ComponentLocator {
|
|||
return _library.addAdapterChain(interphace, adapters);
|
||||
}
|
||||
|
||||
public ComponentInfo<PluggableService> addService(String name, Class<? extends PluggableService> service) {
|
||||
return _library.addService(name, service);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Pair<XmlHandler, HashMap<String, List<ComponentInfo<Adapter>>>> parse2(String filename) {
|
||||
Pair<XmlHandler, HashMap<String, List<ComponentInfo<Adapter>>>> result = new Pair<XmlHandler, HashMap<String, List<ComponentInfo<Adapter>>>>(new XmlHandler("fake"), new HashMap<String, List<ComponentInfo<Adapter>>>());
|
||||
|
|
@ -110,5 +111,10 @@ public class MockComponentLocator extends ComponentLocator {
|
|||
public Map<String, ComponentInfo<Manager>> getManagers() {
|
||||
return _managers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, ComponentInfo<PluggableService>> getPluggableServices() {
|
||||
return _pluggableServices;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue