KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > jofti > parser > AbstractParser


1 /*
2  * Created on 12-Jan-2006
3  *
4  * TODO To change the template for this generated file go to
5  * Window - Preferences - Java - Code Style - Code Templates
6  */

7 package com.jofti.parser;
8
9 import java.util.ArrayList JavaDoc;
10 import java.util.Comparator JavaDoc;
11 import java.util.Iterator JavaDoc;
12 import java.util.LinkedHashMap JavaDoc;
13 import java.util.List JavaDoc;
14 import java.util.Map JavaDoc;
15 import java.util.Stack JavaDoc;
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 /**
27  * Provides the base functionality for other Parser types.
28  *
29  * @author xenephon
30  * @version 1.2
31  *
32  */

33 public class AbstractParser {
34
35     /**
36      *
37      */

38     protected ClassIntrospector introspector = null;
39     protected Map JavaDoc compiledQueries = null;
40
41       protected Object JavaDoc lockObject = new Object JavaDoc();
42         
43      static final String JavaDoc NULL = "NULL";
44     
45      
46      public AbstractParser(final int cachedQueries, ClassIntrospector introspector){
47          
48         this.introspector = introspector;
49         // cache of previously parsed queries
50
compiledQueries = new LinkedHashMap JavaDoc(){
51             
52             private final int MAX_ENTRIES = cachedQueries;
53
54              protected boolean removeEldestEntry(Map.Entry JavaDoc eldest) {
55                 return size() > MAX_ENTRIES;
56              }
57
58         };
59      }
60      
61      
62      
63     /**
64      * Parses the where predicates.
65      * @param expression - start of the where query
66      * @param stack - the predicate stack
67      * @param query
68      * @return
69      * @throws JoftiException
70      */

71     protected Stack JavaDoc parseWherePredicates(AST expression, Stack JavaDoc stack, ParsedQuery query) throws JoftiException{
72         
73         // parse the first expression
74
AST subExpression = parseExpression(expression, stack, query);
75         
76         // keep going while we have a predicate to parse
77
while (subExpression != null){
78             
79             subExpression = parseExpression(subExpression,stack, query);
80         }
81         return stack;
82     }
83     
84     // parse an individual statement
85
protected AST parseExpression(AST expression, Stack JavaDoc stack, ParsedQuery parsedQuery) throws JoftiException{
86         
87         // is the expression joined via a boolean operator?
88
if (expression.getType() == CommonLexerTokenTypes.AND || expression.getType() == CommonLexerTokenTypes.OR){
89             // we have joined statements
90

91         stack.push(new Operator(expression.getType()));
92         return expression.getNextSibling();
93         
94         // is it a grouped expression
95
} else if (expression.getType() == CommonLexerTokenTypes.LPAREN){
96         
97         // parse the subpredicate
98
AST nextNode = parseSubPredicate(expression, parsedQuery, stack);
99         return nextNode;
100     } else if (expression.getType() == CommonLexerTokenTypes.RPAREN){
101         //
102
return expression.getNextSibling();
103     }else if (expression != null){
104         
105          // we have a single predicate
106
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 JavaDoc stack) throws JoftiException{
118         
119         Stack JavaDoc subStack = new Stack JavaDoc();
120         
121         // get next expression
122
AST subExpression = expression.getNextSibling();
123         // parse the expression
124
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         // set the predicate in the current stack
134
stack.push(predicate);
135         // return where we are in the tree
136

137         return subExpression;
138     }
139     
140     protected IPredicate constructPredicate(AST expression,ParsedQuery query) throws JoftiException{
141         
142         // set up the predicate
143
Predicate temp = new Predicate();
144         temp.setOperator(expression.getType());
145         
146         AST field = expression.getFirstChild();
147         
148         String JavaDoc realValue = field.getText();
149         
150         //
151
if(query.getAliasMap().size() >0){
152             // we need to make sure that all fields have aliases
153
int dotIndex = realValue.indexOf(".");
154             if (dotIndex<0){
155                 throw new JoftiException("Alias prefix is missing from field "+ realValue);
156             }else{
157                 //make sure the alias is in the map
158
String JavaDoc 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                     // set the field into the predicate
163
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 empty this could be valid
181
if (value.getText().length() == 0){
182              temp.setValue(value.getText());
183        // else a named parameter could be present
184
}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 // check if numeric one is
190
} 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             // see if it is a number
196
try {
197                 Integer.parseInt(value.getText().substring(1));
198             }catch (NumberFormatException JavaDoc 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 JavaDoc tempList = new ArrayList JavaDoc();
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 JavaDoc[] getMethodsForProperty(Class JavaDoc singleClass, Map JavaDoc aliasMap,String JavaDoc alias) throws JoftiException{
241         int aliasSeperator = alias.indexOf('.');
242         
243         Class JavaDoc clazz = null;
244         
245         if (singleClass == null){
246             clazz= getClassForAlias(aliasMap, alias);
247         }else{
248             clazz = singleClass;
249         }
250         
251         
252         
253         String JavaDoc 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 JavaDoc[] methods = introspector.getMethodsForAttribute(clazz,attribute);
259         if (methods == null || methods.length ==0){
260             // log.warn
261
throw new JoftiException("Attribute "+ attribute + " is not valid for "+ clazz);
262         }else{
263             return methods;
264         }
265
266         
267         
268     }
269     
270     protected Class JavaDoc getClassForAlias(Map JavaDoc aliasMap, String JavaDoc alias)
271     throws JoftiException {
272 int aliasSeperator = alias.indexOf('.');
273
274 if (aliasSeperator > 0) {
275     String JavaDoc aliasObj = alias.substring(0, aliasSeperator);
276
277     // we need to split them up
278
Class JavaDoc clazz = (Class JavaDoc) 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 JavaDoc aliasMap,Map JavaDoc returnMap,String JavaDoc alias) throws JoftiException{
293         int aliasSeperator = alias.indexOf('.');
294         
295         Class JavaDoc 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 JavaDoc attribute = alias.substring(aliasSeperator + 1, alias.length());
307         int i=-1;
308         Iterator JavaDoc it = fieldSet.getFieldMap().keySet().iterator();
309         
310         for (int j=0;j<fieldSet.getFieldMap().size();j++){
311             String JavaDoc key = (String JavaDoc)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         // will be alias for field
326
AST node = expression;
327         boolean arrayIteratorType =false;
328         // work out whether we need object or array iterators
329
if (query.getFieldReturnMap().size() >1){
330             throw new JoftiException("ORDER BY clause is not allowed if multi-object return is specified");
331         }else {
332             //either fields or a whole object is specified
333
Iterator JavaDoc 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                     // we are using array returns object
338
arrayIteratorType =true;
339                 }
340             }
341         }
342         
343         node = node.getFirstChild().getNextSibling();
344
345     do {
346         // we have an as
347

348         
349         // put the aliases into the alias and return map
350
CompositeComparator comp = query.getOrderingComparator();
351         Comparator JavaDoc 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 JavaDoc[] 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 JavaDoc getCompiledQueries() {
394         return compiledQueries;
395     }
396 }
397
Popular Tags