mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
ApiDiscovery: Fix listApis to return api response, related apis etc.
- Fix method to return listApis per api name basis - Return api response, api related cmd etc. as part of response - Caching and processing all cmd, response classes when plugin starts, made class list, maps static so they are shared by multiple instances in case, takes about 1306ms to do the processsing but only on load time - Cache for first listApi() and return precached data thereon, takes 2.2ms for first call, during runtime and 0ms thereon Signed-off-by: Rohit Yadav <bhaisaab@apache.org>
This commit is contained in:
parent
f170075558
commit
86a77e29dc
@ -158,6 +158,7 @@ public class ApiConstants {
|
|||||||
public static final String RECEIVED_BYTES = "receivedbytes";
|
public static final String RECEIVED_BYTES = "receivedbytes";
|
||||||
public static final String REQUIRES_HVM = "requireshvm";
|
public static final String REQUIRES_HVM = "requireshvm";
|
||||||
public static final String RESOURCE_TYPE = "resourcetype";
|
public static final String RESOURCE_TYPE = "resourcetype";
|
||||||
|
public static final String RESPONSE = "response";
|
||||||
public static final String QUERY_FILTER = "queryfilter";
|
public static final String QUERY_FILTER = "queryfilter";
|
||||||
public static final String SCHEDULE = "schedule";
|
public static final String SCHEDULE = "schedule";
|
||||||
public static final String SCOPE = "scope";
|
public static final String SCOPE = "scope";
|
||||||
|
|||||||
@ -16,12 +16,12 @@
|
|||||||
// under the License.
|
// under the License.
|
||||||
package org.apache.cloudstack.api.command.user.discovery;
|
package org.apache.cloudstack.api.command.user.discovery;
|
||||||
|
|
||||||
import com.cloud.user.Account;
|
|
||||||
import com.cloud.user.UserContext;
|
import com.cloud.user.UserContext;
|
||||||
import org.apache.cloudstack.acl.RoleType;
|
import org.apache.cloudstack.acl.RoleType;
|
||||||
import org.apache.cloudstack.api.APICommand;
|
import org.apache.cloudstack.api.APICommand;
|
||||||
|
import org.apache.cloudstack.api.ApiConstants;
|
||||||
import org.apache.cloudstack.api.BaseCmd;
|
import org.apache.cloudstack.api.BaseCmd;
|
||||||
import org.apache.cloudstack.api.BaseListCmd;
|
import org.apache.cloudstack.api.Parameter;
|
||||||
import org.apache.cloudstack.api.PlugService;
|
import org.apache.cloudstack.api.PlugService;
|
||||||
import org.apache.cloudstack.api.ServerApiException;
|
import org.apache.cloudstack.api.ServerApiException;
|
||||||
import org.apache.cloudstack.api.response.ListResponse;
|
import org.apache.cloudstack.api.response.ListResponse;
|
||||||
@ -30,8 +30,8 @@ import org.apache.cloudstack.api.response.ApiDiscoveryResponse;
|
|||||||
|
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
@APICommand(name = "listApis", responseObject = ApiDiscoveryResponse.class, description = "lists all available apis on the server, provided by Api Discovery plugin", since = "4.1.0")
|
@APICommand(name = "listApis", responseObject = ApiDiscoveryResponse.class, description = "lists all available apis on the server, provided by the Api Discovery plugin", since = "4.1.0")
|
||||||
public class ListApisCmd extends BaseListCmd {
|
public class ListApisCmd extends BaseCmd {
|
||||||
|
|
||||||
public static final Logger s_logger = Logger.getLogger(ListApisCmd.class.getName());
|
public static final Logger s_logger = Logger.getLogger(ListApisCmd.class.getName());
|
||||||
private static final String s_name = "listapisresponse";
|
private static final String s_name = "listapisresponse";
|
||||||
@ -39,14 +39,16 @@ public class ListApisCmd extends BaseListCmd {
|
|||||||
@PlugService
|
@PlugService
|
||||||
ApiDiscoveryService _apiDiscoveryService;
|
ApiDiscoveryService _apiDiscoveryService;
|
||||||
|
|
||||||
|
@Parameter(name=ApiConstants.NAME, type=CommandType.STRING, description="API name")
|
||||||
|
private String name;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute() throws ServerApiException {
|
public void execute() throws ServerApiException {
|
||||||
if (_apiDiscoveryService != null) {
|
if (_apiDiscoveryService != null) {
|
||||||
Account caller = UserContext.current().getCaller();
|
|
||||||
RoleType roleType = _accountService.getRoleType(UserContext.current().getCaller());
|
RoleType roleType = _accountService.getRoleType(UserContext.current().getCaller());
|
||||||
ListResponse<ApiDiscoveryResponse> response = (ListResponse<ApiDiscoveryResponse>) _apiDiscoveryService.listApis(roleType);
|
ListResponse<ApiDiscoveryResponse> response = (ListResponse<ApiDiscoveryResponse>) _apiDiscoveryService.listApis(roleType, name);
|
||||||
if (response == null) {
|
if (response == null) {
|
||||||
throw new ServerApiException(BaseCmd.INTERNAL_ERROR, "Api Discovery plugin was unable to find and process any apis");
|
throw new ServerApiException(BaseCmd.INTERNAL_ERROR, "Api Discovery plugin was unable to find an api by that name or process any apis");
|
||||||
}
|
}
|
||||||
response.setResponseName(getCommandName());
|
response.setResponseName(getCommandName());
|
||||||
this.setResponseObject(response);
|
this.setResponseObject(response);
|
||||||
@ -57,4 +59,10 @@ public class ListApisCmd extends BaseListCmd {
|
|||||||
public String getCommandName() {
|
public String getCommandName() {
|
||||||
return s_name;
|
return s_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getEntityOwnerId() {
|
||||||
|
// no owner is needed for list command
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -22,5 +22,5 @@ import org.apache.cloudstack.api.BaseResponse;
|
|||||||
import org.apache.cloudstack.api.response.ListResponse;
|
import org.apache.cloudstack.api.response.ListResponse;
|
||||||
|
|
||||||
public interface ApiDiscoveryService extends PluggableService {
|
public interface ApiDiscoveryService extends PluggableService {
|
||||||
ListResponse<? extends BaseResponse> listApis(RoleType roleType);
|
ListResponse<? extends BaseResponse> listApis(RoleType roleType, String apiName);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,13 +16,13 @@
|
|||||||
// under the License.
|
// under the License.
|
||||||
package org.apache.cloudstack.discovery;
|
package org.apache.cloudstack.discovery;
|
||||||
|
|
||||||
|
import com.cloud.serializer.Param;
|
||||||
import com.cloud.server.ManagementServer;
|
import com.cloud.server.ManagementServer;
|
||||||
import com.cloud.utils.ReflectUtil;
|
import com.cloud.utils.ReflectUtil;
|
||||||
import com.cloud.utils.component.Adapters;
|
import com.cloud.utils.StringUtils;
|
||||||
import com.cloud.utils.component.ComponentLocator;
|
import com.cloud.utils.component.ComponentLocator;
|
||||||
import com.cloud.utils.component.Inject;
|
|
||||||
import com.cloud.utils.component.PluggableService;
|
import com.cloud.utils.component.PluggableService;
|
||||||
import org.apache.cloudstack.acl.APIChecker;
|
import com.google.gson.annotations.SerializedName;
|
||||||
import org.apache.cloudstack.acl.RoleType;
|
import org.apache.cloudstack.acl.RoleType;
|
||||||
import org.apache.cloudstack.api.APICommand;
|
import org.apache.cloudstack.api.APICommand;
|
||||||
import org.apache.cloudstack.api.BaseCmd;
|
import org.apache.cloudstack.api.BaseCmd;
|
||||||
@ -32,6 +32,7 @@ import org.apache.cloudstack.api.BaseResponse;
|
|||||||
import org.apache.cloudstack.api.Parameter;
|
import org.apache.cloudstack.api.Parameter;
|
||||||
import org.apache.cloudstack.api.response.ApiDiscoveryResponse;
|
import org.apache.cloudstack.api.response.ApiDiscoveryResponse;
|
||||||
import org.apache.cloudstack.api.response.ApiParameterResponse;
|
import org.apache.cloudstack.api.response.ApiParameterResponse;
|
||||||
|
import org.apache.cloudstack.api.response.ApiResponseResponse;
|
||||||
import org.apache.cloudstack.api.response.ListResponse;
|
import org.apache.cloudstack.api.response.ListResponse;
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
@ -39,6 +40,7 @@ import javax.ejb.Local;
|
|||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@ -47,19 +49,24 @@ import java.util.Set;
|
|||||||
public class ApiDiscoveryServiceImpl implements ApiDiscoveryService {
|
public class ApiDiscoveryServiceImpl implements ApiDiscoveryService {
|
||||||
private static final Logger s_logger = Logger.getLogger(ApiDiscoveryServiceImpl.class);
|
private static final Logger s_logger = Logger.getLogger(ApiDiscoveryServiceImpl.class);
|
||||||
|
|
||||||
|
private static Map<RoleType, List<ApiDiscoveryResponse>> _roleTypeDiscoveryResponseListMap;
|
||||||
|
|
||||||
private static Map<String, ApiDiscoveryResponse> _apiNameDiscoveryResponseMap =
|
private static Map<String, ApiDiscoveryResponse> _apiNameDiscoveryResponseMap =
|
||||||
new HashMap<String, ApiDiscoveryResponse>();
|
new HashMap<String, ApiDiscoveryResponse>();
|
||||||
|
|
||||||
private static Map<RoleType, List<ApiDiscoveryResponse>> _roleTypeDiscoveryResponseListMap =
|
|
||||||
new HashMap<RoleType, List<ApiDiscoveryResponse>>();
|
|
||||||
|
|
||||||
private static Map<String, List<RoleType>> _apiNameRoleTypeListMap = null;
|
private static Map<String, List<RoleType>> _apiNameRoleTypeListMap = null;
|
||||||
|
|
||||||
protected ApiDiscoveryServiceImpl() {
|
protected ApiDiscoveryServiceImpl() {
|
||||||
super();
|
super();
|
||||||
for (RoleType roleType: RoleType.values())
|
if (_roleTypeDiscoveryResponseListMap == null) {
|
||||||
_roleTypeDiscoveryResponseListMap.put(roleType, new ArrayList<ApiDiscoveryResponse>());
|
long startTime = System.nanoTime();
|
||||||
cacheListApiResponse();
|
_roleTypeDiscoveryResponseListMap = new HashMap<RoleType, List<ApiDiscoveryResponse>>();
|
||||||
|
for (RoleType roleType: RoleType.values())
|
||||||
|
_roleTypeDiscoveryResponseListMap.put(roleType, new ArrayList<ApiDiscoveryResponse>());
|
||||||
|
cacheResponseMap();
|
||||||
|
long endTime = System.nanoTime();
|
||||||
|
s_logger.info("Api Discovery Service: Annotation, docstrings, api relation graph processed in " + (endTime - startTime) / 1000000.0 + " ms");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<String, List<RoleType>> getApiNameRoleTypeListMap() {
|
private Map<String, List<RoleType>> getApiNameRoleTypeListMap() {
|
||||||
@ -86,10 +93,12 @@ public class ApiDiscoveryServiceImpl implements ApiDiscoveryService {
|
|||||||
return apiNameRoleTypeMap;
|
return apiNameRoleTypeMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void cacheListApiResponse() {
|
private void cacheResponseMap() {
|
||||||
Set<Class<?>> cmdClasses = ReflectUtil.getClassesWithAnnotation(APICommand.class,
|
Set<Class<?>> cmdClasses = ReflectUtil.getClassesWithAnnotation(APICommand.class,
|
||||||
new String[]{"org.apache.cloudstack.api", "com.cloud.api"});
|
new String[]{"org.apache.cloudstack.api", "com.cloud.api"});
|
||||||
|
|
||||||
|
Map<String, List<String>> responseApiNameListMap = new HashMap<String, List<String>>();
|
||||||
|
|
||||||
for(Class<?> cmdClass: cmdClasses) {
|
for(Class<?> cmdClass: cmdClasses) {
|
||||||
APICommand apiCmdAnnotation = cmdClass.getAnnotation(APICommand.class);
|
APICommand apiCmdAnnotation = cmdClass.getAnnotation(APICommand.class);
|
||||||
if (apiCmdAnnotation == null)
|
if (apiCmdAnnotation == null)
|
||||||
@ -100,10 +109,32 @@ public class ApiDiscoveryServiceImpl implements ApiDiscoveryService {
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
String apiName = apiCmdAnnotation.name();
|
String apiName = apiCmdAnnotation.name();
|
||||||
|
String responseName = apiCmdAnnotation.responseObject().getName();
|
||||||
|
if (!responseName.contains("SuccessResponse")) {
|
||||||
|
if (!responseApiNameListMap.containsKey(responseName))
|
||||||
|
responseApiNameListMap.put(responseName, new ArrayList<String>());
|
||||||
|
responseApiNameListMap.get(responseName).add(apiName);
|
||||||
|
}
|
||||||
ApiDiscoveryResponse response = new ApiDiscoveryResponse();
|
ApiDiscoveryResponse response = new ApiDiscoveryResponse();
|
||||||
response.setName(apiName);
|
response.setName(apiName);
|
||||||
response.setDescription(apiCmdAnnotation.description());
|
response.setDescription(apiCmdAnnotation.description());
|
||||||
response.setSince(apiCmdAnnotation.since());
|
if (!apiCmdAnnotation.since().isEmpty())
|
||||||
|
response.setSince(apiCmdAnnotation.since());
|
||||||
|
response.setRelated(responseName);
|
||||||
|
|
||||||
|
Field[] responseFields = apiCmdAnnotation.responseObject().getDeclaredFields();
|
||||||
|
for(Field responseField: responseFields) {
|
||||||
|
SerializedName serializedName = responseField.getAnnotation(SerializedName.class);
|
||||||
|
if(serializedName != null) {
|
||||||
|
ApiResponseResponse responseResponse = new ApiResponseResponse();
|
||||||
|
responseResponse.setName(serializedName.value());
|
||||||
|
Param param = responseField.getAnnotation(Param.class);
|
||||||
|
if (param != null)
|
||||||
|
responseResponse.setDescription(param.description());
|
||||||
|
responseResponse.setType(responseField.getType().getSimpleName().toLowerCase());
|
||||||
|
response.addApiResponse(responseResponse);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Field[] fields = ReflectUtil.getAllFieldsForClass(cmdClass,
|
Field[] fields = ReflectUtil.getAllFieldsForClass(cmdClass,
|
||||||
new Class<?>[] {BaseCmd.class, BaseAsyncCmd.class, BaseAsyncCreateCmd.class});
|
new Class<?>[] {BaseCmd.class, BaseAsyncCmd.class, BaseAsyncCreateCmd.class});
|
||||||
@ -122,23 +153,50 @@ public class ApiDiscoveryServiceImpl implements ApiDiscoveryService {
|
|||||||
ApiParameterResponse paramResponse = new ApiParameterResponse();
|
ApiParameterResponse paramResponse = new ApiParameterResponse();
|
||||||
paramResponse.setName(parameterAnnotation.name());
|
paramResponse.setName(parameterAnnotation.name());
|
||||||
paramResponse.setDescription(parameterAnnotation.description());
|
paramResponse.setDescription(parameterAnnotation.description());
|
||||||
paramResponse.setType(parameterAnnotation.type().toString());
|
paramResponse.setType(parameterAnnotation.type().toString().toLowerCase());
|
||||||
paramResponse.setLength(parameterAnnotation.length());
|
paramResponse.setLength(parameterAnnotation.length());
|
||||||
paramResponse.setRequired(parameterAnnotation.required());
|
paramResponse.setRequired(parameterAnnotation.required());
|
||||||
paramResponse.setSince(parameterAnnotation.since());
|
if (!parameterAnnotation.since().isEmpty())
|
||||||
|
paramResponse.setSince(parameterAnnotation.since());
|
||||||
|
paramResponse.setRelated(parameterAnnotation.entityType()[0].getName());
|
||||||
response.addParam(paramResponse);
|
response.addParam(paramResponse);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
response.setObjectName("apis");
|
response.setObjectName("api");
|
||||||
|
_apiNameDiscoveryResponseMap.put(apiName, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (String apiName: _apiNameDiscoveryResponseMap.keySet()) {
|
||||||
|
ApiDiscoveryResponse response = _apiNameDiscoveryResponseMap.get(apiName);
|
||||||
|
Set<ApiParameterResponse> processedParams = new HashSet<ApiParameterResponse>();
|
||||||
|
for (ApiParameterResponse param: response.getParams()) {
|
||||||
|
if (responseApiNameListMap.containsKey(param.getRelated())) {
|
||||||
|
List<String> relatedApis = responseApiNameListMap.get(param.getRelated());
|
||||||
|
param.setRelated(StringUtils.join(relatedApis, ","));
|
||||||
|
} else {
|
||||||
|
param.setRelated(null);
|
||||||
|
}
|
||||||
|
processedParams.add(param);
|
||||||
|
}
|
||||||
|
response.setParams(processedParams);
|
||||||
|
|
||||||
|
if (responseApiNameListMap.containsKey(response.getRelated())) {
|
||||||
|
List<String> relatedApis = responseApiNameListMap.get(response.getRelated());
|
||||||
|
relatedApis.remove(apiName);
|
||||||
|
response.setRelated(StringUtils.join(relatedApis, ","));
|
||||||
|
} else {
|
||||||
|
response.setRelated(null);
|
||||||
|
}
|
||||||
_apiNameDiscoveryResponseMap.put(apiName, response);
|
_apiNameDiscoveryResponseMap.put(apiName, response);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ListResponse<? extends BaseResponse> listApis(RoleType roleType) {
|
public ListResponse<? extends BaseResponse> listApis(RoleType roleType, String name) {
|
||||||
// Creates roles based response list cache the first time listApis is called
|
// Creates roles based response list cache the first time listApis is called
|
||||||
// Due to how adapters work, this cannot be done when mgmt loads
|
// Due to how adapters work, this cannot be done when mgmt loads
|
||||||
if (_apiNameRoleTypeListMap == null) {
|
if (_apiNameRoleTypeListMap == null) {
|
||||||
|
long startTime = System.nanoTime();
|
||||||
_apiNameRoleTypeListMap = getApiNameRoleTypeListMap();
|
_apiNameRoleTypeListMap = getApiNameRoleTypeListMap();
|
||||||
for (Map.Entry<String, List<RoleType>> entry: _apiNameRoleTypeListMap.entrySet()) {
|
for (Map.Entry<String, List<RoleType>> entry: _apiNameRoleTypeListMap.entrySet()) {
|
||||||
String apiName = entry.getKey();
|
String apiName = entry.getKey();
|
||||||
@ -147,9 +205,21 @@ public class ApiDiscoveryServiceImpl implements ApiDiscoveryService {
|
|||||||
_apiNameDiscoveryResponseMap.get(apiName));
|
_apiNameDiscoveryResponseMap.get(apiName));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
long endTime = System.nanoTime();
|
||||||
|
s_logger.info("Api Discovery Service: List apis cached in " + (endTime - startTime) / 1000000.0 + " ms");
|
||||||
}
|
}
|
||||||
ListResponse<ApiDiscoveryResponse> response = new ListResponse<ApiDiscoveryResponse>();
|
ListResponse<ApiDiscoveryResponse> response = new ListResponse<ApiDiscoveryResponse>();
|
||||||
response.setResponses(_roleTypeDiscoveryResponseListMap.get(roleType));
|
if (name != null) {
|
||||||
|
if (!_apiNameDiscoveryResponseMap.containsKey(name))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
List<ApiDiscoveryResponse> singleResponse = new ArrayList<ApiDiscoveryResponse>();
|
||||||
|
singleResponse.add(_apiNameDiscoveryResponseMap.get(name));
|
||||||
|
response.setResponses(singleResponse);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
response.setResponses(_roleTypeDiscoveryResponseListMap.get(roleType));
|
||||||
|
}
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user