All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.github.livr.Validator Maven / Gradle / Ivy

package io.github.livr;

import com.google.common.collect.Lists;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;

import java.io.IOException;
import java.util.*;
import java.util.function.Function;

/**
 * Created by vladislavbaluk on 9/29/2017.
 */
public class Validator {
    Map DEFAULT_RULES = new HashMap<>();
    JSONObject livrRules = new JSONObject();
    Map> validators;
    Map validatorBuilders;
    JSONObject errors;
    boolean isPrepared = false;
    boolean isAutoTrim = false;
    private JSONParser parser = new JSONParser();


    public Validator(Map defaultRules) {
        DEFAULT_RULES = defaultRules;
    }

    public Validator init(JSONObject livrRules, boolean isAutoTrim) {
        this.isPrepared = false;
        this.livrRules = livrRules;
        this.validators = new HashMap<>();
        this.validatorBuilders = new HashMap<>();
        this.errors = null;
        this.isAutoTrim = isAutoTrim;

        this.registerRules(DEFAULT_RULES);

        return this;
    }

    public Validator init(String livrRules, boolean isAutoTrim) throws ParseException {
        this.isPrepared = false;

        this.livrRules = (JSONObject) parser.parse(livrRules);

        this.validators = new HashMap<>();
        this.validatorBuilders = new HashMap<>();
        this.errors = null;
        this.isAutoTrim = isAutoTrim;

        this.registerRules(DEFAULT_RULES);

        return this;
    }

    public Validator() {
    }

    public Validator registerDefaultRules(Map rules) {
        DEFAULT_RULES.putAll(rules);
        return this;
    }

    public Map getDefaultRules() {
        return DEFAULT_RULES;
    }

    public void registerAliasedDefaultRule(JSONObject alias) throws IOException {
        if (((String) alias.get("name")).isEmpty()) throw new IOException("Alias name required");
        String name = (String) alias.get("name");
        DEFAULT_RULES.put(name, _buildAliasedRule(alias));
    }

