package org.zstack.sdk;
import java.lang.reflect.Field;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Created by xing5 on 2016/12/9.
*/
public abstract class AbstractAction {
public String apiId;
abstract RestInfo getRestInfo();
static class Parameter {
Field field;
Param annotation;
}
abstract Map<String, Parameter> getParameterMap();
private void initializeParametersIfNot() {
synchronized (getParameterMap()) {
if (getParameterMap().isEmpty()) {
List<Field> fields = getAllFields();
for (Field f : fields) {
Param at = f.getAnnotation(Param.class);
if (at == null) {
continue;
}
Parameter p = new Parameter();
p.annotation = at;
p.field = f;
p.field.setAccessible(true);
getParameterMap().put(f.getName(), p);
}
}
}
}
protected List<Field> getAllFields() {
Class c = getClass();
List<Field> fs = new ArrayList<>();
while (c != Object.class) {
Collections.addAll(fs, c.getDeclaredFields());
c = c.getSuperclass();
}
return fs;
}
Set<String> getAllParameterNames() {
initializeParametersIfNot();
return getParameterMap().keySet();
}
Object getParameterValue(String name){
return getParameterValue(name, true);
}
Object getParameterValue(String name, boolean exceptionOnNotFound){
Parameter p = getParameterMap().get(name);
if (p == null) {
if (exceptionOnNotFound) {
throw new ApiException(String.format("no such parameter[%s]", name));
} else {
return null;
}
}
try {
return p.field.get(this);
} catch (IllegalAccessException e) {
throw new ApiException(e);
}
}
void checkParameters() {
initializeParametersIfNot();
try {
for (Parameter p : getParameterMap().values()) {
Object value = p.field.get(this);
Param at = p.annotation;
if (at.required() && value == null) {
throw new ApiException(String.format("missing mandatory field[%s]", p.field.getName()));
}
if (value != null && (value instanceof String) && !at.noTrim()) {
value = ((String) value).trim();
}
if (value != null && at.maxLength() != Integer.MIN_VALUE && (value instanceof String)) {
String str = (String) value;
if (str.length() > at.maxLength()) {
throw new ApiException(String.format("filed[%s] exceeds the max length[%s chars] of string",
p.field.getName(), at.maxLength()));
}
}
if (value != null && at.minLength() != 0 && (value instanceof String)) {
String str = (String) value;
if (str.length() < at.minLength()) {
throw new ApiException(String.format("filed[%s] less than the min length[%s chars] of string",
p.field.getName(), at.minLength()));
}
}
if (value != null && at.validValues().length > 0) {
List vals = Arrays.asList(at.validValues());
if (!vals.contains(value.toString())) {
throw new ApiException(String.format("invalid value of the field[%s], valid values are %s",
p.field.getName(), vals));
}
}
if (value != null && at.validRegexValues() != null && at.validRegexValues().trim().equals("") == false) {
String regex = at.validRegexValues().trim();
Pattern pt = Pattern.compile(regex);
Matcher mt = pt.matcher(value.toString());
if (!mt.matches()) {
throw new ApiException(String.format("the value of the field[%s] doesn't match the required regular" +
" expression[%s]", p.field.getName(), regex));
}
}
if (value != null && at.nonempty() && value instanceof Collection) {
Collection col = (Collection) value;
if (col.isEmpty()) {
throw new ApiException(String.format("field[%s] cannot be an empty list", p.field.getName()));
}
}
if (value != null && !at.nullElements() && value instanceof Collection) {
Collection col = (Collection) value;
for (Object o : col) {
if (o == null) {
throw new ApiException(String.format("field[%s] cannot contain any null element", p.field.getName()));
}
}
}
if (value != null && !at.emptyString()) {
if ((value instanceof String) && ((String) value).length() == 0) {
throw new ApiException(String.format("the value of the field[%s] cannot be an empty string", p.field.getName()));
} else if (value instanceof Collection) {
for (Object v : (Collection) value) {
if (v instanceof String && ((String) v).length() == 0) {
throw new ApiException(String.format("the field[%s] cannot contain any empty string", p.field.getName()));
}
}
}
}
if (value != null && at.numberRange().length > 0
&& (value instanceof Long || long.class.isAssignableFrom(value.getClass()) || value instanceof Integer || int.class.isAssignableFrom(value.getClass()))) {
long low = at.numberRange()[0];
long high = at.numberRange()[1];
long val = Long.valueOf(((Number) value).longValue());
if (val < low || val > high) {
throw new ApiException(String.format("the value of the field[%s] out of range[%s, %s]", p.field.getName(), low, high));
}
}
}
} catch (ApiException e) {
throw e;
} catch (Exception e) {
throw new ApiException(e);
}
}
}