com.seer.datacruncher.validation.MacroRulesValidation.java Source code

Java tutorial

Introduction

Here is the source code for com.seer.datacruncher.validation.MacroRulesValidation.java

Source

/*
 * Copyright (c) 2015  www.see-r.com
 * All rights reserved
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.seer.datacruncher.validation;

import com.seer.datacruncher.constants.FieldType;
import com.seer.datacruncher.constants.StreamStatus;
import com.seer.datacruncher.constants.StreamType;
import com.seer.datacruncher.datastreams.DatastreamDTO;
import com.seer.datacruncher.jpa.dao.DaoSet;
import com.seer.datacruncher.jpa.entity.MacroEntity;
import com.seer.datacruncher.jpa.entity.SchemaFieldEntity;
import com.seer.datacruncher.macros.JEXLFieldFactory;
import com.seer.datacruncher.macros.JexlEngineFactory;
import com.seer.datacruncher.utils.generic.I18n;
import com.seer.datacruncher.utils.generic.StreamsUtils;
import org.apache.commons.jexl2.Expression;
import org.apache.commons.jexl2.JexlContext;
import org.apache.commons.jexl2.JexlEngine;
import org.apache.commons.jexl2.MapContext;
import org.apache.log4j.Logger;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import javax.persistence.Query;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.*;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class MacroRulesValidation implements DaoSet {

    static Logger log = Logger.getLogger(MacroRulesValidation.class);
    public static final String MACRO_SQL_VALIDATOR_PATTERN = "SELECT (\\w+|\\w+[.]\\w+) FROM \\w+[.]\\w+ WHERE (\\w+|\\w+[.]\\w+)\\s?(>|<|=|!=)\\s?(\\w+)";

    /**
     * Apply validation macro rules.
     * @param datastreamDTO
     * @return ResultStepValidation
     */
    protected ResultStepValidation doValidation(DatastreamDTO datastreamDTO) {
        long schemaId = datastreamDTO.getIdSchema();
        List<MacroEntity> list = new ArrayList<MacroEntity>();
        DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
        try {
            DocumentBuilder builder = domFactory.newDocumentBuilder();
            Document doc = builder
                    .parse(new ByteArrayInputStream(schemasXSDDao.find(schemaId).getSchemaXSD().getBytes()));
            XPathFactory factory = XPathFactory.newInstance();
            XPath xpath = factory.newXPath();
            XPathExpression expr = xpath.compile("//annotation/appinfo/text()");
            Object result = expr.evaluate(doc, XPathConstants.NODESET);
            NodeList nodes = (NodeList) result;
            for (int i = 0; i < nodes.getLength(); i++) {
                String val = nodes.item(i).getNodeValue();
                if (val.startsWith("@RuleCheck")) {
                    String[] arr = val.split(";\n");
                    for (String s : arr) {
                        list.add(macrosDao.getMacroEntityByName(s.trim().substring(11)));
                    }
                    break;
                }
            }
        } catch (ParserConfigurationException e) {
            log.error("ParserConfigurationException", e);
        } catch (SAXException e) {
            log.error("SAXException", e);
        } catch (IOException e) {
            log.error("IOException", e);
        } catch (XPathExpressionException e) {
            log.error("XPathExpressionException", e);
        }
        ResultStepValidation resultStepValidation = new ResultStepValidation();
        resultStepValidation.setValid(true);
        resultStepValidation.setMessageResult(I18n.getMessage("success.validationOK"));
        List<Element> xmlTextNodes = null;
        try {
            xmlTextNodes = StreamsUtils.parseStreamXml(datastreamDTO.getOutput());
        } catch (DocumentException e) {
            log.error("Stream parse exception", e);
        }
        JexlEngine jexl = JexlEngineFactory.getInstance();
        boolean isSuccess = true;
        Pattern pattern = Pattern.compile(MACRO_SQL_VALIDATOR_PATTERN, Pattern.CASE_INSENSITIVE);
        for (MacroEntity ent : list) {
            if (!isSuccess)
                continue;
            String rule = ent.getRule();
            List<Map<String, String>> varsList = parseVars(ent.getVars());
            combineVariableLists(varsList, schemaId);
            Matcher matcher = pattern.matcher(rule);
            while (matcher.find()) {
                String varName = matcher.group(4);
                String sqlRes = "false";
                for (Map<String, String> m : varsList) {
                    if (m.get("uniqueName").equals(varName)) {
                        for (Element el : xmlTextNodes) {
                            int t = datastreamDTO.getIdStreamType();
                            String fieldPath = (t == StreamType.XML || t == StreamType.XMLEXI ? "" : "ROOT/")
                                    + m.get("nodePath");
                            if (fieldPath.equals(StreamsUtils.formatPathForXmlNode(el.getPath()))) {
                                String prepSql = matcher.group().replaceAll(matcher.group(4),
                                        "\"" + el.getText() + "\"");
                                String signum = matcher.group(3);
                                if (signum.equals("<")) {
                                    prepSql = prepSql.replaceAll(signum, ">=");
                                } else if (signum.equals(">")) {
                                    prepSql = prepSql.replaceAll(signum, "<=");
                                } else if (signum.equals("!=")) {
                                    prepSql = prepSql.replaceAll(signum, "=");
                                }
                                Query q = entityManager.createNativeQuery(prepSql);
                                @SuppressWarnings("rawtypes")
                                List resList = q.getResultList();
                                if ((signum.equals("=") && resList.size() > 0)
                                        || (signum.equals("!=") && resList.size() == 0)
                                        || (signum.equals(">") && resList.size() == 0)
                                        || (signum.equals("<") && resList.size() == 0)) {
                                    sqlRes = "true";
                                }
                                break;
                            }
                        }
                    }
                }
                rule = rule.replaceAll(matcher.group(), sqlRes);
            }
            Expression e = jexl.createExpression(rule);
            JexlContext context = new MapContext();
            for (Map<String, String> m : varsList) {
                for (Element el : xmlTextNodes) {
                    int t = datastreamDTO.getIdStreamType();
                    String fieldPath = (t == StreamType.XML || t == StreamType.XMLEXI ? "" : "ROOT/")
                            + m.get("nodePath");
                    if (fieldPath.equals(StreamsUtils.formatPathForXmlNode(el.getPath()))) {
                        context.set(m.get("uniqueName"),
                                JEXLFieldFactory.getField(m.get("fieldType"), el.getText()).getValue());
                        break;
                    }
                }
            }
            Object res = e.evaluate(context);
            if (res != null) {
                isSuccess = false;
                resultStepValidation.setValid(false);
                if (ent.getErrorType() == StreamStatus.Warning.getCode()) {
                    resultStepValidation.setWarning(true);
                }
                resultStepValidation
                        .setMessageResult(I18n.getMessage("error.validationMacro") + ": " + res.toString());
            }
        }
        return resultStepValidation;
    }

    /**
     * Combines macro's variable lists: from jv_schema_fields and from jv_macros
     *
     * @param list - list of variables retrieved from jv_macros
     * @param schemaId - id of the schema for which schema fields are taken to make tree leaves variable list
     */
    public static void combineVariableLists(List<Map<String, String>> list, long schemaId) {
        List<SchemaFieldEntity> leaves = schemasDao.retrieveAllLeaves(schemaId);
        for (SchemaFieldEntity ent : leaves) {
            boolean isExists = false;
            for (Map<String, String> m : list) {
                if (m.get("uniqueName").equals(ent.getName())) {
                    isExists = true;
                    break;
                }
            }
            if (!isExists) {
                Map<String, String> m = new HashMap<String, String>();
                m.put("uniqueName", ent.getName());
                m.put("fieldType", FieldType.getFieldTypeAsStringById(ent.getIdFieldType()));
                m.put("nodePath", ent.getPath("/"));
                list.add(m);
            }
        }
    }

    /**
     * Parses list of variables for macros in db.
     *
     * @param varList
     * @return
     */
    public static List<Map<String, String>> parseVars(String varList) {
        List<Map<String, String>> list = new ArrayList<Map<String, String>>();
        if (varList == null || varList.isEmpty())
            return list;
        for (String s : varList.split("\n")) {
            if (s.length() == 0)
                continue;
            Map<String, String> m = new HashMap<String, String>();
            String[] arr = s.split(";");
            m.put("uniqueName", arr[0]);
            m.put("fieldType", arr[1]);
            m.put("nodePath", arr[2]);
            list.add(m);
        }
        return list;
    }
}