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:
prachi 2011-10-11 17:34:32 -07:00
parent b2a007dc3c
commit 8570b25506
15 changed files with 402 additions and 13 deletions

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -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");
}
}
}

View File

@ -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

View File

@ -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">

View File

@ -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

View File

@ -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);
}
}

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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";
}
}

View File

@ -51,4 +51,9 @@ public interface ComponentLibrary {
Map<Class<?>, Class<?>> getFactories();
/**
* @return all the services
*
*/
Map<String, ComponentInfo<PluggableService>> getPluggableServices();
}

View File

@ -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);
}
}

View File

@ -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;

View File

@ -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();
}

View File

@ -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;
}
}
}