001package com.plivo.api.validators;
002
003import com.plivo.api.exceptions.PlivoValidationException;
004import com.plivo.api.util.Utils;
005
006import java.lang.annotation.Annotation;
007import java.lang.reflect.Field;
008import java.lang.reflect.InvocationTargetException;
009import java.lang.reflect.Method;
010import java.util.regex.Pattern;
011
012public class Validate {
013
014
015  private static final Pattern urlPattern = Pattern.compile("(http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\\(\\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+|None)");
016  private static final String COLON = ": ";
017
018
019  private static Object fetchValue(Field field, Object request) {
020    // Find the correct method
021    for (Method method: request.getClass().getMethods()) {
022      if (method.getName().equalsIgnoreCase(field.getName()) && field.getType().toString().equals(method.getReturnType().toString())) {
023        try {
024          return method.invoke(request);
025        } catch (IllegalAccessException | InvocationTargetException e) {
026          e.printStackTrace();
027        }
028      }
029    }
030    return null;
031  }
032
033  private static boolean isNotAmong(String[] options, String element, boolean caseSensitive) {
034    for (String opt: options) {
035      if (!caseSensitive && opt.equalsIgnoreCase(element)) {
036        return false;
037      } else if (opt.equals(element)) {
038        return false;
039      }
040    }
041    return true;
042  }
043
044  private static String composeErrorMessage(String fieldName, String errorMessage) {
045    return fieldName + COLON + errorMessage;
046  }
047
048  public static void check(Object request) throws PlivoValidationException {
049    Field[] fields = request.getClass().getDeclaredFields();
050    for (Field field: fields) {
051      Object value = fetchValue(field, request);
052      if (value == null) {
053        continue;
054      }
055      Annotation[] annotations = field.getAnnotations();
056      for (Annotation annotation: annotations) {
057        if (annotation instanceof InRange) {
058          int actualValue = (int) value;
059          if ((((InRange) annotation).min() > actualValue) || (((InRange) annotation).max() < actualValue)) {
060            throw new PlivoValidationException(composeErrorMessage(field.getName(), ((InRange) annotation).message()));
061          }
062        } else if (annotation instanceof OneOf) {
063          String actualValue = (String) value;
064          if (isNotAmong(((OneOf) annotation).options(), actualValue, ((OneOf) annotation).caseSensitive())) {
065            throw new PlivoValidationException(composeErrorMessage(field.getName(), ((OneOf) annotation).message()));
066          }
067        } else if (annotation instanceof UrlValues) {
068          String actualValue = (String) value;
069          if ((!urlPattern.matcher(actualValue).matches() && isNotAmong(((UrlValues) annotation).options(), actualValue, ((UrlValues) annotation).caseSensitive()))) {
070            throw new PlivoValidationException(composeErrorMessage(field.getName(), ((UrlValues) annotation).message()));
071          }
072        } else if (annotation instanceof MultiOf) {
073          if (!(value instanceof String[])) {
074            continue;
075          }
076          String[] actualValue = (String[]) value;
077          for (String val: actualValue) {
078            if (isNotAmong(((MultiOf) annotation).options(), val, ((MultiOf) annotation).caseSensitive())) {
079              throw new PlivoValidationException(composeErrorMessage(field.getName(), ((MultiOf) annotation).message()));
080            }
081          }
082        } else if (annotation instanceof SubAccount) {
083          String actualValue = (String) value;
084          if (!Utils.isSubaccountIdValid(actualValue)) {
085            throw new PlivoValidationException(composeErrorMessage(field.getName(), ((SubAccount) annotation).message()));
086          }
087        } else if (annotation instanceof MultipleValidIntegers) {
088          if( value instanceof Integer) {
089            Integer actualValue = (Integer) value;
090          } else if ( value instanceof String){
091            String actualValue = (String) value;
092            String []values = actualValue.split("<");
093            for (int i=0; i<values.length; i++){
094              try{
095                Integer.parseInt(values[i]);
096              }catch (NumberFormatException e){
097                throw new PlivoValidationException(composeErrorMessage(field.getName(), ((MultipleValidIntegers) annotation).message()));
098              }
099            }
100          } else{
101            throw new PlivoValidationException(composeErrorMessage(field.getName(), ((MultipleValidIntegers) annotation).message()));
102          }
103        }
104      }
105    }
106  }
107}