mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
CLOUDSTACK-9361: Centrally handle API validations
Validate API arguments based on annotations. Introduces: - NotNullOrEmpty: for doing null and empty string checks - PositiveNumber: number > 0 (natural number) Signed-off-by: Rohit Yadav <rohit.yadav@shapeblue.com>
This commit is contained in:
parent
456680dbb2
commit
95abb6efc3
23
api/src/org/apache/cloudstack/api/ApiArgValidator.java
Normal file
23
api/src/org/apache/cloudstack/api/ApiArgValidator.java
Normal file
@ -0,0 +1,23 @@
|
||||
// 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 org.apache.cloudstack.api;
|
||||
|
||||
public enum ApiArgValidator {
|
||||
NotNullOrEmpty, // does Strings.isNullOrEmpty check
|
||||
PositiveNumber, // does != null and > 0 check
|
||||
}
|
||||
@ -49,4 +49,6 @@ public @interface Parameter {
|
||||
String since() default "";
|
||||
|
||||
RoleType[] authorized() default {};
|
||||
|
||||
ApiArgValidator[] validations() default {};
|
||||
}
|
||||
|
||||
@ -34,6 +34,7 @@ import java.text.SimpleDateFormat;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import org.apache.cloudstack.acl.ControlledEntity;
|
||||
@ -49,6 +50,7 @@ import org.apache.cloudstack.api.EntityReference;
|
||||
import org.apache.cloudstack.api.InternalIdentity;
|
||||
import org.apache.cloudstack.api.Parameter;
|
||||
import org.apache.cloudstack.api.ServerApiException;
|
||||
import org.apache.cloudstack.api.ApiArgValidator;
|
||||
import org.apache.cloudstack.api.command.admin.resource.ArchiveAlertsCmd;
|
||||
import org.apache.cloudstack.api.command.admin.resource.DeleteAlertsCmd;
|
||||
import org.apache.cloudstack.api.command.admin.usage.GetUsageRecordsCmd;
|
||||
@ -92,6 +94,55 @@ public class ParamProcessWorker implements DispatchWorker {
|
||||
processParameters(task.getCmd(), task.getParams());
|
||||
}
|
||||
|
||||
private void validateNonEmptyString(final Object param, final String argName) {
|
||||
if (param == null || Strings.isNullOrEmpty(param.toString())) {
|
||||
throw new ServerApiException(ApiErrorCode.PARAM_ERROR, String.format("Empty or null value provided for API arg: %s", argName));
|
||||
}
|
||||
}
|
||||
|
||||
private void validateNaturalNumber(final Object param, final String argName) {
|
||||
Long value = null;
|
||||
if (param != null && param instanceof Long) {
|
||||
value = (Long) param;
|
||||
} else if (param != null) {
|
||||
value = Long.valueOf(param.toString());
|
||||
}
|
||||
if (value == null || value < 1L) {
|
||||
throw new ServerApiException(ApiErrorCode.PARAM_ERROR, String.format("Invalid value provided for API arg: %s", argName));
|
||||
}
|
||||
}
|
||||
|
||||
private void validateField(final Object paramObj, final Parameter annotation) throws ServerApiException {
|
||||
if (annotation == null) {
|
||||
return;
|
||||
}
|
||||
final String argName = annotation.name();
|
||||
for (final ApiArgValidator validator : annotation.validations()) {
|
||||
if (validator == null) {
|
||||
continue;
|
||||
}
|
||||
switch (validator) {
|
||||
case NotNullOrEmpty:
|
||||
switch (annotation.type()) {
|
||||
case UUID:
|
||||
case STRING:
|
||||
validateNonEmptyString(paramObj, argName);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case PositiveNumber:
|
||||
switch (annotation.type()) {
|
||||
case SHORT:
|
||||
case INTEGER:
|
||||
case LONG:
|
||||
validateNaturalNumber(paramObj, argName);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
public void processParameters(final BaseCmd cmd, final Map params) {
|
||||
final Map<Object, AccessType> entitiesToAccess = new HashMap<Object, AccessType>();
|
||||
@ -112,6 +163,7 @@ public class ParamProcessWorker implements DispatchWorker {
|
||||
|
||||
// marshall the parameter into the correct type and set the field value
|
||||
try {
|
||||
validateField(paramObj, parameterAnnotation);
|
||||
setFieldValue(field, cmd, paramObj, parameterAnnotation);
|
||||
} catch (final IllegalArgumentException argEx) {
|
||||
if (s_logger.isDebugEnabled()) {
|
||||
@ -420,6 +472,7 @@ public class ParamProcessWorker implements DispatchWorker {
|
||||
for (final Class<?> entity : entities) {
|
||||
CallContext.current().putContextParameter(entity, internalId);
|
||||
}
|
||||
validateNaturalNumber(internalId, annotation.name());
|
||||
return internalId;
|
||||
}
|
||||
}
|
||||
@ -452,6 +505,7 @@ public class ParamProcessWorker implements DispatchWorker {
|
||||
throw new InvalidParameterValueException("Invalid parameter " + annotation.name() + " value=" + uuid +
|
||||
" due to incorrect long value format, or entity does not exist or due to incorrect parameter annotation for the field in api cmd class.");
|
||||
}
|
||||
validateNaturalNumber(internalId, annotation.name());
|
||||
return internalId;
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user