Package org.broadleafcommerce.openadmin.web.rulebuilder.grouping

Source Code of org.broadleafcommerce.openadmin.web.rulebuilder.grouping.GroupingTranslator

/*
* #%L
* BroadleafCommerce Open Admin Platform
* %%
* Copyright (C) 2009 - 2013 Broadleaf Commerce
* %%
* 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.
* #L%
*/
package org.broadleafcommerce.openadmin.web.rulebuilder.grouping;

import org.broadleafcommerce.openadmin.web.rulebuilder.BLCOperator;
import org.broadleafcommerce.openadmin.web.rulebuilder.MVELTranslationException;

import java.util.Stack;

/**
* @author jfischer
* @author Elbert Bautista (elbertbautista)
*/
public class GroupingTranslator {
    public static final String GROUPSTARTCHAR = "(";
    public static final String GROUPENDCHAR = ")";
    public static final String STATEMENTENDCHAR = ";";
    public static final String SPACECHAR = " ";

    public Group createGroups(String mvel) throws MVELTranslationException {
        mvel = stripWhiteSpace(mvel);
        String[] tokens = mvel.trim().split(STATEMENTENDCHAR);
        if (tokens.length > 1) {
            throw new MVELTranslationException(MVELTranslationException.INCOMPATIBLE_RULE, "mvel expressions must resolve to a boolean result. " +
                    "More than one terminated statement has been detected, which does not cumulatively result " +
                    "in a single boolean. Multiple phrases should be strung together into a single expression using " +
                    "standard operators.");
        }
        Group topGroup = new Group();
        topGroup.setIsTopGroup(true);
        parseGroups(topGroup, tokens[0]);

        return topGroup;
    }

    protected int findGroupStart(String segment, int startPos) {
        int startIndex = -1;
        boolean eof = false;
        while (!eof) {
            startIndex = segment.indexOf(GROUPSTARTCHAR, startPos);
            if (startIndex <= 0) {
                eof = true;
                continue;
            }
            char preChar = segment.charAt(startIndex-1);
            if (preChar == '!' || preChar == '&' || preChar == '|') {
                eof = true;
                continue;
            }
            startPos = startIndex + 1;
        }
        return startIndex;
    }

    protected int findGroupEnd(String segment, int subgroupStartIndex) throws MVELTranslationException {
        Stack<Integer> leftParenPos = new Stack<Integer>();
        char[] characters = segment.toCharArray();
        for (int j=subgroupStartIndex;j<characters.length;j++) {
            if (characters[j]=='(') {
                leftParenPos.push(j);
                continue;
            }
            if (characters[j]==')') {
                leftParenPos.pop();
                if(leftParenPos.isEmpty()) {
                    return j + 1;
                }
            }
        }
        throw new MVELTranslationException(MVELTranslationException.INCOMPATIBLE_RULE, "Unable to find an end parenthesis for the group started at (" +
                segment.substring(subgroupStartIndex) + ")");
    }

    protected String stripWhiteSpace(String mvel) {
        return mvel.replaceAll("[\\t\\n\\r]", "");
    }

    protected void parseGroups(Group myGroup, String segment) throws MVELTranslationException {
        boolean eol = false;
        int startPos = 0;
        while (!eol) {
            int subgroupStartIndex = -1;
            boolean isNegation = false;

            subgroupStartIndex = findGroupStart(segment, startPos);
            if (subgroupStartIndex == startPos || subgroupStartIndex == startPos + 1) {
                Group subGroup = new Group();
                myGroup.getSubGroups().add(subGroup);
                int subgroupEndIndex = findGroupEnd(segment, subgroupStartIndex);
                if (subgroupStartIndex > 0 && segment.charAt(subgroupStartIndex - 1) == '!') {
                    if (myGroup.getIsTopGroup()) {
                        //This is a NOT specified at the topmost level
                        myGroup.setOperatorType(BLCOperator.NOT);
                    } else {
                        //This is a NOT specified on a sub group
                        subGroup.setOperatorType(BLCOperator.NOT);
                    }
                }
                parseGroups(subGroup, segment.substring(subgroupStartIndex+1, subgroupEndIndex-1).trim());
                startPos = subgroupEndIndex;
                if (startPos == segment.length()) {
                    eol = true;
                } else {
                    boolean isAnd = false;
                    boolean isOr = false;
                    if (segment.charAt(startPos) == '&') {
                        isAnd = true;
                    } else if (segment.charAt(startPos) == '|') {
                        isOr = true;
                    }
                    if (myGroup.getOperatorType() == null) {
                        setGroupOperator(segment, myGroup, isAnd, isOr, false);
                    }
                    if (isAnd || isOr) {
                        startPos += 2;
                    }
                }
                continue;
            } else {
                if (subgroupStartIndex < 0) {
                    compilePhrases(segment.substring(startPos, segment.length()).trim(), myGroup, isNegation);
                    eol = true;
                    continue;
                }
                String temp = segment.substring(startPos, subgroupStartIndex);
                compilePhrases(temp.trim(), myGroup, isNegation);
                startPos = subgroupStartIndex;
                continue;
            }
        }
    }

    protected void compilePhrases(String segment, Group myGroup, boolean isNegation) throws MVELTranslationException {
        if (segment.trim().length() == 0) {
            return;
        }
        String[] andTokens = segment.split("&&");
        String[] orTokens = segment.split("\\|\\|");
        if (andTokens.length > 1 && orTokens.length > 1) {
            throw new MVELTranslationException(MVELTranslationException.INCOMPATIBLE_RULE, "Segments that mix logical operators are not compatible with " +
                    "the rules builder: (" + segment + ")");
        }
        boolean isAnd = false;
        boolean isOr = false;
        boolean isNot = false;
        if (andTokens.length > 1 || segment.indexOf("&&") >= 0) {
            isAnd = true;
        } else if (orTokens.length > 1 || segment.indexOf("||") >= 0) {
            isOr = true;
        }
        if (isAnd && isNegation) {
            isNot = true;
        }
        if (!isAnd && !isOr && !isNot) {
            isAnd = true;
        }
        setGroupOperator(segment, myGroup, isAnd, isOr, isNot);
        String[] tokens;
        if (isAnd || isNot) {
            tokens = andTokens;
        } else {
            tokens = orTokens;
        }
        for (String token : tokens) {
            if (token.length() > 0) {
                myGroup.getPhrases().add(token);
            }
        }
    }

    protected void setGroupOperator(String segment, Group myGroup, boolean isAnd, boolean isOr, boolean isNot)
            throws MVELTranslationException {
        if (myGroup.getOperatorType() == null) {
            if (isAnd) {
                myGroup.setOperatorType(BLCOperator.AND);
            } else if (isOr) {
                myGroup.setOperatorType(BLCOperator.OR);
            } else if (isNot) {
                myGroup.setOperatorType(BLCOperator.NOT);
            }
        } else {
            if (
                    (isOr && !myGroup.getOperatorType().toString().equals(BLCOperator.OR.toString()))
                    ) {
                throw new MVELTranslationException(MVELTranslationException.INCOMPATIBLE_RULE, "Segment logical operator is not compatible with the group " +
                        "logical operator: (" + segment + ")");
            }
        }
    }

}
TOP

Related Classes of org.broadleafcommerce.openadmin.web.rulebuilder.grouping.GroupingTranslator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.