com.autobizlogic.abl.rule.JexlExpressionAnalyzer.java Source code

Java tutorial

Introduction

Here is the source code for com.autobizlogic.abl.rule.JexlExpressionAnalyzer.java

Source

package com.autobizlogic.abl.rule;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Vector;

import org.apache.commons.jexl2.Expression;
import org.apache.commons.jexl2.ExpressionImpl;
import org.apache.commons.jexl2.JexlEngine;
import org.apache.commons.jexl2.JexlException;

import com.autobizlogic.abl.logic.analysis.ClassDependency;
import com.autobizlogic.abl.logic.analysis.LogicAnalysisManager;
import com.autobizlogic.abl.logic.analysis.PropertyDependency;
import com.autobizlogic.abl.metadata.MetaEntity;
import com.autobizlogic.abl.metadata.MetaModel;
import com.autobizlogic.abl.metadata.MetaProperty;
import com.autobizlogic.abl.metadata.MetaRole;

/**
 * Figure out the dependencies from a Jexl expression.
 * This depends on a new API in Jexl 2.1, namely JexlEngine.getVariables(Script).
 */
public class JexlExpressionAnalyzer {

    /**
     * Analyze the given expression and return all the dependencies found in it.
     * @param expression The expression, e.g. <code>customer.balance != total</code>
     * @param metaEntity The meta entity from which the expression starts
     * @param methodName The name of the method that defines the logic, for better error reporting.
     * @return The dependencies
     */
    public static Map<ClassDependency, List<PropertyDependency>> getDependenciesFromExpression(String expression,
            MetaEntity metaEntity, String methodName) {

        Map<ClassDependency, List<PropertyDependency>> dependencies = new HashMap<ClassDependency, List<PropertyDependency>>();

        expression = expression.replaceAll("([^=!<>])=([^=])", "$1==$2");

        JexlEngine jexlEngine = new JexlEngine();
        Expression expr = null;
        try {
            expr = jexlEngine.createExpression(expression);
        } catch (JexlException ex) {
            throw new RuntimeException("Logic method " + methodName + " for " + metaEntity.getEntityName()
                    + " has expression (" + expression + ") which has invalid syntax.", ex);
        }
        Set<List<String>> variableSet = jexlEngine.getVariables((ExpressionImpl) expr);

        for (List<String> var : variableSet) {
            if (var.size() > 2)
                throw new RuntimeException("Logic method " + methodName + " for " + metaEntity.getEntityName()
                        + " has expression (" + expression
                        + ") which contains an invalid path -- only one dereference allowed per term.");

            if (var.size() == 1) {
                String attName = var.get(0);

                MetaProperty metaProp = metaEntity.getMetaProperty(attName);
                if (metaProp == null)
                    throw new RuntimeException("Logic method " + methodName + " for " + metaEntity.getEntityName()
                            + " has expression (" + expression + ") which refers to property " + attName
                            + ", which does not seem to exist.");
                addDependency(dependencies, metaEntity.getEntityName(), attName, null, metaEntity.getMetaModel());
            } else if (var.size() == 2) {
                String roleName = var.get(0);
                MetaRole metaRole = metaEntity.getMetaRole(roleName);
                if (metaRole == null)
                    throw new RuntimeException("Logic method " + methodName + " for " + metaEntity.getEntityName()
                            + " has expression (" + expression + ") which refers to relationship " + roleName
                            + ", which does not seem to exist.");
                if (metaRole.isCollection())
                    throw new RuntimeException("Logic method " + methodName + " for " + metaEntity.getEntityName()
                            + " has expression (" + expression + ") which refers to relationship " + roleName
                            + " which is a collection.");

                MetaEntity parentEntity = metaRole.getOtherMetaEntity();
                String attName = var.get(1);
                MetaProperty metaProp = parentEntity.getMetaProperty(attName);
                if (metaProp == null)
                    throw new RuntimeException("Logic method " + methodName + " for " + metaEntity.getEntityName()
                            + " has expression (" + expression + ") which refers to attribute " + attName
                            + " which does not exist.");
                //            if ( ! (metaProp instanceof MetaAttribute))
                //               throw new RuntimeException("Logic method " + methodName + " for " + 
                //                     metaEntity.getEntityName() + " has expression (" + expression + 
                //                     ") which refers to property " + attName + 
                //                     " which is an entity or collection, and not an attribute.");
                addDependency(dependencies, parentEntity.getEntityName(), attName, roleName,
                        metaEntity.getMetaModel());
            }
        }

        return dependencies;
    }

    /**
     * Add a dependency to a Map of them.
     * @param dependencies The collection of dependencies to add to
     * @param className The name of the class
     * @param attributeName The name of the attribute
     * @param roleName The name of the role (if any)
     * @param metaModel The meta model in which this all happens
     */
    private static void addDependency(Map<ClassDependency, List<PropertyDependency>> dependencies, String className,
            String attributeName, String roleName, MetaModel metaModel) {

        LogicAnalysisManager lam = LogicAnalysisManager.getInstance(metaModel);
        ClassDependency clsDep = lam.getDependencyForClass(className);
        List<PropertyDependency> propDeps = dependencies.get(clsDep);
        if (propDeps == null) {
            propDeps = new Vector<PropertyDependency>();
            dependencies.put(clsDep, propDeps);
        }
        PropertyDependency propDep = clsDep.getOrCreatePropertyDependency(attributeName, roleName);
        if (!propDeps.contains(propDep))
            propDeps.add(propDep);
    }
}

/*
 * The contents of this file are subject to the Automated Business Logic Public License Version 1.0 (the "License"),
 * which is derived from the Mozilla Public License version 1.1. You may not use this file except in compliance with the License. 
 * You may obtain a copy of the License at http://www.automatedbusinesslogic.com/license/public-license
 *
 * Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, 
 * either express or implied. See the License for the specific language governing rights and limitations under the License.
 */