1 7 package com.jofti.parser; 8 9 import java.util.ArrayList ; 10 import java.util.Comparator ; 11 import java.util.Iterator ; 12 import java.util.LinkedHashMap ; 13 import java.util.List ; 14 import java.util.Map ; 15 import java.util.Stack ; 16 17 import antlr.collections.AST; 18 19 import com.jofti.core.IPredicate; 20 import com.jofti.exception.JoftiException; 21 import com.jofti.introspect.ClassIntrospector; 22 import com.jofti.util.ArrayComparator; 23 import com.jofti.util.CompositeComparator; 24 import com.jofti.util.ReflectionComparator; 25 26 33 public class AbstractParser { 34 35 38 protected ClassIntrospector introspector = null; 39 protected Map compiledQueries = null; 40 41 protected Object lockObject = new Object (); 42 43 static final String NULL = "NULL"; 44 45 46 public AbstractParser(final int cachedQueries, ClassIntrospector introspector){ 47 48 this.introspector = introspector; 49 compiledQueries = new LinkedHashMap (){ 51 52 private final int MAX_ENTRIES = cachedQueries; 53 54 protected boolean removeEldestEntry(Map.Entry eldest) { 55 return size() > MAX_ENTRIES; 56 } 57 58 }; 59 } 60 61 62 63 71 protected Stack parseWherePredicates(AST expression, Stack stack, ParsedQuery query) throws JoftiException{ 72 73 AST subExpression = parseExpression(expression, stack, query); 75 76 while (subExpression != null){ 78 79 subExpression = parseExpression(subExpression,stack, query); 80 } 81 return stack; 82 } 83 84 protected AST parseExpression(AST expression, Stack stack, ParsedQuery parsedQuery) throws JoftiException{ 86 87 if (expression.getType() == CommonLexerTokenTypes.AND || expression.getType() == CommonLexerTokenTypes.OR){ 89 91 stack.push(new Operator(expression.getType())); 92 return expression.getNextSibling(); 93 94 } else if (expression.getType() == CommonLexerTokenTypes.LPAREN){ 96 97 AST nextNode = parseSubPredicate(expression, parsedQuery, stack); 99 return nextNode; 100 } else if (expression.getType() == CommonLexerTokenTypes.RPAREN){ 101 return expression.getNextSibling(); 103 }else if (expression != null){ 104 105 IPredicate predicate = constructPredicate(expression,parsedQuery); 107 stack.push(predicate); 108 return expression.getNextSibling(); 109 } 110 return expression; 111 112 113 114 } 115 116 117 protected AST parseSubPredicate(AST expression,ParsedQuery query,Stack stack) throws JoftiException{ 118 119 Stack subStack = new Stack (); 120 121 AST subExpression = expression.getNextSibling(); 123 subExpression = parseExpression(subExpression,subStack,query); 125 while (subExpression != null && subExpression.getType() != CommonLexerTokenTypes.RPAREN){ 126 subExpression = parseExpression(subExpression,subStack,query); 127 } 128 if (subExpression != null && subExpression.getType() == CommonLexerTokenTypes.RPAREN){ 129 subExpression = subExpression.getNextSibling(); 130 } 131 StackPredicate predicate = new StackPredicate(); 132 predicate.setPredicateStack(subStack); 133 stack.push(predicate); 135 137 return subExpression; 138 } 139 140 protected IPredicate constructPredicate(AST expression,ParsedQuery query) throws JoftiException{ 141 142 Predicate temp = new Predicate(); 144 temp.setOperator(expression.getType()); 145 146 AST field = expression.getFirstChild(); 147 148 String realValue = field.getText(); 149 150 if(query.getAliasMap().size() >0){ 152 int dotIndex = realValue.indexOf("."); 154 if (dotIndex<0){ 155 throw new JoftiException("Alias prefix is missing from field "+ realValue); 156 }else{ 157 String alias = realValue.substring(0,dotIndex); 159 if (query.getAliasMap().get(alias) == null){ 160 throw new JoftiException("Alias prefix is missing or incorrect from field "+ realValue); 161 }else{ 162 temp.setField(realValue.substring(dotIndex+1)); 164 temp.setAlias(alias); 165 } 166 167 } 168 169 } else{ 170 temp.setField(realValue); 171 } 172 173 174 AST value = field.getNextSibling(); 175 176 if (value == null){ 177 throw new JoftiException("field name is missing from expression - check that you are not trying to use 'and' or 'or' as field names"); 178 } 179 180 if (value.getText().length() == 0){ 182 temp.setValue(value.getText()); 183 }else if (value.getText().charAt(0) == ':' ){ 185 if (value.getText().length() <2){ 186 throw new JoftiException("Parameter "+ value.getText() + " must have an associated identifier"); 187 } 188 temp.setValue(value.getText()); 189 } else if ( value.getText().charAt(0) == '?'){ 191 if (value.getText().length() <2){ 192 throw new JoftiException("Parameter "+ value.getText() + " must have an associated identifier"); 193 194 } 195 try { 197 Integer.parseInt(value.getText().substring(1)); 198 }catch (NumberFormatException nfe){ 199 throw new JoftiException("Parameter "+ value.getText() + " is not numeric"); 200 } 201 temp.setValue(value.getText()); 202 }else if (temp.getOperator() == CommonLexerTokenTypes.IS || 203 temp.getOperator() == CommonLexerTokenTypes.NOT){ 204 if (!(NULL.equalsIgnoreCase(value.getText()) )){ 205 throw new JoftiException("Only value 'NULL' is supported for operators IS or NOT"); 206 207 } 208 temp.setValue(value.getText()); 209 }else if (temp.getOperator() == CommonLexerTokenTypes.LIKE){ 210 if (!(value.getText().endsWith("%") || value.getText().length() <2 )){ 211 throw new JoftiException("Value must end with '%' for operator LIKE and contain at least 1 character prefix"); 212 213 } 214 temp.setValue(value.getText()); 215 }else if (temp.getOperator() == CommonLexerTokenTypes.IN){ 216 217 if (value.getType() != CommonLexerTokenTypes.LPAREN ){ 218 throw new JoftiException("argument for IN operator Collection must be of format (val1,val2,..,valn)"); 219 220 } 221 222 List tempList = new ArrayList (); 223 while (value.getNextSibling() != null && value.getNextSibling().getType() != CommonLexerTokenTypes.RPAREN){ 224 value = value.getNextSibling(); 225 if (value.getType() != CommonLexerTokenTypes.COMMA){ 226 tempList.add(value.getText()); 227 } 228 229 } 230 temp.setValue(tempList); 231 }else{ 232 temp.setValue(value.getText()); 233 } 234 235 return temp; 236 237 } 238 239 240 protected Object [] getMethodsForProperty(Class singleClass, Map aliasMap,String alias) throws JoftiException{ 241 int aliasSeperator = alias.indexOf('.'); 242 243 Class clazz = null; 244 245 if (singleClass == null){ 246 clazz= getClassForAlias(aliasMap, alias); 247 }else{ 248 clazz = singleClass; 249 } 250 251 252 253 String attribute = alias.substring(aliasSeperator + 1, alias.length()); 254 if (clazz ==null){ 255 throw new JoftiException("attribute "+ alias + " must consist of Class.property and Class must be specified in from clause"); 256 } 257 258 Object [] methods = introspector.getMethodsForAttribute(clazz,attribute); 259 if (methods == null || methods.length ==0){ 260 throw new JoftiException("Attribute "+ attribute + " is not valid for "+ clazz); 262 }else{ 263 return methods; 264 } 265 266 267 268 } 269 270 protected Class getClassForAlias(Map aliasMap, String alias) 271 throws JoftiException { 272 int aliasSeperator = alias.indexOf('.'); 273 274 if (aliasSeperator > 0) { 275 String aliasObj = alias.substring(0, aliasSeperator); 276 277 Class clazz = (Class ) aliasMap.get(aliasObj); 279 if (clazz == null) { 280 throw new JoftiException("identifier " + aliasObj 281 + " in " + alias + " is not specified as a Class in from clause"); 282 283 } 284 return clazz; 285 } else if (aliasSeperator == 0) { 286 throw new JoftiException("Object identifier:" + alias 287 + " cannot start with '.'"); 288 } 289 return null; 290 } 291 292 protected int getIndexFor(Map aliasMap,Map returnMap,String alias) throws JoftiException{ 293 int aliasSeperator = alias.indexOf('.'); 294 295 Class clazz = getClassForAlias(aliasMap, alias); 296 297 if (clazz ==null){ 298 throw new JoftiException("attribute "+ alias + " must consist of Class.property and Class must be specified in from clause"); 299 } 300 301 ClassFieldMethods fieldSet = (ClassFieldMethods) returnMap.get(clazz); 302 if (fieldSet == null) { 303 throw new JoftiException("ordering class "+ clazz + " is not in select clause"); 304 } 305 306 String attribute = alias.substring(aliasSeperator + 1, alias.length()); 307 int i=-1; 308 Iterator it = fieldSet.getFieldMap().keySet().iterator(); 309 310 for (int j=0;j<fieldSet.getFieldMap().size();j++){ 311 String key = (String )it.next(); 312 if (key.equals(attribute)){ 313 i =j; 314 } 315 } 316 317 return i; 318 319 320 } 321 322 protected ParsedQuery parseOrder(AST expression, ParsedQuery query) 323 throws JoftiException { 324 325 AST node = expression; 327 boolean arrayIteratorType =false; 328 if (query.getFieldReturnMap().size() >1){ 330 throw new JoftiException("ORDER BY clause is not allowed if multi-object return is specified"); 331 }else { 332 Iterator it = query.getFieldReturnMap().values().iterator(); 334 for (int i=0;i<query.getFieldReturnMap().size();i++){ 335 ClassFieldMethods temp = (ClassFieldMethods)it.next(); 336 if (temp!= null && temp.getFieldMap() !=null && temp.getFieldMap().size() >0){ 337 arrayIteratorType =true; 339 } 340 } 341 } 342 343 node = node.getFirstChild().getNextSibling(); 344 345 do { 346 348 349 CompositeComparator comp = query.getOrderingComparator(); 351 Comparator itemComp = null; 352 353 if (arrayIteratorType){ 354 int index = getIndexFor(query.getAliasMap(),query.getFieldReturnMap(),node.getText().trim() ); 355 if (index <0){ 356 throw new JoftiException("ORDER BY attribute "+node.getText().trim() + " must be specified in select clause"); 357 } 358 itemComp = new ArrayComparator(index); 359 }else{ 360 Object [] methods =getMethodsForProperty(query.getClassName(),query.getAliasMap(), node.getText().trim()); 361 362 itemComp = new ReflectionComparator(methods,introspector); 363 } 364 365 366 node = node.getNextSibling(); 367 if (node != null){ 368 switch (node.getType()){ 369 case CommonLexerTokenTypes.ASC : 370 comp.addComparator(itemComp); 371 node = node.getNextSibling(); 372 break; 373 case CommonLexerTokenTypes.DESC : 374 comp.addComparator(itemComp,true); 375 node = node.getNextSibling(); 376 break; 377 default: 378 comp.addComparator(itemComp); 379 break; 380 381 } 382 }else{ 383 comp.addComparator(itemComp); 384 385 } 386 387 } while (node != null); 388 389 return query; 390 391 } 392 393 public Map getCompiledQueries() { 394 return compiledQueries; 395 } 396 } 397 | Popular Tags |