View Javadoc
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   *
14   */
15  package org.esigate.vars;
16  
17  import java.util.ArrayList;
18  import java.util.regex.Matcher;
19  import java.util.regex.Pattern;
20  
21  /**
22   * Support for ESI expressions.
23   * 
24   * @author Alexis Thaveau
25   * @author Nicolas Richeton
26   * 
27   */
28  public final class Operations {
29  
30      private Operations() {
31  
32      }
33  
34      private final static Pattern AKAMAI_EXISTS_PATTERN = Pattern.compile("\\$exists\\((.*?)\\)");
35  
36      private static boolean executeOperation(String op) {
37  
38          int i;
39          Double dop1, dop2;
40          String op1, op2;
41  
42          try {
43              if (op.contains("==")) {
44                  i = op.indexOf("==");
45                  op1 = VarUtils.removeSimpleQuotes(op.substring(0, i));
46                  op2 = VarUtils.removeSimpleQuotes(op.substring(i + 2));
47  
48                  dop1 = getOperandAsNumeric(op1);
49                  dop2 = getOperandAsNumeric(op2);
50                  if (dop1 != null && dop2 != null) {
51                      return dop1.equals(dop2);
52                  }
53  
54                  return op1.equals(op2);
55  
56              } else if (op.contains("!=")) {
57                  i = op.indexOf("!=");
58                  op1 = VarUtils.removeSimpleQuotes(op.substring(0, i));
59                  op2 = VarUtils.removeSimpleQuotes(op.substring(i + 2));
60  
61                  dop1 = getOperandAsNumeric(op1);
62                  dop2 = getOperandAsNumeric(op2);
63                  if (dop1 != null && dop2 != null) {
64                      return !dop1.equals(dop2);
65                  }
66  
67                  return !op1.equals(op2);
68  
69              } else if (op.contains(">=")) {
70                  i = op.indexOf(">=");
71                  op1 = VarUtils.removeSimpleQuotes(op.substring(0, i));
72                  op2 = VarUtils.removeSimpleQuotes(op.substring(i + 2));
73  
74                  dop1 = getOperandAsNumeric(op1);
75                  dop2 = getOperandAsNumeric(op2);
76                  if (dop1 != null && dop2 != null) {
77                      return dop1 >= dop2;
78                  }
79                  int cmp = op1.compareTo(op2);
80                  return cmp >= 0;
81  
82              } else if (op.contains("<=")) {
83                  i = op.indexOf("<=");
84                  op1 = VarUtils.removeSimpleQuotes(op.substring(0, i));
85                  op2 = VarUtils.removeSimpleQuotes(op.substring(i + 2));
86  
87                  dop1 = getOperandAsNumeric(op1);
88                  dop2 = getOperandAsNumeric(op2);
89                  if (dop1 != null && dop2 != null) {
90                      return dop1 <= dop2;
91                  }
92  
93                  int cmp = op1.compareTo(op2);
94                  return cmp <= 0;
95  
96              } else if (op.contains(">")) {
97                  i = op.indexOf(">");
98                  op1 = VarUtils.removeSimpleQuotes(op.substring(0, i));
99                  op2 = VarUtils.removeSimpleQuotes(op.substring(i + 1));
100 
101                 dop1 = getOperandAsNumeric(op1);
102                 dop2 = getOperandAsNumeric(op2);
103                 if (dop1 != null && dop2 != null) {
104                     return dop1 > dop2;
105                 }
106 
107                 int cmp = op1.compareTo(op2);
108                 return cmp > 0;
109             } else if (op.contains("<")) {
110                 i = op.indexOf("<");
111                 op1 = VarUtils.removeSimpleQuotes(op.substring(0, i));
112                 op2 = VarUtils.removeSimpleQuotes(op.substring(i + 1));
113 
114                 dop1 = getOperandAsNumeric(op1);
115                 dop2 = getOperandAsNumeric(op2);
116                 if (dop1 != null && dop2 != null) {
117                     return dop1 < dop2;
118                 }
119 
120                 int cmp = op1.compareTo(op2);
121                 return cmp < 0;
122             }
123         } catch (Exception e) {
124             return false;
125         }
126 
127         return false;
128     }
129 
130     private static boolean executeOperations(ArrayList<String> operands, ArrayList<String> operations) {
131         boolean res;
132         ArrayList<Boolean> results = new ArrayList<>();
133 
134         try {
135             for (String op : operands) {
136                 results.add(executeOperation(op));
137             }
138 
139             if (results.size() == 1) {
140                 if (operations.size() == 1 && operations.get(0).equals("!")) {
141                     return !results.get(0);
142                 } else {
143                     return results.get(0);
144                 }
145             }
146 
147             int i = 1;
148             res = results.get(0);
149             for (String op : operations) {
150                 if (op.equals("&")) {
151                     res = res && results.get(i);
152                 } else if (op.equals("|")) {
153                     res = res || results.get(i);
154                 } else {
155                     res = false;
156                 }
157                 i++;
158             }
159         } catch (Exception e) {
160             return false;
161         }
162 
163         return res;
164     }
165 
166     /**
167      * Get an operand as a numeric type.
168      * 
169      * @param op
170      *            operand as String
171      * @return Double value or null if op is not numeric
172      */
173     private static Double getOperandAsNumeric(String op) {
174         Double d = null;
175         try {
176             d = Double.valueOf(op);
177         } catch (Exception e) {
178             // Null is returned if not numeric.
179         }
180         return d;
181     }
182 
183     public static boolean processOperators(String test) {
184 
185         if (test == null || test.equals("") || test.contains("$exists()") || test.contains("$exists('')")) {
186             return false;
187         }
188 
189         ArrayList<String> operands = new ArrayList<>();
190         ArrayList<String> operations = new ArrayList<>();
191 
192         Matcher existsMatcher = AKAMAI_EXISTS_PATTERN.matcher(test);
193 
194         while (existsMatcher.find()) {
195             String group = existsMatcher.group();
196             String existsValue = group.substring(8, group.length() - 1);
197 
198             test = test.replace(group, existsValue + " != \"\"");
199         }
200 
201         String s = test.replaceAll(" ", "");
202         if (s.startsWith("!")) {
203             operations.add("!");
204         }
205 
206         if (s.indexOf('(') == -1) {
207             s = "(" + s + ")";
208         }
209 
210         // allocate (...)
211         try {
212             while (s.length() > 0) {
213                 int sbIndex = s.indexOf(')');
214                 operands.add(s.substring(s.indexOf('(') + 1, sbIndex));
215                 if (s.length() > sbIndex + 1) {
216                     String oper = s.substring(sbIndex + 1, s.substring(sbIndex).indexOf('(') + sbIndex);
217                     operations.add(oper);
218                     s = s.substring(sbIndex + 2);
219                 } else {
220                     s = "";
221                 }
222 
223             }
224         } catch (Exception e) {
225             return false;
226         }
227 
228         return executeOperations(operands, operations);
229     }
230 
231 }