1 /*
2  * Licensed under the Apache License, Version 2.0 (the "License");
3  * you may not use this file except in compliance with the License.
4  * You may obtain a copy of the License at
5  *
6  * http://www.apache.org/licenses/LICENSE-2.0
7  *
8  * Unless required by applicable law or agreed to in writing, software
9  * distributed under the License is distributed on an "AS IS" BASIS,
10 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 * See the License for the specific language governing permissions and
12 * limitations under the License.
13 */
14package org.tp23.antinstaller.runtime.logic;
15
16import java.util.Arrays;
17import java.util.Comparator;
18import java.util.HashMap;
19import java.util.Map;
20
21import org.tp23.antinstaller.input.ResultContainer;
22import org.tp23.antinstaller.runtime.ConfigurationException;
23
24/**
25 * @author mwilson
26 * @version $Id: ExpressionBuilder.java,v 1.2 2006/12/21 00:03:18 teknopaul Exp $
27 * @since 0.7.4 patch 2
28 */
29public class ExpressionBuilder {
30    private static final int GROUPING_START_OPERATOR = '(';
31
32    private static final int GROUPING_END_OPERATOR = ')';
33
34    private static final ValuesTest[] testValueConditions = { 
35        new EndsWithTest(), 
36        new EqualsTest(), 
37        new GreaterThanOrEqualsTest(),
38        new LessThanOrEqualsTest(), 
39        new NotEqualsTest(), 
40        new StartsWithTest() 
41    };
42
43    private static final LogicalTest[] testLogicalConditions = { 
44        new LogicalAndTest(), 
45        new LogicalOrTest() 
46    };
47
48    private static final SingleExpressionTest SINGLE_EXPRESSION_TEST = new SingleExpressionTest();
49
50    private static Map tokenMap = new HashMap();
51
52    private static String[] valueTokens;
53
54    private static String[] logicalTokens;
55
56    static {
57        for (int i = 0; i < testValueConditions.length; i++) {
58            String[] tmpTokens = testValueConditions[i].getTestTokens();
59            for (int j = 0; j < tmpTokens.length; j++) {
60                tokenMap.put(tmpTokens[j], testValueConditions[i]);
61            }
62        }
63
64        valueTokens = new String[tokenMap.size()];
65        int index = 0;
66        for (int i = 0; i < testValueConditions.length; i++) {
67            String[] tmpTokens = testValueConditions[i].getTestTokens();
68            for (int j = 0; j < tmpTokens.length; j++) {
69                valueTokens[index++] = tmpTokens[j];
70            }
71        }
72
73        Comparator lengthComparator = new StringLengthComparator();
74
75        //Have to sort so that longest test operator is checked for first
76        Arrays.sort(valueTokens, lengthComparator);
77
78        index = 0;
79        final int mapInitialSize = tokenMap.size();
80
81        for (int i = 0; i < testLogicalConditions.length; i++) {
82            String[] tmpTokens = testLogicalConditions[i].getTestTokens();
83            for (int j = 0; j < tmpTokens.length; j++) {
84                tokenMap.put(tmpTokens[j], testLogicalConditions[i]);
85            }
86        }
87
88        logicalTokens = new String[tokenMap.size() - mapInitialSize];
89        for (int i = 0; i < testLogicalConditions.length; i++) {
90            String[] tmpTokens = testLogicalConditions[i].getTestTokens();
91            for (int j = 0; j < tmpTokens.length; j++) {
92                logicalTokens[index++] = tmpTokens[j];
93            }
94        }
95
96        Arrays.sort(logicalTokens, lengthComparator);
97
98    }
99
00    public static Expression parseLogicalExpressions(ResultContainer container, String exprStr) throws ConfigurationException {
01        int startIndex = skipWhiteSpace(exprStr, 0);
02        int index = exprStr.indexOf(GROUPING_START_OPERATOR, startIndex);
03
04        if (index == -1) {
05            return getSimpleExpression(container, exprStr.substring(startIndex));
06        }
07
08        if (index != 0) {
09            throw new ConfigurationException("Illegal ifProperty value: If present, grouping operator " + GROUPING_START_OPERATOR
10                    + " must be at start of property string");
11        }
12
13        ++startIndex; //Skip over grouping operator
14
15        int endIndex = exprStr.indexOf(GROUPING_END_OPERATOR, startIndex);
16
17        if (endIndex == -1) {
18            throw new ConfigurationException("Missing closing grouping bracket " + GROUPING_END_OPERATOR + " in expression " + exprStr);
19        }
20
21        //Check that this isn't an attempt tu use nested logical tests - not supported
22        int tstIndex = exprStr.indexOf(GROUPING_START_OPERATOR, startIndex);
23        if ((tstIndex != -1) && (tstIndex < endIndex)) {
24            throw new ConfigurationException("Nesting of logical operations is not supported: " + exprStr);
25        }
26
27        try {
28            Expression expr1 = parseLogicalExpressions(container, exprStr.substring(startIndex, endIndex));
29
30            LogicalTest test = null;
31
32            startIndex = endIndex + 1;
33
34            //Look for logical operator token
35            String logicalToken = getLogicalToken(exprStr, startIndex);
36
37            for (int i = 0; i < logicalTokens.length; i++) {
38
39                if (logicalTokens[i].compareTo(logicalToken) == 0) {
40                    test = (LogicalTest) tokenMap.get(logicalTokens[i]);
41                    index = exprStr.indexOf(logicalTokens[i], startIndex);
42                    startIndex = index + logicalTokens[i].length();
43                    break;
44                }
45            }
46
47            if (test == null) {
48                return new CompoundExpression(expr1, SINGLE_EXPRESSION_TEST, null);
49            } else {
50                startIndex = skipWhiteSpace(exprStr, startIndex);
51                String expr2Str = exprStr.substring(startIndex, exprStr.length());
52                return new CompoundExpression(expr1, test, parseLogicalExpressions(container, expr2Str));
53
54            }
55        } catch (Exception e) {
56            throw new ConfigurationException("Invalid ifProperty expression");
57        }
58    }
59
60    private static Expression getSimpleExpression(ResultContainer resultContainer, String exprStr) throws ConfigurationException {
61        try {
62            int index = -1;
63            int i;
64
65            for (i = 0; i < valueTokens.length; i++) {
66                index = exprStr.indexOf(valueTokens[i]);
67
68                if (index != -1) {
69                    break;
70                }
71            }
72
73            return new SimpleExpression(resultContainer, exprStr.substring(0, index), (ValuesTest) tokenMap.get(valueTokens[i]), exprStr
74                    .substring(index + valueTokens[i].length()));
75        } catch (Exception e) { // can be StringIndexOutOfBoundsException - PH
76            throw new ConfigurationException("Invalid ifProperty expression");
77        }
78    }
79
80    private static int skipWhiteSpace(final String str, final int startIndex) {
81        final int strLen = str.length();
82        int index = startIndex;
83
84        while (index < strLen) {
85            if ((str.charAt(index) != ' ') && (str.charAt(index) != '\t')) {
86                break;
87            }
88
89            ++index;
90        }
91
92        return index;
93    }
94
95    private static String getLogicalToken(final String str, final int startIndex) {
96        final int strLen = str.length();
97        int tokenStart = skipWhiteSpace(str, startIndex);
98        int endIndex = tokenStart;
99
00        while (endIndex < strLen) {
01            int chr = str.charAt(endIndex);
02            if ((chr == ' ') || (chr == '\t') || (chr == GROUPING_START_OPERATOR)) {
03                break;
04            }
05
06            ++endIndex;
07        }
08
09        return str.substring(tokenStart, endIndex);
10    }
11}
12