com.infinities.nova.policy.Rules.java Source code

Java tutorial

Introduction

Here is the source code for com.infinities.nova.policy.Rules.java

Source

/*******************************************************************************
 * Copyright 2015 InfinitiesSoft Solutions Inc.
 *
 * Licensed 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.infinities.nova.policy;

import java.io.IOException;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.fasterxml.jackson.core.type.TypeReference;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.infinities.nova.policy.check.Check;
import com.infinities.nova.policy.check.FalseCheck;
import com.infinities.nova.policy.check.GenericCheck;
import com.infinities.nova.policy.check.HttpCheck;
import com.infinities.nova.policy.check.IsAdminCheck;
import com.infinities.nova.policy.check.RoleCheck;
import com.infinities.nova.policy.check.RuleCheck;
import com.infinities.nova.policy.check.StringCheck;
import com.infinities.nova.policy.check.TrueCheck;
import com.infinities.skyport.util.JsonUtil;

public class Rules implements Map<String, BaseCheck> {

    private final static Logger logger = LoggerFactory.getLogger(Rules.class);
    private final static String NO_HANDLER = "No handler for matches of kind {}";
    private final static String FAIL_TO_UNDERSTAND_RULE = "Failed to understand rule {}";
    private final static String NONE = "none";
    private Map<String, BaseCheck> rules;
    private Object defaultRule;
    private final static Map<String, Check> checks = Maps.newHashMap();
    // private final List<String> checks = Lists.newArrayList();
    // private final long lastModified;
    private final static Set<String> logicOperators = Sets.newHashSet();

    static {
        logicOperators.add("and");
        logicOperators.add("or");
        logicOperators.add("not");
    }

    public Rules(Map<String, BaseCheck> rules, Object defaultRule) {
        this.rules = rules;
        if (this.rules == null) {
            this.rules = Maps.newHashMap();
        }
        this.defaultRule = defaultRule;
        setChecks(checks);
    }

    private void setChecks(Map<String, Check> checks) {
        checks.put("rule", new RuleCheck());
        checks.put("role", new RoleCheck());
        checks.put("http", new HttpCheck());
        checks.put("is_admin", new IsAdminCheck());
        checks.put("none", new GenericCheck());
    }

    public static Rules loadJson(String data, Object defaultRule) throws IOException {
        Map<String, String> map = JsonUtil.readJson(data, new TypeReference<LinkedHashMap<String, String>>() {
        });

        Map<String, BaseCheck> rules = Maps.newHashMap();
        for (Entry<String, String> entry : map.entrySet()) {
            logger.debug("put rules key:{}, value:{} ", new Object[] { entry.getKey(), entry.getValue() });
            rules.put(entry.getKey(), parseRule(entry.getValue()));
        }

        return new Rules(rules, defaultRule);
    }

    // parse_rule _parse_text_rule
    private static BaseCheck parseRule(String value) {
        if (Strings.isNullOrEmpty(value)) {
            return new TrueCheck();
        }

        ParseState state = new ParseState();
        List<Entry<String, BaseCheck>> entrys = parseTokenize(value);

        for (Entry<String, BaseCheck> entry : entrys) {
            state.shift(entry);
        }

        try {
            logger.debug("parse rule: {} --> {}", new Object[] { value, state.getResult().getValue().getRule() });
            return state.getResult().getValue();
        } catch (IllegalArgumentException e) {
            logger.error(FAIL_TO_UNDERSTAND_RULE, value);
            logger.error("", e);
            return new FalseCheck();
        }
    }

    private static List<Entry<String, BaseCheck>> parseTokenize(String orig) {
        String[] tokens = orig.split("\\s+");

        List<Entry<String, BaseCheck>> entrys = Lists.newArrayList();

        for (String token : tokens) {
            token = token.trim();
            if (Strings.isNullOrEmpty(token)) {
                continue;
            }
            String clean = lstrip(token, "(");
            int range = token.length() - clean.length();
            // logger.debug("lstrip: {}, range:{}", new Object[] { clean, range
            // });
            for (int i = 0; i < range; i++) {
                BaseCheck check = new StringCheck("(");
                entrys.add(Maps.immutableEntry("(", check));
            }

            if (Strings.isNullOrEmpty(clean)) {
                continue;
            } else {
                token = clean;
            }

            clean = rstrip(token, ")");
            int trail = token.length() - clean.length();
            // logger.debug("rstrip: {}, trail:{}", new Object[] { clean, trail
            // });
            String lowered = clean.toLowerCase();
            if (logicOperators.contains(lowered)) {
                BaseCheck check = new StringCheck(clean);
                entrys.add(Maps.immutableEntry(lowered, check));
            } else if (!Strings.isNullOrEmpty(clean)) {
                if (token.length() >= 2 && ((token.charAt(0) == '\"' && token.charAt(token.length()) == '\"')
                        || (token.charAt(0) == '\'' && token.charAt(token.length()) == '\''))) {
                    BaseCheck check = new StringCheck(token.substring(1, token.length() - 1));
                    entrys.add(Maps.immutableEntry("string", check));
                } else {
                    entrys.add(Maps.immutableEntry("check", parseCheck(clean)));
                }
            }

            for (int i = 0; i < trail; i++) {
                BaseCheck check = new StringCheck(")");
                entrys.add(Maps.immutableEntry(")", check));
            }
        }

        return entrys;
    }

    private static BaseCheck parseCheck(String clean) {
        if (clean.equals("|")) {
            return new FalseCheck();
        } else if (clean.equals("@")) {
            return new TrueCheck();
        }

        String[] splitStr;
        try {
            splitStr = clean.split(":", 2);
        } catch (Exception e) {
            logger.error(FAIL_TO_UNDERSTAND_RULE, clean);
            return new FalseCheck();
        }
        String kind = splitStr[0];
        String match = splitStr[1];

        if (checks.containsKey(kind)) {
            Check check = checks.get(kind).newInstance(kind, match);
            return check;
        } else if (checks.containsKey(NONE)) {
            Check check = checks.get(NONE).newInstance(kind, match);
            return check;
        } else {
            logger.error(NO_HANDLER, splitStr[0]);
            return new FalseCheck();
        }
    }

    private static String lstrip(String orig, String strip) {
        char[] origs = orig.toCharArray();
        char[] tokens = strip.toCharArray();
        StringBuilder ret = new StringBuilder();
        boolean isStriped = false;

        for (int i = 0; i < origs.length; i++) {
            boolean isEquals = false;
            for (int j = 0; j < tokens.length; j++) {
                if (tokens[j] == origs[i]) {
                    isEquals = true;
                }
            }
            if (isStriped) {
                ret.append(origs[i]);
                continue;
            } else {
                if (isEquals) {
                    continue;
                } else {
                    isStriped = true;
                    ret.append(origs[i]);
                }
            }
        }
        return ret.toString();
    }

    private static String rstrip(String orig, String strip) {
        char[] origs = orig.toCharArray();
        char[] tokens = strip.toCharArray();
        StringBuilder ret = new StringBuilder();
        boolean isStriped = false;

        for (int i = origs.length - 1; i >= 0; i--) {
            boolean isEquals = false;
            for (int j = 0; j < tokens.length; j++) {
                if (tokens[j] == origs[i]) {
                    isEquals = true;
                }
            }
            if (isStriped) {
                ret.append(origs[i]);
                continue;
            } else {
                if (isEquals) {
                    continue;
                } else {
                    isStriped = true;
                    ret.append(origs[i]);
                }
            }
        }
        return ret.reverse().toString();
    }

    public Map<String, BaseCheck> getRules() {
        return rules;
    }

    @Override
    public void clear() {
        rules.clear();
    }

    @Override
    public boolean containsKey(Object key) {
        return rules.containsKey(key);
    }

    @Override
    public boolean containsValue(Object value) {
        return rules.containsValue(value);
    }

    @Override
    public Set<java.util.Map.Entry<String, BaseCheck>> entrySet() {
        return rules.entrySet();
    }

    @Override
    public BaseCheck get(Object key) {
        BaseCheck value = rules.get(key);

        if (value != null) {
            return value;
        }

        if (defaultRule == null) {
            throw new IllegalArgumentException((String) key);
        }

        if (defaultRule instanceof BaseCheck) {
            return (BaseCheck) defaultRule;
        }

        if (defaultRule instanceof String) {
            if (rules.containsKey(defaultRule)) {
                return rules.get(defaultRule);
            } else {
                throw new IllegalArgumentException((String) key);
            }
        }

        throw new IllegalArgumentException((String) key);
    }

    @Override
    public boolean isEmpty() {
        return rules.isEmpty();
    }

    @Override
    public Set<String> keySet() {
        return rules.keySet();
    }

    @Override
    public BaseCheck put(String key, BaseCheck value) {
        return rules.put(key, value);
    }

    @Override
    public void putAll(Map<? extends String, ? extends BaseCheck> m) {
        rules.putAll(m);
    }

    @Override
    public BaseCheck remove(Object key) {
        return rules.remove(key);
    }

    @Override
    public int size() {
        return rules.size();
    }

    @Override
    public Collection<BaseCheck> values() {
        return rules.values();
    }

}