Return-Path: X-Original-To: apmail-cloudstack-commits-archive@www.apache.org Delivered-To: apmail-cloudstack-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 1248F1080E for ; Tue, 4 Feb 2014 12:38:56 +0000 (UTC) Received: (qmail 25674 invoked by uid 500); 4 Feb 2014 12:38:50 -0000 Delivered-To: apmail-cloudstack-commits-archive@cloudstack.apache.org Received: (qmail 25578 invoked by uid 500); 4 Feb 2014 12:38:49 -0000 Mailing-List: contact commits-help@cloudstack.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@cloudstack.apache.org Delivered-To: mailing list commits@cloudstack.apache.org Received: (qmail 24758 invoked by uid 99); 4 Feb 2014 12:38:32 -0000 Received: from tyr.zones.apache.org (HELO tyr.zones.apache.org) (140.211.11.114) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 04 Feb 2014 12:38:32 +0000 Received: by tyr.zones.apache.org (Postfix, from userid 65534) id A05CA314AA5; Tue, 4 Feb 2014 12:38:32 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: dahn@apache.org To: commits@cloudstack.apache.org Date: Tue, 04 Feb 2014 12:38:36 -0000 Message-Id: In-Reply-To: <80ed1c04e97b4cd28763b64cb1630f86@git.apache.org> References: <80ed1c04e97b4cd28763b64cb1630f86@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: [5/6] CLOUDSTACK-6003 fixing plus refactoring dispatcher http://git-wip-us.apache.org/repos/asf/cloudstack/blob/447430c3/server/src/com/cloud/api/ApiServer.java ---------------------------------------------------------------------- diff --git a/server/src/com/cloud/api/ApiServer.java b/server/src/com/cloud/api/ApiServer.java index d715db6..290e9de 100755 --- a/server/src/com/cloud/api/ApiServer.java +++ b/server/src/com/cloud/api/ApiServer.java @@ -43,8 +43,6 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; -import java.util.regex.Matcher; -import java.util.regex.Pattern; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; @@ -86,6 +84,7 @@ import org.springframework.stereotype.Component; import org.apache.cloudstack.acl.APIChecker; import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiErrorCode; import org.apache.cloudstack.api.BaseAsyncCmd; import org.apache.cloudstack.api.BaseAsyncCreateCmd; @@ -122,6 +121,7 @@ import org.apache.cloudstack.framework.jobs.AsyncJobManager; import org.apache.cloudstack.framework.jobs.impl.AsyncJobVO; import org.apache.cloudstack.managed.context.ManagedContextRunnable; +import com.cloud.api.dispatch.DispatchChainFactory; import com.cloud.api.response.ApiResponseSerializer; import com.cloud.configuration.Config; import com.cloud.domain.Domain; @@ -159,12 +159,14 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer private static final Logger s_logger = Logger.getLogger(ApiServer.class.getName()); private static final Logger s_accessLogger = Logger.getLogger("apiserver." + ApiServer.class.getName()); - private static boolean encodeApiResponse = false; - private static String jsonContentType = "text/javascript"; - private static String controlCharacters = "[\000-\011\013-\014\016-\037\177]"; // Non-printable ASCII characters - numbers 0 to 31 and 127 decimal - @Inject ApiDispatcher _dispatcher; + public static boolean encodeApiResponse = false; + public static String jsonContentType = "text/javascript"; @Inject + protected ApiDispatcher _dispatcher; + @Inject() + protected DispatchChainFactory dispatchChainFactory = null; + @Inject private AccountManager _accountMgr; @Inject private DomainManager _domainMgr; @@ -191,27 +193,27 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer } @Override - public boolean configure(String name, Map params) throws ConfigurationException { + public boolean configure(final String name, final Map params) throws ConfigurationException { return true; } @Override public boolean start() { Integer apiPort = null; // api port, null by default - SearchCriteria sc = _configDao.createSearchCriteria(); + final SearchCriteria sc = _configDao.createSearchCriteria(); sc.addAnd("name", SearchCriteria.Op.EQ, Config.IntegrationAPIPort.key()); - List values = _configDao.search(sc, null); + final List values = _configDao.search(sc, null); if ((values != null) && (values.size() > 0)) { - ConfigurationVO apiPortConfig = values.get(0); + final ConfigurationVO apiPortConfig = values.get(0); if (apiPortConfig.getValue() != null) { apiPort = Integer.parseInt(apiPortConfig.getValue()); } } - Map configs = _configDao.getConfiguration(); - String strSnapshotLimit = configs.get(Config.ConcurrentSnapshotsThresholdPerHost.key()); + final Map configs = _configDao.getConfiguration(); + final String strSnapshotLimit = configs.get(Config.ConcurrentSnapshotsThresholdPerHost.key()); if (strSnapshotLimit != null) { - Long snapshotLimit = NumbersUtil.parseLong(strSnapshotLimit, 1L); + final Long snapshotLimit = NumbersUtil.parseLong(strSnapshotLimit, 1L); if (snapshotLimit.longValue() <= 0) { s_logger.debug("Global config parameter " + Config.ConcurrentSnapshotsThresholdPerHost.toString() + " is less or equal 0; defaulting to unlimited"); } else { @@ -219,20 +221,20 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer } } - Set> cmdClasses = new HashSet>(); - for (PluggableService pluggableService : _pluggableServices) { + final Set> cmdClasses = new HashSet>(); + for (final PluggableService pluggableService : _pluggableServices) { cmdClasses.addAll(pluggableService.getCommands()); if (s_logger.isDebugEnabled()) { s_logger.debug("Discovered plugin " + pluggableService.getClass().getSimpleName()); } } - for (Class cmdClass : cmdClasses) { - APICommand at = cmdClass.getAnnotation(APICommand.class); + for (final Class cmdClass : cmdClasses) { + final APICommand at = cmdClass.getAnnotation(APICommand.class); if (at == null) { throw new CloudRuntimeException(String.format("%s is claimed as a API command, but it doesn't have @APICommand annotation", cmdClass.getName())); } - String apiName = at.name(); + final String apiName = at.name(); if (s_apiNameCmdClassMap.containsKey(apiName)) { s_logger.error("API Cmd class " + cmdClass.getName() + " has non-unique apiname" + apiName); continue; @@ -241,13 +243,13 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer } setEncodeApiResponse(Boolean.valueOf(_configDao.getValue(Config.EncodeApiResponse.key()))); - String jsonType = _configDao.getValue(Config.JavaScriptDefaultContentType.key()); + final String jsonType = _configDao.getValue(Config.JavaScriptDefaultContentType.key()); if (jsonType != null) { jsonContentType = jsonType; } if (apiPort != null) { - ListenerThread listenerThread = new ListenerThread(this, apiPort); + final ListenerThread listenerThread = new ListenerThread(this, apiPort); listenerThread.start(); } @@ -258,13 +260,13 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer // If integration api port is not configured, actual OTW requests will be received by ApiServlet @SuppressWarnings({"unchecked", "rawtypes"}) @Override - public void handle(HttpRequest request, HttpResponse response, HttpContext context) throws HttpException, IOException { + public void handle(final HttpRequest request, final HttpResponse response, final HttpContext context) throws HttpException, IOException { // Create StringBuffer to log information in access log - StringBuffer sb = new StringBuffer(); - HttpServerConnection connObj = (HttpServerConnection)context.getAttribute("http.connection"); + final StringBuffer sb = new StringBuffer(); + final HttpServerConnection connObj = (HttpServerConnection)context.getAttribute("http.connection"); if (connObj instanceof SocketHttpServerConnection) { - InetAddress remoteAddr = ((SocketHttpServerConnection)connObj).getRemoteAddress(); + final InetAddress remoteAddr = ((SocketHttpServerConnection)connObj).getRemoteAddress(); sb.append(remoteAddr.toString() + " -- "); } sb.append(StringUtils.cleanString(request.getRequestLine().toString())); @@ -273,7 +275,7 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer List paramList = null; try { paramList = URLEncodedUtils.parse(new URI(request.getRequestLine().getUri()), "UTF-8"); - } catch (URISyntaxException e) { + } catch (final URISyntaxException e) { s_logger.error("Error parsing url request", e); } @@ -282,9 +284,9 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer // APITODO: Use Guava's (import com.google.common.collect.Multimap;) // (Immutable)Multimap paramMultiMap = HashMultimap.create(); // Map> parameterMap = paramMultiMap.asMap(); - Map parameterMap = new HashMap(); + final Map parameterMap = new HashMap(); String responseType = BaseCmd.RESPONSE_TYPE_XML; - for (NameValuePair param : paramList) { + for (final NameValuePair param : paramList) { if (param.getName().equalsIgnoreCase("response")) { responseType = param.getValue(); continue; @@ -304,15 +306,15 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer // always trust commands from API port, user context will always be UID_SYSTEM/ACCOUNT_ID_SYSTEM CallContext.register(_accountMgr.getSystemUser(), _accountMgr.getSystemAccount()); sb.insert(0, "(userId=" + User.UID_SYSTEM + " accountId=" + Account.ACCOUNT_ID_SYSTEM + " sessionId=" + null + ") "); - String responseText = handleRequest(parameterMap, responseType, sb); + final String responseText = handleRequest(parameterMap, responseType, sb); sb.append(" 200 " + ((responseText == null) ? 0 : responseText.length())); writeResponse(response, responseText, HttpStatus.SC_OK, responseType, null); - } catch (ServerApiException se) { - String responseText = getSerializedApiError(se, parameterMap, responseType); + } catch (final ServerApiException se) { + final String responseText = getSerializedApiError(se, parameterMap, responseType); writeResponse(response, responseText, se.getErrorCode().getHttpCode(), responseType, se.getDescription()); sb.append(" " + se.getErrorCode() + " " + se.getDescription()); - } catch (RuntimeException e) { + } catch (final RuntimeException e) { // log runtime exception like NullPointerException to help identify the source easier s_logger.error("Unhandled exception, ", e); throw e; @@ -325,77 +327,70 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer @Override @SuppressWarnings("rawtypes") - public String handleRequest(Map params, String responseType, StringBuffer auditTrailSb) throws ServerApiException { + public String handleRequest(final Map rawParams, final String responseType, final StringBuffer auditTrailSb) throws ServerApiException { + final Map params = ParameterHandler.unpackParams(rawParams); + String response = null; - String[] command = null; + String command = null; try { - command = (String[])params.get("command"); + command = (String) params.get(ApiConstants.COMMAND); if (command == null) { s_logger.error("invalid request, no command sent"); if (s_logger.isTraceEnabled()) { s_logger.trace("dumping request parameters"); - for (Object key : params.keySet()) { - String keyStr = (String)key; - String[] value = (String[])params.get(key); - s_logger.trace(" key: " + keyStr + ", value: " + ((value == null) ? "'null'" : value[0])); + for (final Object key : params.keySet()) { + final String keyStr = (String)key; + final Object value = params.get(key); + s_logger.trace(" key: " + keyStr + ", value: " + ((value == null) ? "'null'" : value)); } } throw new ServerApiException(ApiErrorCode.UNSUPPORTED_ACTION_ERROR, "Invalid request, no command sent"); } else { - Map paramMap = new HashMap(); - Set keys = params.keySet(); - Iterator keysIter = keys.iterator(); + final Map paramMap = new HashMap(); + final Set keys = rawParams.keySet(); + final Iterator keysIter = keys.iterator(); while (keysIter.hasNext()) { - String key = (String)keysIter.next(); + final String key = (String)keysIter.next(); if ("command".equalsIgnoreCase(key)) { continue; } - String[] value = (String[])params.get(key); - // fail if parameter value contains ASCII control (non-printable) characters - if (value[0] != null) { - Pattern pattern = Pattern.compile(controlCharacters); - Matcher matcher = pattern.matcher(value[0]); - if (matcher.find()) { - throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Received value " + value[0] + " for parameter " + key + - " is invalid, contains illegal ASCII non-printable characters"); - } - } + final String[] value = (String[])rawParams.get(key); paramMap.put(key, value[0]); } - Class cmdClass = getCmdClass(command[0]); + final Class cmdClass = getCmdClass(command); if (cmdClass != null) { BaseCmd cmdObj = (BaseCmd)cmdClass.newInstance(); cmdObj = ComponentContext.inject(cmdObj); cmdObj.configure(); cmdObj.setFullUrlParams(paramMap); cmdObj.setResponseType(responseType); - cmdObj.setHttpMethod(paramMap.get("httpmethod").toString()); + cmdObj.setHttpMethod(params.get(ApiConstants.HTTPMETHOD).toString()); // This is where the command is either serialized, or directly dispatched - response = queueCommand(cmdObj, paramMap); - buildAuditTrail(auditTrailSb, command[0], response); + response = queueCommand(cmdObj, params); + buildAuditTrail(auditTrailSb, command, response); } else { - if (!command[0].equalsIgnoreCase("login") && !command[0].equalsIgnoreCase("logout")) { - String errorString = "Unknown API command: " + command[0]; + if (!command.equalsIgnoreCase("login") && !command.equalsIgnoreCase("logout")) { + final String errorString = "Unknown API command: " + command; s_logger.warn(errorString); auditTrailSb.append(" " + errorString); throw new ServerApiException(ApiErrorCode.UNSUPPORTED_ACTION_ERROR, errorString); } } } - } catch (InvalidParameterValueException ex) { + } catch (final InvalidParameterValueException ex) { s_logger.info(ex.getMessage()); throw new ServerApiException(ApiErrorCode.PARAM_ERROR, ex.getMessage(), ex); - } catch (IllegalArgumentException ex) { + } catch (final IllegalArgumentException ex) { s_logger.info(ex.getMessage()); throw new ServerApiException(ApiErrorCode.PARAM_ERROR, ex.getMessage(), ex); - } catch (PermissionDeniedException ex) { - ArrayList idList = ex.getIdProxyList(); + } catch (final PermissionDeniedException ex) { + final ArrayList idList = ex.getIdProxyList(); if (idList != null) { - StringBuffer buf = new StringBuffer(); - for (ExceptionProxyObject obj : idList) { + final StringBuffer buf = new StringBuffer(); + for (final ExceptionProxyObject obj : idList) { buf.append(obj.getDescription()); buf.append(":"); buf.append(obj.getUuid()); @@ -406,10 +401,10 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer s_logger.info("PermissionDenied: " + ex.getMessage()); } throw new ServerApiException(ApiErrorCode.ACCOUNT_ERROR, ex.getMessage(), ex); - } catch (AccountLimitException ex) { + } catch (final AccountLimitException ex) { s_logger.info(ex.getMessage()); throw new ServerApiException(ApiErrorCode.ACCOUNT_RESOURCE_LIMIT_ERROR, ex.getMessage(), ex); - } catch (InsufficientCapacityException ex) { + } catch (final InsufficientCapacityException ex) { s_logger.info(ex.getMessage()); String errorMsg = ex.getMessage(); if (CallContext.current().getCallingAccount().getType() != Account.ACCOUNT_TYPE_ADMIN) { @@ -417,10 +412,10 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer errorMsg = BaseCmd.USER_ERROR_MESSAGE; } throw new ServerApiException(ApiErrorCode.INSUFFICIENT_CAPACITY_ERROR, errorMsg, ex); - } catch (ResourceAllocationException ex) { + } catch (final ResourceAllocationException ex) { s_logger.info(ex.getMessage()); throw new ServerApiException(ApiErrorCode.RESOURCE_ALLOCATION_ERROR, ex.getMessage(), ex); - } catch (ResourceUnavailableException ex) { + } catch (final ResourceUnavailableException ex) { s_logger.info(ex.getMessage()); String errorMsg = ex.getMessage(); if (CallContext.current().getCallingAccount().getType() != Account.ACCOUNT_TYPE_ADMIN) { @@ -428,11 +423,11 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer errorMsg = BaseCmd.USER_ERROR_MESSAGE; } throw new ServerApiException(ApiErrorCode.RESOURCE_UNAVAILABLE_ERROR, errorMsg, ex); - } catch (ServerApiException ex) { + } catch (final ServerApiException ex) { s_logger.info(ex.getDescription()); throw ex; - } catch (Exception ex) { - s_logger.error("unhandled exception executing api command: " + ((command == null) ? "null" : command[0]), ex); + } catch (final Exception ex) { + s_logger.error("unhandled exception executing api command: " + ((command == null) ? "null" : command), ex); String errorMsg = ex.getMessage(); if (CallContext.current().getCallingAccount().getType() != Account.ACCOUNT_TYPE_ADMIN) { // hide internal details to non-admin user for security reason @@ -444,28 +439,28 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer return response; } - private String getBaseAsyncResponse(long jobId, BaseAsyncCmd cmd) { - AsyncJobResponse response = new AsyncJobResponse(); + private String getBaseAsyncResponse(final long jobId, final BaseAsyncCmd cmd) { + final AsyncJobResponse response = new AsyncJobResponse(); - AsyncJob job = _entityMgr.findById(AsyncJob.class, jobId); + final AsyncJob job = _entityMgr.findById(AsyncJob.class, jobId); response.setJobId(job.getUuid()); response.setResponseName(cmd.getCommandName()); return ApiResponseSerializer.toSerializedString(response, cmd.getResponseType()); } - private String getBaseAsyncCreateResponse(long jobId, BaseAsyncCreateCmd cmd, String objectUuid) { - CreateCmdResponse response = new CreateCmdResponse(); - AsyncJob job = _entityMgr.findById(AsyncJob.class, jobId); + private String getBaseAsyncCreateResponse(final long jobId, final BaseAsyncCreateCmd cmd, final String objectUuid) { + final CreateCmdResponse response = new CreateCmdResponse(); + final AsyncJob job = _entityMgr.findById(AsyncJob.class, jobId); response.setJobId(job.getUuid()); response.setId(objectUuid); response.setResponseName(cmd.getCommandName()); return ApiResponseSerializer.toSerializedString(response, cmd.getResponseType()); } - private String queueCommand(BaseCmd cmdObj, Map params) throws Exception { - CallContext ctx = CallContext.current(); - Long callerUserId = ctx.getCallingUserId(); - Account caller = ctx.getCallingAccount(); + private String queueCommand(final BaseCmd cmdObj, final Map params) throws Exception { + final CallContext ctx = CallContext.current(); + final Long callerUserId = ctx.getCallingUserId(); + final Account caller = ctx.getCallingAccount(); // Queue command based on Cmd super class: // BaseCmd: cmd is dispatched to ApiDispatcher, executed, serialized and returned. @@ -475,16 +470,16 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer Long objectId = null; String objectUuid = null; if (cmdObj instanceof BaseAsyncCreateCmd) { - BaseAsyncCreateCmd createCmd = (BaseAsyncCreateCmd)cmdObj; + final BaseAsyncCreateCmd createCmd = (BaseAsyncCreateCmd)cmdObj; _dispatcher.dispatchCreateCmd(createCmd, params); objectId = createCmd.getEntityId(); objectUuid = createCmd.getEntityUuid(); params.put("id", objectId.toString()); } else { - ApiDispatcher.processParameters(cmdObj, params); + dispatchChainFactory.getStandardDispatchChain().dispatch(cmdObj, params); } - BaseAsyncCmd asyncCmd = (BaseAsyncCmd)cmdObj; + final BaseAsyncCmd asyncCmd = (BaseAsyncCmd)cmdObj; if (callerUserId != null) { params.put("ctxUserId", callerUserId.toString()); @@ -497,7 +492,7 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer asyncCmd.setStartEventId(startEventId); // save the scheduled event - Long eventId = + final Long eventId = ActionEventUtils.onScheduledActionEvent((callerUserId == null) ? User.UID_SYSTEM : callerUserId, asyncCmd.getEntityOwnerId(), asyncCmd.getEventType(), asyncCmd.getEventDescription(), startEventId); if (startEventId == 0) { @@ -508,22 +503,22 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer params.put("ctxStartEventId", String.valueOf(startEventId)); params.put("cmdEventType", asyncCmd.getEventType().toString()); - Long instanceId = (objectId == null) ? asyncCmd.getInstanceId() : objectId; - AsyncJobVO job = + final Long instanceId = (objectId == null) ? asyncCmd.getInstanceId() : objectId; + final AsyncJobVO job = new AsyncJobVO(ctx.getContextId(), callerUserId, caller.getId(), cmdObj.getClass().getName(), ApiGsonHelper.getBuilder().create().toJson(params), instanceId, asyncCmd.getInstanceType() != null ? asyncCmd.getInstanceType().toString() : null); job.setDispatcher(_asyncDispatcher.getName()); - long jobId = _asyncMgr.submitAsyncJob(job); + final long jobId = _asyncMgr.submitAsyncJob(job); if (jobId == 0L) { - String errorMsg = "Unable to schedule async job for command " + job.getCmd(); + final String errorMsg = "Unable to schedule async job for command " + job.getCmd(); s_logger.warn(errorMsg); throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, errorMsg); } if (objectId != null) { - String objUuid = (objectUuid == null) ? objectId.toString() : objectUuid; + final String objUuid = (objectUuid == null) ? objectId.toString() : objectUuid; return getBaseAsyncCreateResponse(jobId, (BaseAsyncCreateCmd)asyncCmd, objUuid); } else { SerializationContext.current().setUuidTranslation(true); @@ -550,8 +545,8 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer } @SuppressWarnings("unchecked") - private void buildAsyncListResponse(BaseListCmd command, Account account) { - List responses = ((ListResponse)command.getResponseObject()).getResponses(); + private void buildAsyncListResponse(final BaseListCmd command, final Account account) { + final List responses = ((ListResponse)command.getResponseObject()).getResponses(); if (responses != null && responses.size() > 0) { List jobs = null; @@ -566,18 +561,18 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer return; } - Map objectJobMap = new HashMap(); - for (AsyncJob job : jobs) { + final Map objectJobMap = new HashMap(); + for (final AsyncJob job : jobs) { if (job.getInstanceId() == null) { continue; } - String instanceUuid = ApiDBUtils.findJobInstanceUuid(job); + final String instanceUuid = ApiDBUtils.findJobInstanceUuid(job); objectJobMap.put(instanceUuid, job); } - for (ResponseObject response : responses) { + for (final ResponseObject response : responses) { if (response.getObjectId() != null && objectJobMap.containsKey(response.getObjectId())) { - AsyncJob job = objectJobMap.get(response.getObjectId()); + final AsyncJob job = objectJobMap.get(response.getObjectId()); response.setJobId(job.getUuid()); response.setJobStatus(job.getStatus().ordinal()); } @@ -585,7 +580,7 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer } } - private void buildAuditTrail(StringBuffer auditTrailSb, String command, String result) { + private void buildAuditTrail(final StringBuffer auditTrailSb, final String command, final String result) { if (result == null) { return; } @@ -598,31 +593,31 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer } @Override - public boolean verifyRequest(Map requestParameters, Long userId) throws ServerApiException { + public boolean verifyRequest(final Map requestParameters, final Long userId) throws ServerApiException { try { String apiKey = null; String secretKey = null; String signature = null; String unsignedRequest = null; - String[] command = (String[])requestParameters.get("command"); + final String[] command = (String[])requestParameters.get(ApiConstants.COMMAND); if (command == null) { s_logger.info("missing command, ignoring request..."); return false; } - String commandName = command[0]; + final String commandName = command[0]; // if userId not null, that mean that user is logged in if (userId != null) { - User user = ApiDBUtils.findUserById(userId); + final User user = ApiDBUtils.findUserById(userId); try { checkCommandAvailable(user, commandName); - } catch (RequestLimitException ex) { + } catch (final RequestLimitException ex) { s_logger.debug(ex.getMessage()); throw new ServerApiException(ApiErrorCode.API_LIMIT_EXCEED, ex.getMessage()); - } catch (PermissionDeniedException ex) { + } catch (final PermissionDeniedException ex) { s_logger.debug("The given command:" + commandName + " does not exist or it is not available for user with id:" + userId); throw new ServerApiException(ApiErrorCode.UNSUPPORTED_ACTION_ERROR, "The given command does not exist or it is not available for user"); } @@ -637,9 +632,9 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer // - build a request string with sorted params, make sure it's all lowercase // - sign the request, verify the signature is the same - List parameterNames = new ArrayList(); + final List parameterNames = new ArrayList(); - for (Object paramNameObj : requestParameters.keySet()) { + for (final Object paramNameObj : requestParameters.keySet()) { parameterNames.add((String)paramNameObj); // put the name in a list that we'll sort later } @@ -648,9 +643,9 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer String signatureVersion = null; String expires = null; - for (String paramName : parameterNames) { + for (final String paramName : parameterNames) { // parameters come as name/value pairs in the form String/String[] - String paramValue = ((String[])requestParameters.get(paramName))[0]; + final String paramValue = ((String[])requestParameters.get(paramName))[0]; if ("signature".equalsIgnoreCase(paramName)) { signature = paramValue; @@ -688,30 +683,30 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer synchronized (DateFormatToUse) { try { expiresTS = DateFormatToUse.parse(expires); - } catch (ParseException pe) { + } catch (final ParseException pe) { s_logger.debug("Incorrect date format for Expires parameter", pe); return false; } } - Date now = new Date(System.currentTimeMillis()); + final Date now = new Date(System.currentTimeMillis()); if (expiresTS.before(now)) { s_logger.debug("Request expired -- ignoring ...sig: " + signature + ", apiKey: " + apiKey); return false; } } - TransactionLegacy txn = TransactionLegacy.open(TransactionLegacy.CLOUD_DB); + final TransactionLegacy txn = TransactionLegacy.open(TransactionLegacy.CLOUD_DB); txn.close(); User user = null; // verify there is a user with this api key - Pair userAcctPair = _accountMgr.findUserByApiKey(apiKey); + final Pair userAcctPair = _accountMgr.findUserByApiKey(apiKey); if (userAcctPair == null) { s_logger.debug("apiKey does not map to a valid user -- ignoring request, apiKey: " + apiKey); return false; } user = userAcctPair.first(); - Account account = userAcctPair.second(); + final Account account = userAcctPair.second(); if (user.getState() != Account.State.enabled || !account.getState().equals(Account.State.enabled)) { s_logger.info("disabled or locked user accessing the api, userid = " + user.getId() + "; name = " + user.getUsername() + "; state: " + user.getState() + @@ -721,10 +716,10 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer try { checkCommandAvailable(user, commandName); - } catch (RequestLimitException ex) { + } catch (final RequestLimitException ex) { s_logger.debug(ex.getMessage()); throw new ServerApiException(ApiErrorCode.API_LIMIT_EXCEED, ex.getMessage()); - } catch (PermissionDeniedException ex) { + } catch (final PermissionDeniedException ex) { s_logger.debug("The given command:" + commandName + " does not exist or it is not available for user"); throw new ServerApiException(ApiErrorCode.UNSUPPORTED_ACTION_ERROR, "The given command:" + commandName + " does not exist or it is not available for user with id:" + userId); @@ -739,30 +734,30 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer unsignedRequest = unsignedRequest.toLowerCase(); - Mac mac = Mac.getInstance("HmacSHA1"); - SecretKeySpec keySpec = new SecretKeySpec(secretKey.getBytes(), "HmacSHA1"); + final Mac mac = Mac.getInstance("HmacSHA1"); + final SecretKeySpec keySpec = new SecretKeySpec(secretKey.getBytes(), "HmacSHA1"); mac.init(keySpec); mac.update(unsignedRequest.getBytes()); - byte[] encryptedBytes = mac.doFinal(); - String computedSignature = Base64.encodeBase64String(encryptedBytes); - boolean equalSig = signature.equals(computedSignature); + final byte[] encryptedBytes = mac.doFinal(); + final String computedSignature = Base64.encodeBase64String(encryptedBytes); + final boolean equalSig = signature.equals(computedSignature); if (!equalSig) { s_logger.info("User signature: " + signature + " is not equaled to computed signature: " + computedSignature); } else { CallContext.register(user, account); } return equalSig; - } catch (ServerApiException ex) { + } catch (final ServerApiException ex) { throw ex; - } catch (Exception ex) { + } catch (final Exception ex) { s_logger.error("unable to verify request signature"); } return false; } @Override - public Long fetchDomainId(String domainUUID) { - Domain domain = _domainMgr.getDomain(domainUUID); + public Long fetchDomainId(final String domainUUID) { + final Domain domain = _domainMgr.getDomain(domainUUID); if (domain != null) return domain.getId(); else @@ -770,15 +765,15 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer } @Override - public void loginUser(HttpSession session, String username, String password, Long domainId, String domainPath, String loginIpAddress, - Map requestParameters) throws CloudAuthenticationException { + public void loginUser(final HttpSession session, final String username, final String password, Long domainId, final String domainPath, final String loginIpAddress, + final Map requestParameters) throws CloudAuthenticationException { // We will always use domainId first. If that does not exist, we will use domain name. If THAT doesn't exist // we will default to ROOT if (domainId == null) { if (domainPath == null || domainPath.trim().length() == 0) { domainId = Domain.ROOT_DOMAIN; } else { - Domain domainObj = _domainMgr.findDomainByPath(domainPath); + final Domain domainObj = _domainMgr.findDomainByPath(domainPath); if (domainObj != null) { domainId = domainObj.getId(); } else { // if an unknown path is passed in, fail the login call @@ -787,26 +782,26 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer } } - UserAccount userAcct = _accountMgr.authenticateUser(username, password, domainId, loginIpAddress, requestParameters); + final UserAccount userAcct = _accountMgr.authenticateUser(username, password, domainId, loginIpAddress, requestParameters); if (userAcct != null) { - String timezone = userAcct.getTimezone(); + final String timezone = userAcct.getTimezone(); float offsetInHrs = 0f; if (timezone != null) { - TimeZone t = TimeZone.getTimeZone(timezone); + final TimeZone t = TimeZone.getTimeZone(timezone); s_logger.info("Current user logged in under " + timezone + " timezone"); - java.util.Date date = new java.util.Date(); - long longDate = date.getTime(); - float offsetInMs = (t.getOffset(longDate)); + final java.util.Date date = new java.util.Date(); + final long longDate = date.getTime(); + final float offsetInMs = (t.getOffset(longDate)); offsetInHrs = offsetInMs / (1000 * 60 * 60); s_logger.info("Timezone offset from UTC is: " + offsetInHrs); } - Account account = _accountMgr.getAccount(userAcct.getAccountId()); + final Account account = _accountMgr.getAccount(userAcct.getAccountId()); // set the userId and account object for everyone session.setAttribute("userid", userAcct.getId()); - UserVO user = (UserVO)_accountMgr.getActiveUser(userAcct.getId()); + final UserVO user = (UserVO)_accountMgr.getActiveUser(userAcct.getId()); if (user.getUuid() != null) { session.setAttribute("user_UUID", user.getUuid()); } @@ -818,7 +813,7 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer session.setAttribute("account", account.getAccountName()); session.setAttribute("domainid", account.getDomainId()); - DomainVO domain = (DomainVO)_domainMgr.getDomain(account.getDomainId()); + final DomainVO domain = (DomainVO)_domainMgr.getDomain(account.getDomainId()); if (domain.getUuid() != null) { session.setAttribute("domain_UUID", domain.getUuid()); } @@ -834,10 +829,10 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer // (bug 5483) generate a session key that the user must submit on every request to prevent CSRF, add that // to the login response so that session-based authenticators know to send the key back - SecureRandom sesssionKeyRandom = new SecureRandom(); - byte sessionKeyBytes[] = new byte[20]; + final SecureRandom sesssionKeyRandom = new SecureRandom(); + final byte sessionKeyBytes[] = new byte[20]; sesssionKeyRandom.nextBytes(sessionKeyBytes); - String sessionKey = Base64.encodeBase64String(sessionKeyBytes); + final String sessionKey = Base64.encodeBase64String(sessionKeyBytes); session.setAttribute("sessionkey", sessionKey); return; @@ -846,14 +841,14 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer } @Override - public void logoutUser(long userId) { + public void logoutUser(final long userId) { _accountMgr.logoutUser(userId); return; } @Override - public boolean verifyUser(Long userId) { - User user = _accountMgr.getUserIncludingRemoved(userId); + public boolean verifyUser(final Long userId) { + final User user = _accountMgr.getUserIncludingRemoved(userId); Account account = null; if (user != null) { account = _accountMgr.getAccount(user.getAccountId()); @@ -867,27 +862,27 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer return true; } - private void checkCommandAvailable(User user, String commandName) throws PermissionDeniedException { + private void checkCommandAvailable(final User user, final String commandName) throws PermissionDeniedException { if (user == null) { throw new PermissionDeniedException("User is null for role based API access check for command" + commandName); } - for (APIChecker apiChecker : _apiAccessCheckers) { + for (final APIChecker apiChecker : _apiAccessCheckers) { apiChecker.checkAccess(user, commandName); } } - private Class getCmdClass(String cmdName) { + private Class getCmdClass(final String cmdName) { return s_apiNameCmdClassMap.get(cmdName); } // FIXME: rather than isError, we might was to pass in the status code to give more flexibility - private void writeResponse(HttpResponse resp, final String responseText, final int statusCode, String responseType, String reasonPhrase) { + private void writeResponse(final HttpResponse resp, final String responseText, final int statusCode, final String responseType, final String reasonPhrase) { try { resp.setStatusCode(statusCode); resp.setReasonPhrase(reasonPhrase); - BasicHttpEntity body = new BasicHttpEntity(); + final BasicHttpEntity body = new BasicHttpEntity(); if (BaseCmd.RESPONSE_TYPE_JSON.equalsIgnoreCase(responseType)) { // JSON response body.setContentType(jsonContentType); @@ -905,7 +900,7 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer body.setContent(new ByteArrayInputStream(responseText.getBytes("UTF-8"))); } resp.setEntity(body); - } catch (Exception ex) { + } catch (final Exception ex) { s_logger.error("error!", ex); } } @@ -920,10 +915,10 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer private ServerSocket _serverSocket = null; private HttpParams _params = null; - public ListenerThread(ApiServer requestHandler, int port) { + public ListenerThread(final ApiServer requestHandler, final int port) { try { _serverSocket = new ServerSocket(port); - } catch (IOException ioex) { + } catch (final IOException ioex) { s_logger.error("error initializing api server", ioex); return; } @@ -936,14 +931,14 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer .setParameter(CoreProtocolPNames.ORIGIN_SERVER, "HttpComponents/1.1"); // Set up the HTTP protocol processor - BasicHttpProcessor httpproc = new BasicHttpProcessor(); + final BasicHttpProcessor httpproc = new BasicHttpProcessor(); httpproc.addInterceptor(new ResponseDate()); httpproc.addInterceptor(new ResponseServer()); httpproc.addInterceptor(new ResponseContent()); httpproc.addInterceptor(new ResponseConnControl()); // Set up request handlers - HttpRequestHandlerRegistry reqistry = new HttpRequestHandlerRegistry(); + final HttpRequestHandlerRegistry reqistry = new HttpRequestHandlerRegistry(); reqistry.register("*", requestHandler); // Set up the HTTP service @@ -958,15 +953,15 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer while (!Thread.interrupted()) { try { // Set up HTTP connection - Socket socket = _serverSocket.accept(); - DefaultHttpServerConnection conn = new DefaultHttpServerConnection(); + final Socket socket = _serverSocket.accept(); + final DefaultHttpServerConnection conn = new DefaultHttpServerConnection(); conn.bind(socket, _params); // Execute a new worker task to handle the request s_executor.execute(new WorkerTask(_httpService, conn, s_workerCount++)); - } catch (InterruptedIOException ex) { + } catch (final InterruptedIOException ex) { break; - } catch (IOException e) { + } catch (final IOException e) { s_logger.error("I/O error initializing connection thread", e); break; } @@ -985,33 +980,33 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer @Override protected void runInContext() { - HttpContext context = new BasicHttpContext(null); + final HttpContext context = new BasicHttpContext(null); try { while (!Thread.interrupted() && _conn.isOpen()) { _httpService.handleRequest(_conn, context); _conn.close(); } - } catch (ConnectionClosedException ex) { + } catch (final ConnectionClosedException ex) { if (s_logger.isTraceEnabled()) { s_logger.trace("ApiServer: Client closed connection"); } - } catch (IOException ex) { + } catch (final IOException ex) { if (s_logger.isTraceEnabled()) { s_logger.trace("ApiServer: IOException - " + ex); } - } catch (HttpException ex) { + } catch (final HttpException ex) { s_logger.warn("ApiServer: Unrecoverable HTTP protocol violation" + ex); } finally { try { _conn.shutdown(); - } catch (IOException ignore) { + } catch (final IOException ignore) { } } } } @Override - public String getSerializedApiError(int errorCode, String errorText, Map apiCommandParams, String responseType) { + public String getSerializedApiError(final int errorCode, final String errorText, final Map apiCommandParams, final String responseType) { String responseName = null; Class cmdClass = null; String responseText = null; @@ -1020,10 +1015,10 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer if (apiCommandParams == null || apiCommandParams.isEmpty()) { responseName = "errorresponse"; } else { - Object cmdObj = apiCommandParams.get("command"); + final Object cmdObj = apiCommandParams.get(ApiConstants.COMMAND); // cmd name can be null when "command" parameter is missing in the request if (cmdObj != null) { - String cmdName = ((String[])cmdObj)[0]; + final String cmdName = ((String[])cmdObj)[0]; cmdClass = getCmdClass(cmdName); if (cmdClass != null) { responseName = ((BaseCmd)cmdClass.newInstance()).getCommandName(); @@ -1032,21 +1027,21 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer } } } - ExceptionResponse apiResponse = new ExceptionResponse(); + final ExceptionResponse apiResponse = new ExceptionResponse(); apiResponse.setErrorCode(errorCode); apiResponse.setErrorText(errorText); apiResponse.setResponseName(responseName); SerializationContext.current().setUuidTranslation(true); responseText = ApiResponseSerializer.toSerializedString(apiResponse, responseType); - } catch (Exception e) { + } catch (final Exception e) { s_logger.error("Exception responding to http request", e); } return responseText; } @Override - public String getSerializedApiError(ServerApiException ex, Map apiCommandParams, String responseType) { + public String getSerializedApiError(final ServerApiException ex, final Map apiCommandParams, final String responseType) { String responseName = null; Class cmdClass = null; String responseText = null; @@ -1059,11 +1054,11 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer if (ex.getErrorCode() == ApiErrorCode.UNSUPPORTED_ACTION_ERROR || apiCommandParams == null || apiCommandParams.isEmpty()) { responseName = "errorresponse"; } else { - Object cmdObj = apiCommandParams.get("command"); + final Object cmdObj = apiCommandParams.get(ApiConstants.COMMAND); // cmd name can be null when "command" parameter is missing in // the request if (cmdObj != null) { - String cmdName = ((String[])cmdObj)[0]; + final String cmdName = ((String[])cmdObj)[0]; cmdClass = getCmdClass(cmdName); if (cmdClass != null) { responseName = ((BaseCmd)cmdClass.newInstance()).getCommandName(); @@ -1072,11 +1067,11 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer } } } - ExceptionResponse apiResponse = new ExceptionResponse(); + final ExceptionResponse apiResponse = new ExceptionResponse(); apiResponse.setErrorCode(ex.getErrorCode().getHttpCode()); apiResponse.setErrorText(ex.getDescription()); apiResponse.setResponseName(responseName); - ArrayList idList = ex.getIdProxyList(); + final ArrayList idList = ex.getIdProxyList(); if (idList != null) { for (int i = 0; i < idList.size(); i++) { apiResponse.addProxyObject(idList.get(i)); @@ -1089,7 +1084,7 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer SerializationContext.current().setUuidTranslation(true); responseText = ApiResponseSerializer.toSerializedString(apiResponse, responseType); - } catch (Exception e) { + } catch (final Exception e) { s_logger.error("Exception responding to http request", e); } return responseText; @@ -1100,7 +1095,7 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer } @Inject - public void setPluggableServices(List pluggableServices) { + public void setPluggableServices(final List pluggableServices) { _pluggableServices = pluggableServices; } @@ -1109,7 +1104,7 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer } @Inject - public void setApiAccessCheckers(List apiAccessCheckers) { + public void setApiAccessCheckers(final List apiAccessCheckers) { _apiAccessCheckers = apiAccessCheckers; } @@ -1117,7 +1112,7 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer return encodeApiResponse; } - private static void setEncodeApiResponse(boolean encodeApiResponse) { + private static void setEncodeApiResponse(final boolean encodeApiResponse) { ApiServer.encodeApiResponse = encodeApiResponse; } http://git-wip-us.apache.org/repos/asf/cloudstack/blob/447430c3/server/src/com/cloud/api/ApiServlet.java ---------------------------------------------------------------------- diff --git a/server/src/com/cloud/api/ApiServlet.java b/server/src/com/cloud/api/ApiServlet.java index 46f7eba..901a0fd 100755 --- a/server/src/com/cloud/api/ApiServlet.java +++ b/server/src/com/cloud/api/ApiServlet.java @@ -35,6 +35,7 @@ import org.apache.log4j.Logger; import org.springframework.stereotype.Component; import org.springframework.web.context.support.SpringBeanAutowiringSupport; +import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiErrorCode; import org.apache.cloudstack.api.BaseCmd; import org.apache.cloudstack.api.ServerApiException; @@ -67,40 +68,40 @@ public class ApiServlet extends HttpServlet { } @Override - public void init(ServletConfig config) throws ServletException { + public void init(final ServletConfig config) throws ServletException { SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(this, config.getServletContext()); } @Override - protected void doGet(HttpServletRequest req, HttpServletResponse resp) { + protected void doGet(final HttpServletRequest req, final HttpServletResponse resp) { processRequest(req, resp); } @Override - protected void doPost(HttpServletRequest req, HttpServletResponse resp) { + protected void doPost(final HttpServletRequest req, final HttpServletResponse resp) { processRequest(req, resp); } - private void utf8Fixup(HttpServletRequest req, Map params) { + private void utf8Fixup(final HttpServletRequest req, final Map params) { if (req.getQueryString() == null) { return; } - String[] paramsInQueryString = req.getQueryString().split("&"); + final String[] paramsInQueryString = req.getQueryString().split("&"); if (paramsInQueryString != null) { - for (String param : paramsInQueryString) { - String[] paramTokens = param.split("=", 2); + for (final String param : paramsInQueryString) { + final String[] paramTokens = param.split("=", 2); if (paramTokens != null && paramTokens.length == 2) { String name = paramTokens[0]; String value = paramTokens[1]; try { name = URLDecoder.decode(name, "UTF-8"); - } catch (UnsupportedEncodingException e) { + } catch (final UnsupportedEncodingException e) { } try { value = URLDecoder.decode(value, "UTF-8"); - } catch (UnsupportedEncodingException e) { + } catch (final UnsupportedEncodingException e) { } params.put(name, new String[] {value}); } else { @@ -119,13 +120,13 @@ public class ApiServlet extends HttpServlet { }); } - private void processRequestInContext(HttpServletRequest req, HttpServletResponse resp) { - StringBuffer auditTrailSb = new StringBuffer(); + private void processRequestInContext(final HttpServletRequest req, final HttpServletResponse resp) { + final StringBuffer auditTrailSb = new StringBuffer(); auditTrailSb.append(" " + req.getRemoteAddr()); auditTrailSb.append(" -- " + req.getMethod() + " "); // get the response format since we'll need it in a couple of places String responseType = BaseCmd.RESPONSE_TYPE_XML; - Map params = new HashMap(); + final Map params = new HashMap(); params.putAll(req.getParameterMap()); // For HTTP GET requests, it seems that HttpServletRequest.getParameterMap() actually tries @@ -143,19 +144,19 @@ public class ApiServlet extends HttpServlet { try { HttpSession session = req.getSession(false); - Object[] responseTypeParam = params.get("response"); + final Object[] responseTypeParam = params.get(ApiConstants.RESPONSE); if (responseTypeParam != null) { responseType = (String)responseTypeParam[0]; } - Object[] commandObj = params.get("command"); - if (commandObj != null) { - String command = (String)commandObj[0]; + final Object[] commandParam = params.get(ApiConstants.COMMAND); + if (commandParam != null) { + final String command = (String)commandParam[0]; if ("logout".equalsIgnoreCase(command)) { // if this is just a logout, invalidate the session and return if (session != null) { - Long userId = (Long)session.getAttribute("userid"); - Account account = (Account)session.getAttribute("accountobj"); + final Long userId = (Long)session.getAttribute("userid"); + final Account account = (Account)session.getAttribute("accountobj"); Long accountId = null; if (account != null) { accountId = account.getId(); @@ -166,7 +167,7 @@ public class ApiServlet extends HttpServlet { } try { session.invalidate(); - } catch (IllegalStateException ise) { + } catch (final IllegalStateException ise) { } } auditTrailSb.append("command=logout"); @@ -179,18 +180,18 @@ public class ApiServlet extends HttpServlet { if (session != null) { try { session.invalidate(); - } catch (IllegalStateException ise) { + } catch (final IllegalStateException ise) { } } session = req.getSession(true); - String[] username = (String[])params.get("username"); - String[] password = (String[])params.get("password"); - String[] domainIdArr = (String[])params.get("domainid"); + final String[] username = (String[])params.get(ApiConstants.USERNAME); + final String[] password = (String[])params.get(ApiConstants.PASSWORD); + String[] domainIdArr = (String[])params.get(ApiConstants.DOMAIN_ID); if (domainIdArr == null) { - domainIdArr = (String[])params.get("domainId"); + domainIdArr = (String[])params.get(ApiConstants.DOMAIN__ID); } - String[] domainName = (String[])params.get("domain"); + final String[] domainName = (String[])params.get(ApiConstants.DOMAIN); Long domainId = null; if ((domainIdArr != null) && (domainIdArr.length > 0)) { try { @@ -200,10 +201,10 @@ public class ApiServlet extends HttpServlet { domainId = new Long(Long.parseLong(domainIdArr[0])); } auditTrailSb.append(" domainid=" + domainId);// building the params for POST call - } catch (NumberFormatException e) { + } catch (final NumberFormatException e) { s_logger.warn("Invalid domain id entered by user"); auditTrailSb.append(" " + HttpServletResponse.SC_UNAUTHORIZED + " " + "Invalid domain id entered, please enter a valid one"); - String serializedResponse = + final String serializedResponse = _apiServer.getSerializedApiError(HttpServletResponse.SC_UNAUTHORIZED, "Invalid domain id entered, please enter a valid one", params, responseType); writeResponse(resp, serializedResponse, HttpServletResponse.SC_UNAUTHORIZED, responseType); @@ -225,24 +226,24 @@ public class ApiServlet extends HttpServlet { } if (username != null) { - String pwd = ((password == null) ? null : password[0]); + final String pwd = ((password == null) ? null : password[0]); try { _apiServer.loginUser(session, username[0], pwd, domainId, domain, req.getRemoteAddr(), params); auditTrailSb.insert(0, "(userId=" + session.getAttribute("userid") + " accountId=" + ((Account)session.getAttribute("accountobj")).getId() + " sessionId=" + session.getId() + ")"); - String loginResponse = getLoginSuccessResponse(session, responseType); + final String loginResponse = getLoginSuccessResponse(session, responseType); writeResponse(resp, loginResponse, HttpServletResponse.SC_OK, responseType); return; - } catch (CloudAuthenticationException ex) { + } catch (final CloudAuthenticationException ex) { // TODO: fall through to API key, or just fail here w/ auth error? (HTTP 401) try { session.invalidate(); - } catch (IllegalStateException ise) { + } catch (final IllegalStateException ise) { } auditTrailSb.append(" " + ApiErrorCode.ACCOUNT_ERROR + " " + ex.getMessage() != null ? ex.getMessage() : "failed to authenticate user, check if username/password are correct"); - String serializedResponse = + final String serializedResponse = _apiServer.getSerializedApiError(ApiErrorCode.ACCOUNT_ERROR.getHttpCode(), ex.getMessage() != null ? ex.getMessage() : "failed to authenticate user, check if username/password are correct", params, responseType); writeResponse(resp, serializedResponse, ApiErrorCode.ACCOUNT_ERROR.getHttpCode(), responseType); @@ -252,7 +253,7 @@ public class ApiServlet extends HttpServlet { } } auditTrailSb.append(req.getQueryString()); - boolean isNew = ((session == null) ? true : session.isNew()); + final boolean isNew = ((session == null) ? true : session.isNew()); // Initialize an empty context and we will update it after we have verified the request below, // we no longer rely on web-session here, verifyRequest will populate user/account information @@ -261,17 +262,17 @@ public class ApiServlet extends HttpServlet { if (!isNew) { userId = (Long)session.getAttribute("userid"); - String account = (String)session.getAttribute("account"); - Object accountObj = session.getAttribute("accountobj"); - String sessionKey = (String)session.getAttribute("sessionkey"); - String[] sessionKeyParam = (String[])params.get("sessionkey"); + final String account = (String)session.getAttribute("account"); + final Object accountObj = session.getAttribute("accountobj"); + final String sessionKey = (String)session.getAttribute("sessionkey"); + final String[] sessionKeyParam = (String[])params.get(ApiConstants.SESSIONKEY); if ((sessionKeyParam == null) || (sessionKey == null) || !sessionKey.equals(sessionKeyParam[0])) { try { session.invalidate(); - } catch (IllegalStateException ise) { + } catch (final IllegalStateException ise) { } auditTrailSb.append(" " + HttpServletResponse.SC_UNAUTHORIZED + " " + "unable to verify user credentials"); - String serializedResponse = + final String serializedResponse = _apiServer.getSerializedApiError(HttpServletResponse.SC_UNAUTHORIZED, "unable to verify user credentials", params, responseType); writeResponse(resp, serializedResponse, HttpServletResponse.SC_UNAUTHORIZED, responseType); return; @@ -279,26 +280,25 @@ public class ApiServlet extends HttpServlet { // Do a sanity check here to make sure the user hasn't already been deleted if ((userId != null) && (account != null) && (accountObj != null) && _apiServer.verifyUser(userId)) { - String[] command = (String[])params.get("command"); - if (command == null) { + if (commandParam == null || commandParam[0] == null) { s_logger.info("missing command, ignoring request..."); auditTrailSb.append(" " + HttpServletResponse.SC_BAD_REQUEST + " " + "no command specified"); - String serializedResponse = _apiServer.getSerializedApiError(HttpServletResponse.SC_BAD_REQUEST, "no command specified", params, responseType); + final String serializedResponse = _apiServer.getSerializedApiError(HttpServletResponse.SC_BAD_REQUEST, "no command specified", params, responseType); writeResponse(resp, serializedResponse, HttpServletResponse.SC_BAD_REQUEST, responseType); return; } - User user = _entityMgr.findById(User.class, userId); + final User user = _entityMgr.findById(User.class, userId); CallContext.register(user, (Account)accountObj); } else { // Invalidate the session to ensure we won't allow a request across management server // restarts if the userId was serialized to the stored session try { session.invalidate(); - } catch (IllegalStateException ise) { + } catch (final IllegalStateException ise) { } auditTrailSb.append(" " + HttpServletResponse.SC_UNAUTHORIZED + " " + "unable to verify user credentials"); - String serializedResponse = + final String serializedResponse = _apiServer.getSerializedApiError(HttpServletResponse.SC_UNAUTHORIZED, "unable to verify user credentials", params, responseType); writeResponse(resp, serializedResponse, HttpServletResponse.SC_UNAUTHORIZED, responseType); return; @@ -326,29 +326,29 @@ public class ApiServlet extends HttpServlet { // Add the HTTP method (GET/POST/PUT/DELETE) as well into the params map. params.put("httpmethod", new String[] {req.getMethod()}); - String response = _apiServer.handleRequest(params, responseType, auditTrailSb); + final String response = _apiServer.handleRequest(params, responseType, auditTrailSb); writeResponse(resp, response != null ? response : "", HttpServletResponse.SC_OK, responseType); } else { if (session != null) { try { session.invalidate(); - } catch (IllegalStateException ise) { + } catch (final IllegalStateException ise) { } } auditTrailSb.append(" " + HttpServletResponse.SC_UNAUTHORIZED + " " + "unable to verify user credentials and/or request signature"); - String serializedResponse = + final String serializedResponse = _apiServer.getSerializedApiError(HttpServletResponse.SC_UNAUTHORIZED, "unable to verify user credentials and/or request signature", params, responseType); writeResponse(resp, serializedResponse, HttpServletResponse.SC_UNAUTHORIZED, responseType); } - } catch (ServerApiException se) { - String serializedResponseText = _apiServer.getSerializedApiError(se, params, responseType); + } catch (final ServerApiException se) { + final String serializedResponseText = _apiServer.getSerializedApiError(se, params, responseType); resp.setHeader("X-Description", se.getDescription()); writeResponse(resp, serializedResponseText, se.getErrorCode().getHttpCode(), responseType); auditTrailSb.append(" " + se.getErrorCode() + " " + se.getDescription()); - } catch (Exception ex) { + } catch (final Exception ex) { s_logger.error("unknown exception writing api response", ex); auditTrailSb.append(" unknown exception writing api response"); } finally { @@ -372,7 +372,7 @@ public class ApiServlet extends HttpServlet { */ // FIXME: rather than isError, we might was to pass in the status code to give more flexibility - private void writeResponse(HttpServletResponse resp, String response, int responseCode, String responseType) { + private void writeResponse(final HttpServletResponse resp, final String response, final int responseCode, final String responseType) { try { if (BaseCmd.RESPONSE_TYPE_JSON.equalsIgnoreCase(responseType)) { resp.setContentType(ApiServer.getJsonContentType() + "; charset=UTF-8"); @@ -382,11 +382,11 @@ public class ApiServlet extends HttpServlet { resp.setStatus(responseCode); resp.getWriter().print(response); - } catch (IOException ioex) { + } catch (final IOException ioex) { if (s_logger.isTraceEnabled()) { s_logger.trace("exception writing response: " + ioex); } - } catch (Exception ex) { + } catch (final Exception ex) { if (!(ex instanceof IllegalStateException)) { s_logger.error("unknown exception writing api response", ex); } @@ -394,29 +394,29 @@ public class ApiServlet extends HttpServlet { } @SuppressWarnings("rawtypes") - private String getLoginSuccessResponse(HttpSession session, String responseType) { - StringBuffer sb = new StringBuffer(); - int inactiveInterval = session.getMaxInactiveInterval(); + private String getLoginSuccessResponse(final HttpSession session, final String responseType) { + final StringBuffer sb = new StringBuffer(); + final int inactiveInterval = session.getMaxInactiveInterval(); - String user_UUID = (String)session.getAttribute("user_UUID"); + final String user_UUID = (String)session.getAttribute("user_UUID"); session.removeAttribute("user_UUID"); - String domain_UUID = (String)session.getAttribute("domain_UUID"); + final String domain_UUID = (String)session.getAttribute("domain_UUID"); session.removeAttribute("domain_UUID"); if (BaseCmd.RESPONSE_TYPE_JSON.equalsIgnoreCase(responseType)) { sb.append("{ \"loginresponse\" : { "); - Enumeration attrNames = session.getAttributeNames(); + final Enumeration attrNames = session.getAttributeNames(); if (attrNames != null) { sb.append("\"timeout\" : \"" + inactiveInterval + "\""); while (attrNames.hasMoreElements()) { - String attrName = (String)attrNames.nextElement(); + final String attrName = (String)attrNames.nextElement(); if ("userid".equalsIgnoreCase(attrName)) { sb.append(", \"" + attrName + "\" : \"" + user_UUID + "\""); } else if ("domainid".equalsIgnoreCase(attrName)) { sb.append(", \"" + attrName + "\" : \"" + domain_UUID + "\""); } else { - Object attrObj = session.getAttribute(attrName); + final Object attrObj = session.getAttribute(attrName); if ((attrObj instanceof String) || (attrObj instanceof Long)) { sb.append(", \"" + attrName + "\" : \"" + attrObj.toString() + "\""); } @@ -428,16 +428,16 @@ public class ApiServlet extends HttpServlet { sb.append(""); sb.append(""); sb.append("" + inactiveInterval + ""); - Enumeration attrNames = session.getAttributeNames(); + final Enumeration attrNames = session.getAttributeNames(); if (attrNames != null) { while (attrNames.hasMoreElements()) { - String attrName = (String)attrNames.nextElement(); + final String attrName = (String)attrNames.nextElement(); if ("userid".equalsIgnoreCase(attrName)) { sb.append("<" + attrName + ">" + user_UUID + ""); } else if ("domainid".equalsIgnoreCase(attrName)) { sb.append("<" + attrName + ">" + domain_UUID + ""); } else { - Object attrObj = session.getAttribute(attrName); + final Object attrObj = session.getAttribute(attrName); if (attrObj instanceof String || attrObj instanceof Long || attrObj instanceof Short) { sb.append("<" + attrName + ">" + attrObj.toString() + ""); } @@ -450,8 +450,8 @@ public class ApiServlet extends HttpServlet { return sb.toString(); } - private String getLogoutSuccessResponse(String responseType) { - StringBuffer sb = new StringBuffer(); + private String getLogoutSuccessResponse(final String responseType) { + final StringBuffer sb = new StringBuffer(); if (BaseCmd.RESPONSE_TYPE_JSON.equalsIgnoreCase(responseType)) { sb.append("{ \"logoutresponse\" : { \"description\" : \"success\" } }"); } else { http://git-wip-us.apache.org/repos/asf/cloudstack/blob/447430c3/server/src/com/cloud/api/ParameterHandler.java ---------------------------------------------------------------------- diff --git a/server/src/com/cloud/api/ParameterHandler.java b/server/src/com/cloud/api/ParameterHandler.java new file mode 100644 index 0000000..a9eb390 --- /dev/null +++ b/server/src/com/cloud/api/ParameterHandler.java @@ -0,0 +1,138 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.api; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.log4j.Logger; + +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.ServerApiException; + +public class ParameterHandler { + + private static final Logger s_logger = Logger.getLogger(ParameterHandler.class.getName()); + + /** + * Non-printable ASCII characters - numbers 0 to 31 and 127 decimal + */ + public static final String CONTROL_CHARACTERS = "[\000-\011\013-\014\016-\037\177]"; + + @SuppressWarnings({"unchecked", "rawtypes"}) + public static Map unpackParams(final Map params) { + final Map stringMap = new HashMap(); + final Set keys = params.keySet(); + final Iterator keysIter = keys.iterator(); + while (keysIter.hasNext()) { + final String key = (String)keysIter.next(); + final String[] value = (String[])params.get(key); + // fail if parameter value contains ASCII control (non-printable) characters + if (value[0] != null) { + final Pattern pattern = Pattern.compile(CONTROL_CHARACTERS); + final Matcher matcher = pattern.matcher(value[0]); + if (matcher.find()) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Received value " + value[0] + " for parameter " + key + + " is invalid, contains illegal ASCII non-printable characters"); + } + } + stringMap.put(key, value[0]); + } + + final Map lowercaseParams = new HashMap(); + for (final Object keyObject : stringMap.keySet()) { + final String key = (String) keyObject; + final int arrayStartIndex = key.indexOf('['); + final int arrayStartLastIndex = key.lastIndexOf('['); + if (arrayStartIndex != arrayStartLastIndex) { + throw new ServerApiException(ApiErrorCode.MALFORMED_PARAMETER_ERROR, "Unable to decode parameter " + key + + "; if specifying an object array, please use parameter[index].field=XXX, e.g. userGroupList[0].group=httpGroup"); + } + + if (arrayStartIndex > 0) { + final int arrayEndIndex = key.indexOf(']'); + final int arrayEndLastIndex = key.lastIndexOf(']'); + if ((arrayEndIndex < arrayStartIndex) || (arrayEndIndex != arrayEndLastIndex)) { + // malformed parameter + throw new ServerApiException(ApiErrorCode.MALFORMED_PARAMETER_ERROR, "Unable to decode parameter " + key + + "; if specifying an object array, please use parameter[index].field=XXX, e.g. userGroupList[0].group=httpGroup"); + } + + // Now that we have an array object, check for a field name in the case of a complex object + final int fieldIndex = key.indexOf('.'); + String fieldName = null; + if (fieldIndex < arrayEndIndex) { + throw new ServerApiException(ApiErrorCode.MALFORMED_PARAMETER_ERROR, "Unable to decode parameter " + key + + "; if specifying an object array, please use parameter[index].field=XXX, e.g. userGroupList[0].group=httpGroup"); + } else { + fieldName = key.substring(fieldIndex + 1); + } + + // parse the parameter name as the text before the first '[' character + String paramName = key.substring(0, arrayStartIndex); + paramName = paramName.toLowerCase(); + + Map mapArray = null; + Map mapValue = null; + final String indexStr = key.substring(arrayStartIndex + 1, arrayEndIndex); + int index = 0; + boolean parsedIndex = false; + try { + if (indexStr != null) { + index = Integer.parseInt(indexStr); + parsedIndex = true; + } + } catch (final NumberFormatException nfe) { + s_logger.warn("Invalid parameter " + key + " received, unable to parse object array, returning an error."); + } + + if (!parsedIndex) { + throw new ServerApiException(ApiErrorCode.MALFORMED_PARAMETER_ERROR, "Unable to decode parameter " + key + + "; if specifying an object array, please use parameter[index].field=XXX, e.g. userGroupList[0].group=httpGroup"); + } + + final Object value = lowercaseParams.get(paramName); + if (value == null) { + // for now, assume object array with sub fields + mapArray = new HashMap(); + mapValue = new HashMap(); + mapArray.put(Integer.valueOf(index), mapValue); + } else if (value instanceof Map) { + mapArray = (HashMap)value; + mapValue = mapArray.get(Integer.valueOf(index)); + if (mapValue == null) { + mapValue = new HashMap(); + mapArray.put(Integer.valueOf(index), mapValue); + } + } + + // we are ready to store the value for a particular field into the map for this object + mapValue.put(fieldName, stringMap.get(key)); + + lowercaseParams.put(paramName, mapArray); + } else { + lowercaseParams.put(key.toLowerCase(), stringMap.get(key)); + } + } + return lowercaseParams; + } + +} http://git-wip-us.apache.org/repos/asf/cloudstack/blob/447430c3/server/src/com/cloud/api/dispatch/CommandCreationWorker.java ---------------------------------------------------------------------- diff --git a/server/src/com/cloud/api/dispatch/CommandCreationWorker.java b/server/src/com/cloud/api/dispatch/CommandCreationWorker.java new file mode 100644 index 0000000..3e11cc0 --- /dev/null +++ b/server/src/com/cloud/api/dispatch/CommandCreationWorker.java @@ -0,0 +1,55 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package com.cloud.api.dispatch; + +import java.util.Map; + +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseAsyncCreateCmd; +import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.ServerApiException; + +import com.cloud.exception.ResourceAllocationException; + + +/** + * This worker validates parameters in a semantic way, that is of + * course specific for each {@link BaseCmd}, so actually it delegates + * the validation on the {@link BaseCmd} itself + * + * @author afornie + */ +public class CommandCreationWorker implements DispatchWorker { + + @Override + public boolean handle(final BaseCmd cmd, final Map params) { + if (cmd instanceof BaseAsyncCreateCmd) { + try { + ((BaseAsyncCreateCmd)cmd).create(); + } catch (final ResourceAllocationException e) { + throw new ServerApiException(ApiErrorCode.RESOURCE_ALLOCATION_ERROR, + e.getMessage(), e); + } + } else { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, + "Trying to invoke creation on a Command that is not BaseAsyncCreateCmd"); + } + return true; + } + +} http://git-wip-us.apache.org/repos/asf/cloudstack/blob/447430c3/server/src/com/cloud/api/dispatch/DispatchChain.java ---------------------------------------------------------------------- diff --git a/server/src/com/cloud/api/dispatch/DispatchChain.java b/server/src/com/cloud/api/dispatch/DispatchChain.java new file mode 100644 index 0000000..ecbb883 --- /dev/null +++ b/server/src/com/cloud/api/dispatch/DispatchChain.java @@ -0,0 +1,45 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package com.cloud.api.dispatch; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.ServerApiException; + +public class DispatchChain { + + protected List workers = new ArrayList(); + + public DispatchChain add(final DispatchWorker worker) { + workers.add(worker); + return this; + } + + public void dispatch(final BaseCmd cmd, final Map params) + throws ServerApiException { + + for (final DispatchWorker worker : workers) { + if (!worker.handle(cmd, params)) { + break; + } + } + } +}