| 1 |  |   | 
  | 2 |  |   | 
  | 3 |  |   | 
  | 4 |  |   | 
  | 5 |  |   | 
  | 6 |  |   | 
  | 7 |  |   | 
  | 8 |  |   | 
  | 9 |  |   | 
  | 10 |  |   | 
  | 11 |  |   | 
  | 12 |  |   | 
  | 13 |  |   | 
  | 14 |  |   | 
  | 15 |  |   | 
  | 16 |  |  package org.kuali.student.common.ui.client.widgets.rules; | 
  | 17 |  |   | 
  | 18 |  |  import java.util.ArrayList; | 
  | 19 |  |  import java.util.List; | 
  | 20 |  |  import java.util.Stack; | 
  | 21 |  |   | 
  | 22 |  |  import org.kuali.student.common.ui.client.widgets.table.Node; | 
  | 23 |  |  import org.kuali.student.core.statement.dto.StatementInfo; | 
  | 24 |  |  import org.kuali.student.core.statement.dto.StatementOperatorTypeKey; | 
  | 25 |  |   | 
  | 26 |  |  import com.google.gwt.core.client.GWT; | 
  | 27 |  |   | 
  | 28 | 0 |  public class RuleExpressionParser { | 
  | 29 |  |       | 
  | 30 |  |      private String expression; | 
  | 31 |  |      private List<Token> tokenList; | 
  | 32 |  |          | 
  | 33 |  |      private void checkExpressionSet() { | 
  | 34 | 0 |          if (tokenList == null || expression == null) { | 
  | 35 | 0 |              throw new java.lang.IllegalStateException("setExpression must be called first"); | 
  | 36 |  |          } | 
  | 37 | 0 |      } | 
  | 38 |  |   | 
  | 39 |  |      public void checkMissingRCs(List<ReqComponentVO> missingRCs, List<ReqComponentVO> rcs) { | 
  | 40 | 0 |          checkExpressionSet(); | 
  | 41 |  |   | 
  | 42 | 0 |          List<String> conditionValues = new ArrayList<String>();         | 
  | 43 | 0 |          for (Token token : tokenList) { | 
  | 44 | 0 |              if (token.type == Token.Condition) { | 
  | 45 | 0 |                  conditionValues.add(token.value); | 
  | 46 |  |              } | 
  | 47 |  |          } | 
  | 48 |  |   | 
  | 49 | 0 |          if (rcs != null && !rcs.isEmpty()) { | 
  | 50 | 0 |              for (ReqComponentVO rc : rcs) { | 
  | 51 | 0 |                  boolean foundId = false; | 
  | 52 | 0 |                  if (!conditionValues.isEmpty()) { | 
  | 53 | 0 |                      for (String conditionValue : conditionValues) { | 
  | 54 | 0 |                          if (conditionValue != null && conditionValue.equalsIgnoreCase(rc.getGuiReferenceLabelId())) { | 
  | 55 | 0 |                              foundId = true; | 
  | 56 | 0 |                              break; | 
  | 57 |  |                          } | 
  | 58 |  |                      } | 
  | 59 |  |                  } | 
  | 60 | 0 |                  if (!foundId) { | 
  | 61 | 0 |                      missingRCs.add(rc); | 
  | 62 |  |                  } | 
  | 63 | 0 |              } | 
  | 64 |  |          } | 
  | 65 | 0 |      } | 
  | 66 |  |   | 
  | 67 |  |      public boolean validateExpression(List<String> errorMessages, List<ReqComponentVO> validRCs) { | 
  | 68 | 0 |          checkExpressionSet(); | 
  | 69 | 0 |          return doValidateExpression(errorMessages, tokenList, validRCs); | 
  | 70 |  |      }     | 
  | 71 |  |       | 
  | 72 |  |      private boolean doValidateExpression(List<String> errorMessages, final List<Token> tokens, List<ReqComponentVO> validRCs) { | 
  | 73 | 0 |          boolean valid = true; | 
  | 74 | 0 |          List<String> seenConditonValues = new ArrayList<String>(); | 
  | 75 |  |           | 
  | 76 | 0 |          if (tokens.size() == 0) { | 
  | 77 | 0 |              return true; | 
  | 78 |  |          } | 
  | 79 |  |   | 
  | 80 | 0 |          if ((tokens.get(0).type == Token.StartParenthesis  | 
  | 81 |  |                  || tokens.get(0).type == Token.Condition) == false) { | 
  | 82 | 0 |              errorMessages.add("must start with ( or condition"); | 
  | 83 | 0 |              return false; | 
  | 84 |  |          } | 
  | 85 | 0 |          int lastIndex = tokens.size() - 1; | 
  | 86 | 0 |          if ((tokens.get(lastIndex).type == Token.EndParenthesis || tokens.get(lastIndex).type == Token.Condition) == false) { | 
  | 87 | 0 |              errorMessages.add("must end with ) or condition"); | 
  | 88 | 0 |              return false; | 
  | 89 |  |          } | 
  | 90 | 0 |          if (countToken(tokens, Token.StartParenthesis) != countToken(tokens, Token.EndParenthesis)) { | 
  | 91 | 0 |              errorMessages.add("() not in pair"); | 
  | 92 | 0 |              return false; | 
  | 93 |  |          } | 
  | 94 |  |           | 
  | 95 | 0 |          for (int i = 0; i < tokens.size(); i++) { | 
  | 96 | 0 |              Token token = tokens.get(i); | 
  | 97 | 0 |              if (token.type == Token.And) { | 
  | 98 | 0 |                  if (!checkAnd(errorMessages, tokens, i)) { | 
  | 99 | 0 |                      return false; | 
  | 100 |  |                  } | 
  | 101 | 0 |              } else if (token.type == Token.Or) { | 
  | 102 | 0 |                  if (!checkOr(errorMessages, tokens, i)) { | 
  | 103 | 0 |                      return false; | 
  | 104 |  |                  } | 
  | 105 | 0 |              } else if (token.type == Token.StartParenthesis) { | 
  | 106 | 0 |                  if (!checkStartParenthesis(errorMessages, tokens, i)) { | 
  | 107 | 0 |                      return false; | 
  | 108 |  |                  } | 
  | 109 | 0 |              } else if (token.type == Token.EndParenthesis) { | 
  | 110 | 0 |                  if (!checkEndParenthesis(errorMessages, tokens, i)) { | 
  | 111 | 0 |                      return false; | 
  | 112 |  |                  } | 
  | 113 | 0 |              } else if (token.type == Token.Condition) { | 
  | 114 | 0 |                  if (seenConditonValues.contains(token.value)) { | 
  | 115 | 0 |                      errorMessages.add("Condition " + token.value + " is duplicated."); | 
  | 116 | 0 |                      return false; | 
  | 117 |  |                  } else { | 
  | 118 | 0 |                      seenConditonValues.add(token.value); | 
  | 119 |  |                  } | 
  | 120 | 0 |                  if (!checkCondition(errorMessages, tokens, i, validRCs)) { | 
  | 121 | 0 |                      return false; | 
  | 122 |  |                  } | 
  | 123 |  |              } | 
  | 124 |  |          } | 
  | 125 | 0 |          return valid; | 
  | 126 |  |      } | 
  | 127 |  |       | 
  | 128 |  |      private int countToken(List<Token> tokenList, int type) { | 
  | 129 | 0 |          int count = 0; | 
  | 130 | 0 |          for (Token t : tokenList) { | 
  | 131 | 0 |              if (t.type == type) { | 
  | 132 | 0 |                  count++; | 
  | 133 |  |              } | 
  | 134 |  |          } | 
  | 135 | 0 |          return count; | 
  | 136 |  |      } | 
  | 137 |  |   | 
  | 138 |  |      private boolean checkAnd(List<String> errorMessages, List<Token> tokenList, int currentIndex) { | 
  | 139 | 0 |          Token prevToken = (tokenList == null || currentIndex - 1 < 0)? null : | 
  | 140 |  |              tokenList.get(currentIndex - 1); | 
  | 141 | 0 |          Token nextToken = (tokenList == null || currentIndex + 1 >= tokenList.size())? null : | 
  | 142 |  |              tokenList.get(currentIndex + 1); | 
  | 143 | 0 |          boolean validToken = true; | 
  | 144 | 0 |          if (prevToken != null && (prevToken.type == Token.Condition || prevToken.type == Token.EndParenthesis) == false) { | 
  | 145 | 0 |              errorMessages.add("only ) and condition could sit before and"); | 
  | 146 | 0 |              validToken = false; | 
  | 147 |  |          } | 
  | 148 | 0 |          if (nextToken != null && (nextToken.type == Token.Condition || nextToken.type == Token.StartParenthesis) == false) { | 
  | 149 | 0 |              errorMessages.add("only ( and condition could sit after and"); | 
  | 150 | 0 |              validToken = false; | 
  | 151 |  |          } | 
  | 152 | 0 |          return validToken; | 
  | 153 |  |      } | 
  | 154 |  |   | 
  | 155 |  |      private boolean checkOr(List<String> errorMessages, List<Token> tokenList, int currentIndex) { | 
  | 156 | 0 |          Token prevToken = (tokenList == null || currentIndex - 1 < 0)? null : | 
  | 157 |  |              tokenList.get(currentIndex - 1); | 
  | 158 | 0 |          Token nextToken = (tokenList == null || currentIndex + 1 >= tokenList.size())? null : | 
  | 159 |  |              tokenList.get(currentIndex + 1); | 
  | 160 | 0 |          boolean validToken = true; | 
  | 161 | 0 |          if (prevToken != null && (prevToken.type == Token.Condition || prevToken.type == Token.EndParenthesis) == false) { | 
  | 162 | 0 |              errorMessages.add("only ) and condition could sit before or"); | 
  | 163 | 0 |              validToken = false; | 
  | 164 |  |          } | 
  | 165 | 0 |          if (nextToken != null && (nextToken.type == Token.Condition || nextToken.type == Token.StartParenthesis) == false) { | 
  | 166 | 0 |              errorMessages.add("only ( and condition could sit after or"); | 
  | 167 | 0 |              validToken = false; | 
  | 168 |  |          } | 
  | 169 | 0 |          return validToken; | 
  | 170 |  |      } | 
  | 171 |  |   | 
  | 172 |  |      private boolean checkStartParenthesis(List<String> errorMessages, List<Token> tokenList, int currentIndex) { | 
  | 173 | 0 |          Token prevToken = (tokenList == null || currentIndex - 1 < 0)? null : | 
  | 174 |  |              tokenList.get(currentIndex - 1); | 
  | 175 | 0 |          Token nextToken = (tokenList == null || currentIndex + 1 >= tokenList.size())? null : | 
  | 176 |  |              tokenList.get(currentIndex + 1); | 
  | 177 | 0 |          boolean validToken = true; | 
  | 178 | 0 |          if (prevToken != null && (prevToken.type == Token.And || prevToken.type == Token.Or || prevToken.type == Token.StartParenthesis) == false) { | 
  | 179 | 0 |              errorMessages.add("only and, or, ( could sit before ("); | 
  | 180 | 0 |              validToken = false; | 
  | 181 |  |          } | 
  | 182 | 0 |          if (nextToken != null && (nextToken.type == Token.Condition || nextToken.type == Token.StartParenthesis) == false) { | 
  | 183 | 0 |              errorMessages.add("only ( and condition could sit after ("); | 
  | 184 | 0 |              validToken = false; | 
  | 185 |  |          } | 
  | 186 | 0 |          return validToken; | 
  | 187 |  |      } | 
  | 188 |  |   | 
  | 189 |  |      private boolean checkEndParenthesis(List<String> errorMessages, List<Token> tokenList, int currentIndex) { | 
  | 190 | 0 |          Token prevToken = (tokenList == null || currentIndex - 1 < 0)? null : | 
  | 191 |  |              tokenList.get(currentIndex - 1); | 
  | 192 | 0 |          Token nextToken = (tokenList == null || currentIndex + 1 >= tokenList.size())? null : | 
  | 193 |  |              tokenList.get(currentIndex + 1); | 
  | 194 | 0 |          boolean validToken = true; | 
  | 195 | 0 |          if (prevToken != null && (prevToken.type == Token.Condition || prevToken.type == Token.EndParenthesis) == false) { | 
  | 196 | 0 |              errorMessages.add("only condition and ) could sit before )"); | 
  | 197 | 0 |              validToken = false; | 
  | 198 |  |          } | 
  | 199 | 0 |          if (nextToken != null && (nextToken.type == Token.Or || nextToken.type == Token.And || nextToken.type == Token.EndParenthesis) == false) { | 
  | 200 | 0 |              errorMessages.add("only ), and, or could sit after )"); | 
  | 201 | 0 |              validToken = false; | 
  | 202 |  |          } | 
  | 203 | 0 |          return validToken; | 
  | 204 |  |      } | 
  | 205 |  |   | 
  | 206 |  |      private boolean checkCondition(List<String> errorMessages, List<Token> tokenList, int currentIndex, | 
  | 207 |  |              List<ReqComponentVO> validRCs) { | 
  | 208 | 0 |          Token prevToken = (tokenList == null || currentIndex - 1 < 0)? null : | 
  | 209 |  |              tokenList.get(currentIndex - 1); | 
  | 210 | 0 |          Token nextToken = (tokenList == null || currentIndex + 1 >= tokenList.size())? null : | 
  | 211 |  |              tokenList.get(currentIndex + 1); | 
  | 212 | 0 |          boolean validToken = true; | 
  | 213 | 0 |          if (prevToken != null && (prevToken.type == Token.And || prevToken.type == Token.Or || prevToken.type == Token.StartParenthesis) == false) { | 
  | 214 | 0 |              errorMessages.add("only and, or could sit before condition"); | 
  | 215 | 0 |              validToken = false; | 
  | 216 |  |          } | 
  | 217 | 0 |          if (nextToken != null && (nextToken.type == Token.Or || nextToken.type == Token.And || nextToken.type == Token.EndParenthesis) == false) { | 
  | 218 | 0 |              errorMessages.add("only ), and, or could sit after condition"); | 
  | 219 | 0 |              validToken = false; | 
  | 220 |  |          } | 
  | 221 | 0 |          Token conditionToken = tokenList.get(currentIndex); | 
  | 222 | 0 |          String conditionLetter = conditionToken.value; | 
  | 223 | 0 |          boolean validConditonLetter = false; | 
  | 224 | 0 |          if (validRCs != null) { | 
  | 225 | 0 |              for (ReqComponentVO rc : validRCs) { | 
  | 226 | 0 |                  if (rc.getGuiReferenceLabelId() != null && | 
  | 227 |  |                          rc.getGuiReferenceLabelId().equalsIgnoreCase(conditionLetter)) { | 
  | 228 | 0 |                      validConditonLetter = true; | 
  | 229 |  |                  } | 
  | 230 |  |              } | 
  | 231 |  |          } | 
  | 232 | 0 |          if (!validConditonLetter) { | 
  | 233 | 0 |              errorMessages.add(conditionLetter + " is not a valid conditon"); | 
  | 234 | 0 |              validToken = false; | 
  | 235 |  |          } | 
  | 236 | 0 |          return validToken; | 
  | 237 |  |      } | 
  | 238 |  |       | 
  | 239 |  |      public Node parseExpressionIntoTree(String expression, StatementVO statementVO, String statementType) { | 
  | 240 | 0 |          Node tree = null; | 
  | 241 | 0 |          if (expression != null && expression.trim().length() > 0) { | 
  | 242 | 0 |              StatementVO parsedS = parseExpressionIntoStatementVO(expression, statementVO, statementType); | 
  | 243 | 0 |              if (parsedS != null) { | 
  | 244 | 0 |                  tree = parsedS.getTree(); | 
  | 245 |  |              } | 
  | 246 |  |          } | 
  | 247 | 0 |          return tree; | 
  | 248 |  |      } | 
  | 249 |  |       | 
  | 250 |  |      public StatementVO parseExpressionIntoStatementVO(String expression, StatementVO statementVO, String statementType) { | 
  | 251 | 0 |          StatementVO parsedS = null; | 
  | 252 |  |   | 
  | 253 | 0 |          if (expression.trim().isEmpty()) { | 
  | 254 | 0 |              statementVO.clearStatementAndReqComponents(); | 
  | 255 | 0 |              return statementVO; | 
  | 256 |  |          } | 
  | 257 |  |   | 
  | 258 | 0 |          List<ReqComponentVO> rcs = statementVO.getAllReqComponentVOs(); | 
  | 259 |  |          try { | 
  | 260 | 0 |              List<String> tokenValueList = getTokenValue(expression); | 
  | 261 | 0 |              List<Token> tokenList = getTokenList(tokenValueList); | 
  | 262 | 0 |              if (!doValidateExpression(new ArrayList<String>(), tokenList, rcs)) return null; | 
  | 263 | 0 |              List<Node<Token>> nodeList = toNodeList(tokenList); | 
  | 264 | 0 |              List<Node<Token>> rpnList = getRPN(nodeList); | 
  | 265 | 0 |              parsedS = statementVOFromRPN(rpnList, rcs, statementType); | 
  | 266 |  |   | 
  | 267 | 0 |              if (parsedS != null) { | 
  | 268 | 0 |                  parsedS.simplify(); | 
  | 269 |  |              } | 
  | 270 | 0 |          } catch (Exception error) { | 
  | 271 | 0 |              GWT.log("Exception parsing",error); | 
  | 272 | 0 |          } | 
  | 273 | 0 |          return parsedS; | 
  | 274 |  |      } | 
  | 275 |  |       | 
  | 276 |  |      private ReqComponentVO lookupReqComponent(List<ReqComponentVO> rcs, String guiKey) { | 
  | 277 | 0 |          ReqComponentVO result = null; | 
  | 278 | 0 |          if (rcs != null) { | 
  | 279 | 0 |              for (ReqComponentVO rc : rcs) { | 
  | 280 | 0 |                  if (rc.getGuiReferenceLabelId() != null && rc.getGuiReferenceLabelId().equalsIgnoreCase(guiKey)) { | 
  | 281 | 0 |                      result = rc; | 
  | 282 | 0 |                      break; | 
  | 283 |  |                  } | 
  | 284 |  |              } | 
  | 285 |  |          } | 
  | 286 | 0 |          return result; | 
  | 287 |  |      } | 
  | 288 |  |       | 
  | 289 |  |       | 
  | 290 |  |      private StatementVO statementVOFromRPN(List<Node<Token>> rpnList, List<ReqComponentVO> rcs, String statementType) { | 
  | 291 |  |          StatementVO statementVO;         | 
  | 292 |  |   | 
  | 293 |  |           | 
  | 294 | 0 |          if (rpnList.size() == 0) { | 
  | 295 | 0 |              return new StatementVO(); | 
  | 296 |  |          } | 
  | 297 |  |   | 
  | 298 | 0 |          Stack<Node<? extends Token>> conditionStack = new Stack<Node<? extends Token>>(); | 
  | 299 | 0 |          for (Node<Token> node : rpnList) { | 
  | 300 | 0 |              if (node.getUserObject().type == Token.Condition) { | 
  | 301 | 0 |                  ReqComponentVO rc = null; | 
  | 302 | 0 |                  Node<ReqComponentVO> rcNode = null; | 
  | 303 | 0 |                  rc = lookupReqComponent(rcs, node.getUserObject().value); | 
  | 304 | 0 |                  if (rc != null) { | 
  | 305 | 0 |                      rcNode = new Node<ReqComponentVO>(); | 
  | 306 | 0 |                      rcNode.setUserObject(rc); | 
  | 307 |  |                  } | 
  | 308 | 0 |                  conditionStack.push(rcNode); | 
  | 309 | 0 |              } else if (node.getUserObject().type == Token.And || node.getUserObject().type == Token.Or) { | 
  | 310 | 0 |                  StatementVO subS = new StatementVO(); | 
  | 311 | 0 |                  subS.setTokenOperator(true); | 
  | 312 | 0 |                  StatementOperatorTypeKey op = null; | 
  | 313 | 0 |                  if (node.getUserObject().type == Token.And) { | 
  | 314 | 0 |                      op = StatementOperatorTypeKey.AND; | 
  | 315 | 0 |                  } else if (node.getUserObject().type == Token.Or) { | 
  | 316 | 0 |                      op = StatementOperatorTypeKey.OR; | 
  | 317 |  |                  } | 
  | 318 | 0 |                  StatementInfo statementInfo = new StatementInfo(); | 
  | 319 | 0 |                  statementInfo.setOperator(op); | 
  | 320 | 0 |                  statementInfo.setType(statementType); | 
  | 321 | 0 |                  subS.setStatementInfo(statementInfo); | 
  | 322 | 0 |                  Token right = conditionStack.pop().getUserObject(); | 
  | 323 | 0 |                  Token left = conditionStack.pop().getUserObject(); | 
  | 324 | 0 |                  List<ReqComponentVO> nodeRcs = new ArrayList<ReqComponentVO>(); | 
  | 325 | 0 |                  if (left instanceof ReqComponentVO) { | 
  | 326 | 0 |                      nodeRcs.add((ReqComponentVO) left); | 
  | 327 |  |                  } | 
  | 328 | 0 |                  if (right instanceof ReqComponentVO) { | 
  | 329 | 0 |                      nodeRcs.add((ReqComponentVO) right); | 
  | 330 |  |                  } | 
  | 331 |  |                   | 
  | 332 |  |                   | 
  | 333 | 0 |                  if (nodeRcs != null && nodeRcs.size() == 2) { | 
  | 334 | 0 |                      subS.addReqComponentVOs(nodeRcs); | 
  | 335 |  |                  } else { | 
  | 336 | 0 |                      if (left instanceof ReqComponentVO) { | 
  | 337 | 0 |                          subS.addStatementVO(wrapReqComponent(op, (ReqComponentVO)left, statementType)); | 
  | 338 |  |                      } else { | 
  | 339 | 0 |                          subS.addStatementVO((StatementVO)left); | 
  | 340 |  |                      } | 
  | 341 | 0 |                      if (right instanceof ReqComponentVO) { | 
  | 342 | 0 |                          subS.addStatementVO(wrapReqComponent(op, (ReqComponentVO)right, statementType)); | 
  | 343 |  |                      } else { | 
  | 344 | 0 |                          subS.addStatementVO((StatementVO)right); | 
  | 345 |  |                      } | 
  | 346 |  |                  } | 
  | 347 |  |                   | 
  | 348 | 0 |                  Node<StatementVO> nodeS = new Node<StatementVO>(); | 
  | 349 | 0 |                  nodeS.setUserObject(subS); | 
  | 350 | 0 |                  conditionStack.push(nodeS); | 
  | 351 | 0 |              } | 
  | 352 |  |          } | 
  | 353 |  |           | 
  | 354 | 0 |          if (conditionStack.peek().getUserObject() instanceof ReqComponentVO) { | 
  | 355 | 0 |              statementVO = wrapReqComponent(StatementOperatorTypeKey.AND, | 
  | 356 |  |                      (ReqComponentVO)conditionStack.pop().getUserObject(), statementType); | 
  | 357 |  |          } else { | 
  | 358 | 0 |              statementVO = (StatementVO)conditionStack.pop().getUserObject(); | 
  | 359 |  |          } | 
  | 360 | 0 |          statementVO.getStatementInfo().setType(statementType); | 
  | 361 |  |   | 
  | 362 | 0 |          return statementVO; | 
  | 363 |  |      } | 
  | 364 |  |       | 
  | 365 |  |      private StatementVO wrapReqComponent(StatementOperatorTypeKey op, ReqComponentVO rc, String statementType) { | 
  | 366 | 0 |          StatementVO wrapS = new StatementVO(); | 
  | 367 | 0 |          StatementInfo wrapStatementInfo = new StatementInfo(); | 
  | 368 | 0 |          wrapStatementInfo.setOperator(op); | 
  | 369 | 0 |          wrapStatementInfo.setType(statementType); | 
  | 370 | 0 |          wrapS.setStatementInfo(wrapStatementInfo); | 
  | 371 | 0 |          wrapS.addReqComponentVO(rc); | 
  | 372 | 0 |          return wrapS; | 
  | 373 |  |      } | 
  | 374 |  |       | 
  | 375 |  |       | 
  | 376 |  |   | 
  | 377 |  |   | 
  | 378 |  |   | 
  | 379 |  |   | 
  | 380 |  |   | 
  | 381 |  |   | 
  | 382 |  |      private List<Node<Token>> getRPN(List<Node<Token>> nodeList) { | 
  | 383 | 0 |          List<Node<Token>> rpnList = new ArrayList<Node<Token>>(); | 
  | 384 | 0 |          Stack<Node<Token>> operatorStack = new Stack<Node<Token>>(); | 
  | 385 |  |   | 
  | 386 | 0 |          for (Node<Token> node : nodeList) { | 
  | 387 | 0 |              if (node.getUserObject().type == Token.Condition) { | 
  | 388 | 0 |                  rpnList.add(node); | 
  | 389 |  |   | 
  | 390 | 0 |              } else if (node.getUserObject().type == Token.And) { | 
  | 391 | 0 |                  operatorStack.push(node); | 
  | 392 | 0 |              } else if (node.getUserObject().type == Token.StartParenthesis) { | 
  | 393 | 0 |                  operatorStack.push(node); | 
  | 394 | 0 |              } else if (node.getUserObject().type == Token.Or) { | 
  | 395 |  |   | 
  | 396 | 0 |                  if (operatorStack.isEmpty() == false && operatorStack.peek().getUserObject().type == Token.And) { | 
  | 397 |  |                      do { | 
  | 398 | 0 |                          rpnList.add(operatorStack.pop()); | 
  | 399 | 0 |                      } while (operatorStack.isEmpty() == false && operatorStack.peek().getUserObject().type == Token.And); | 
  | 400 |  |                  } | 
  | 401 |  |   | 
  | 402 | 0 |                  operatorStack.push(node); | 
  | 403 | 0 |              } else if (node.getUserObject().type == Token.EndParenthesis) { | 
  | 404 | 0 |                  while (operatorStack.peek().getUserObject().type != Token.StartParenthesis) { | 
  | 405 | 0 |                      rpnList.add(operatorStack.pop()); | 
  | 406 |  |                  } | 
  | 407 | 0 |                  operatorStack.pop(); | 
  | 408 |  |              } | 
  | 409 |  |          } | 
  | 410 | 0 |          if (operatorStack.isEmpty() == false) { | 
  | 411 |  |              do { | 
  | 412 | 0 |                  rpnList.add(operatorStack.pop()); | 
  | 413 | 0 |              } while (operatorStack.isEmpty() == false); | 
  | 414 |  |          } | 
  | 415 | 0 |          return rpnList; | 
  | 416 |  |      } | 
  | 417 |  |       | 
  | 418 |  |      private List<Node<Token>> toNodeList(List<Token> tokenList) { | 
  | 419 | 0 |          List<Node<Token>> nodeList = new ArrayList<Node<Token>>(); | 
  | 420 | 0 |          for (Token token : tokenList) { | 
  | 421 | 0 |              Node<Token> node = new Node<Token>(); | 
  | 422 | 0 |              node.setUserObject(token); | 
  | 423 | 0 |              nodeList.add(node); | 
  | 424 | 0 |          } | 
  | 425 | 0 |          return nodeList; | 
  | 426 |  |      } | 
  | 427 |  |       | 
  | 428 |  |      private List<Token> getTokenList(List<String> tokenValueList) { | 
  | 429 | 0 |          List<Token> tokenList = new ArrayList<Token>(); | 
  | 430 | 0 |          for (String value : tokenValueList) { | 
  | 431 | 0 |              if (value.isEmpty()) { | 
  | 432 | 0 |                  continue; | 
  | 433 |  |              } | 
  | 434 | 0 |              if ("(".equals(value)) { | 
  | 435 | 0 |                  Token t = new Token(); | 
  | 436 | 0 |                  t.type = Token.StartParenthesis; | 
  | 437 | 0 |                  tokenList.add(t); | 
  | 438 | 0 |              } else if (")".equals(value)) { | 
  | 439 | 0 |                  Token t = new Token(); | 
  | 440 | 0 |                  t.type = Token.EndParenthesis; | 
  | 441 | 0 |                  tokenList.add(t); | 
  | 442 |  |   | 
  | 443 | 0 |              } else if ("and".equals(value)) { | 
  | 444 | 0 |                  Token t = new Token(); | 
  | 445 | 0 |                  t.type = Token.And; | 
  | 446 | 0 |                  tokenList.add(t); | 
  | 447 |  |   | 
  | 448 | 0 |              } else if ("or".equals(value)) { | 
  | 449 | 0 |                  Token t = new Token(); | 
  | 450 | 0 |                  t.type = Token.Or; | 
  | 451 | 0 |                  tokenList.add(t); | 
  | 452 |  |   | 
  | 453 | 0 |              } else { | 
  | 454 | 0 |                  Token t = new Token(); | 
  | 455 | 0 |                  t.type = Token.Condition; | 
  | 456 | 0 |                  t.value = value; | 
  | 457 | 0 |                  tokenList.add(t); | 
  | 458 |  |   | 
  | 459 | 0 |              } | 
  | 460 |  |          } | 
  | 461 | 0 |          return tokenList; | 
  | 462 |  |      } | 
  | 463 |  |       | 
  | 464 |  |      private List<String> getTokenValue(String expression) { | 
  | 465 | 0 |          expression = expression.toLowerCase(); | 
  | 466 | 0 |          List<String> tokenValueList = new ArrayList<String>(); | 
  | 467 | 0 |          StringBuffer tokenValue = new StringBuffer(); | 
  | 468 | 0 |          for (int i = 0; i < expression.length(); i++) { | 
  | 469 |  |   | 
  | 470 | 0 |              char ch = expression.charAt(i); | 
  | 471 | 0 |              if (ch == ' ') { | 
  | 472 | 0 |                  tokenValueList.add(tokenValue.toString()); | 
  | 473 | 0 |                  tokenValue = new StringBuffer(); | 
  | 474 | 0 |              } else if (ch == '(' || ch == ')') { | 
  | 475 | 0 |                  tokenValueList.add(tokenValue.toString()); | 
  | 476 | 0 |                  tokenValue = new StringBuffer(); | 
  | 477 | 0 |                  tokenValueList.add(String.valueOf(ch)); | 
  | 478 |  |              } else { | 
  | 479 | 0 |                  tokenValue.append(ch); | 
  | 480 |  |              } | 
  | 481 |  |          } | 
  | 482 | 0 |          tokenValueList.add(tokenValue.toString()); | 
  | 483 | 0 |          return tokenValueList; | 
  | 484 |  |      } | 
  | 485 |  |   | 
  | 486 |  |      public void setExpression(String expression) { | 
  | 487 | 0 |          this.expression = expression; | 
  | 488 | 0 |          List<String> tokenValueList = getTokenValue(expression); | 
  | 489 | 0 |          this.tokenList = getTokenList(tokenValueList); | 
  | 490 | 0 |      } | 
  | 491 |  |   | 
  | 492 |  |      public String getExpression() { | 
  | 493 | 0 |          return expression; | 
  | 494 |  |      }     | 
  | 495 |  |           | 
  | 496 |  |  } |