    Function _buildAliasedRule(JSONObject alias) throws IOException {
        if (((String) alias.get("name")).isEmpty()) throw new IOException("Alias name required");
        if (alias.get("rules") == null) throw new IOException("Alias rules required");

        JSONObject livr = new JSONObject();
        Object rules = alias.get("rules");
        livr.put("value", rules);

        Function, Function> aliasFunction = objects -> {
            Map ruleBuilders = (Map) ((objects.size() > 1) ? objects.get(1) : objects.get(0));
            try {
                Validator validator = new Validator(ruleBuilders).init(livr, false).prepare();
                return (Function) (wrapper) -> {
                    try {
                        JSONObject json = new JSONObject();
                        json.put("value", wrapper.getValue());
                        JSONObject result = validator.validate(json);

                        if (result != null) {
                            wrapper.getFieldResultArr().add(result.get("value"));
                            return "";
                        } else {
                            return alias.get("error") == null ? validator.getErrors().get("value") : alias.get("error");
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    } catch (ParseException e) {
                        e.printStackTrace();
                    }
                    return null;
                };
            } catch (IOException e) {
                e.printStackTrace();
            }
            return null;
        };
        return aliasFunction;
    }

    public Validator prepare() throws IOException {
        JSONObject allRules = this.livrRules;

        for (String field : (Set) allRules.keySet()) {
            Object fieldRules = allRules.get(field);
            JSONArray rules1 = null;
            if (fieldRules.getClass() == JSONArray.class) {
                rules1 = (JSONArray) fieldRules;
            }
            if (fieldRules.getClass() == JSONObject.class) {
                rules1 = new JSONArray();
                rules1.add(fieldRules);
            }
            if (fieldRules.getClass() == String.class) {
                rules1 = new JSONArray();
                JSONObject json = new JSONObject();
                json.put(fieldRules, new JSONArray());
                rules1.add(json);
            }
            if (rules1 == null)
                return this;

            List validators = new ArrayList<>();

            for (int i = 0; i < rules1.size(); i++) {
                Map parsed = this._parseRule(rules1.get(i));
                validators.add(this._buildValidator((String) parsed.get("name"), (List) parsed.get("args")));
            }

            this.validators.put(field, validators);
        }

        this.isPrepared = true;
        return this;
    }

    public JSONObject validate(Object str) throws IOException {
        try {
            if (str == null) {
                throw new ParseException(0);
            }
            return validate((JSONObject) parser.parse(str + ""));
        } catch (ParseException e) {
            this.errors = new JSONObject();
            this.errors.put("base", "FORMAT_ERROR");
            return null;
        }
    }

    public JSONObject validate(JSONObject data) throws IOException, ParseException {
        if (!this.isPrepared) this.prepare();

        if (this.isAutoTrim) {
            data = (JSONObject) _autoTrim(data);
        }

        JSONObject errors = new JSONObject();
        Map result = new HashMap<>();
        JSONObject finalData = data;

        for (String k : validators.keySet()) {
            Object value = finalData.get(k);
            List valids = validators.get(k);
            for (FunctionKeeper v : valids) {
                v.setFieldResultArr(new ArrayList<>());
                v.setValue(result.get(k) != null ? result.get(k) : value);
                v.setArgs(toMap(finalData));
                Object errCode = v.getFunction().apply(v);
                if (errCode != null && !errCode.toString().isEmpty()) {
                    errors.put(k, errCode);
                    break;
                } else if (!v.getFieldResultArr().isEmpty()) {
                    result.put(k, v.getFieldResultArr().get(0));
                } else if (finalData.get(k) != null && !result.containsKey(k)) {
                    result.put(k, value);
                }
            }
        }

        if (LIVRUtils.isEmptyObject(errors)) {
            this.errors = null;

            return (JSONObject) new JSONParser().parse(JSONObject.toJSONString(result));
        } else {
            this.errors = errors;
            return null;
        }
    }

    public JSONObject getErrors() {
        return this.errors;
    }

    public Validator registerRules(Map rules) {
        validatorBuilders.putAll(rules);
        return this;
    }

    public void registerAliasedRule(String alias) throws IOException, ParseException {
        registerAliasedRule((JSONObject) parser.parse(alias));
    }

    public void registerAliasedRule(JSONObject alias) throws IOException {
        if (((String) alias.get("name")).isEmpty()) throw new IOException("Alias name required");
        String name = (String) alias.get("name");
        this.validatorBuilders.put(name, _buildAliasedRule(alias));
    }

    public Map getRules() {
        return this.validatorBuilders;
    }

    public Map _parseRule(Object livrRule) {
        String name;
        List args = new ArrayList<>();

        if (LIVRUtils.isObject(livrRule)) {
            name = (String) ((JSONObject) livrRule).keySet().iterator().next();
            Object args1 = ((JSONObject) livrRule).get(name);

            if (args1.getClass() == JSONArray.class) {
                args1 = removeRedundantBracers((JSONArray) args1);
                args = Lists.newArrayList();
                args.add(args1);
            } else args = Lists.newArrayList(args1);
        } else {
            name = (String) livrRule;
        }
        Map map = new HashMap();
        map.put("name", name);
        map.put("args", args);
        return map;
    }

    public Object removeRedundantBracers(JSONArray jsonArray) {
        if (jsonArray.size() == 1 && jsonArray.get(0) instanceof JSONArray) {
            return removeRedundantBracers((JSONArray) jsonArray.get(0));
        } else if (jsonArray.size() == 1 && !(jsonArray.get(0) instanceof JSONArray)) {
            return jsonArray.get(0);
        }
        return jsonArray;
    }

    public FunctionKeeper _buildValidator(String name, List args) throws IOException {

        if (this.validatorBuilders.get(name) == null) {
            throw new IOException("Rule [" + name + "] not registered");
        }

        Function func = this.validatorBuilders.get(name);

        args.add(this.getRules());
        func = (Function) func.apply(args);

        return new FunctionKeeper(null, func);
    }

    public static Object _autoTrim(Object data) {
        Class dataType = data.getClass();

        if (dataType != JSONObject.class) {
            if (data != null) {
                return (data + "").trim();
            } else {
                return data;
            }
        } else if (dataType == JSONArray.class) {
            JSONArray trimmedData = new JSONArray();

            for (Object entry : ((JSONArray) data).toArray()) {
                trimmedData.add(Validator._autoTrim(entry));
            }
            return trimmedData;
        } else if (dataType == JSONObject.class) {
            JSONObject trimmedData = new JSONObject();

            for (Object key : ((JSONObject) data).keySet()) {
                trimmedData.put(key, Validator._autoTrim(((JSONObject) data).get(key)));
            }
            return trimmedData;
        }

        return data;
    }


    public static Map toMap(JSONObject object) {
        Map map = new HashMap();

        Iterator keysItr = object.keySet().iterator();
        while (keysItr.hasNext()) {
            String key = keysItr.next();
            Object value = object.get(key);

            if (value instanceof JSONArray) {
                value = toList((JSONArray) value);
            } else if (value instanceof JSONObject) {
                value = toMap((JSONObject) value);
            }
            map.put(key, value);
        }
        return map;
    }

    public static List toList(JSONArray array) {
        List list = new ArrayList();
        for (int i = 0; i < array.size(); i++) {
            Object value = array.get(i);
            if (value instanceof JSONArray) {
                value = toList((JSONArray) value);
            } else if (value instanceof JSONObject) {
                value = toMap((JSONObject) value);
            }
            list.add(value);
        }
        return list;
    }
}