Coverage Report - net.sf.sapjcosupport.SapQuery
 
Classes in this File Line Coverage Branch Coverage Complexity
SapQuery
0% 
0% 
2,391
 
 1  
 package net.sf.sapjcosupport;
 2  
 
 3  
 import org.apache.log4j.Logger;
 4  
 import org.apache.oro.text.regex.*;
 5  
 
 6  
 import java.util.*;
 7  
 
 8  
 /**
 9  
  * @author Niki Driessen
 10  
  * @since Apr 21, 2006 - 10:47:03 AM
 11  
  */
 12  
 public class SapQuery {
 13  
     private String searchHelpName, selectionMethod;
 14  
     private int maximumResults;
 15  
     private Class persistentObject;
 16  0
     private List javaFields = new ArrayList(2);
 17  0
     private List sapFields = new ArrayList(2);
 18  0
     private List criteria = new ArrayList(1);
 19  
 
 20  0
     protected final Logger log = Logger.getLogger(getClass());
 21  
     private static Map optionMap;
 22  
     private static final String operatorRegex = "(like|not like|==|=|<>|!=|<=|>=|<|>)";
 23  
 
 24  
     static {
 25  0
         optionMap = new TreeMap();
 26  0
         optionMap.put("like", SearchCriterion.CONTAINS_PATTERN);
 27  0
         optionMap.put("not like", SearchCriterion.CONTAINS_NOT_PATTERN);
 28  0
         optionMap.put("==", SearchCriterion.EQUAL);
 29  0
         optionMap.put("=", SearchCriterion.EQUAL);
 30  0
         optionMap.put("<>", SearchCriterion.NOT_EQUAL);
 31  0
         optionMap.put("!=", SearchCriterion.NOT_EQUAL);
 32  0
         optionMap.put("<=", SearchCriterion.LESS_OR_EQUAL);
 33  0
         optionMap.put(">=", SearchCriterion.GREATER_OR_EQUAL);
 34  0
         optionMap.put("<", SearchCriterion.LESS);
 35  0
         optionMap.put(">", SearchCriterion.GREATER);
 36  
 //        optionMap.put("between", SearchCriterion.BETWEEN);
 37  
 //        optionMap.put("not between",SearchCriterion.NOT_BETWEEN);
 38  
 
 39  0
     }
 40  
 
 41  
     private static final String WHERE = "where";
 42  
     private static final String FROM = "from";
 43  
     private static final String SELECT = "select";
 44  
 
 45  
     /**
 46  
      * "partNumber = MATNR_EXT where MATNR_EXT like '?%' AND SPRAS = 'E'"
 47  
      * "partNumber = MATNR_EXT, alternateDescription = MAKTG where MAKTG like '%?%' AND SPRAS = 'E'"
 48  
      *
 49  
      * @param query
 50  
      */
 51  0
     public SapQuery(String query, Class persistentObject, int maximumResults) {
 52  0
         this.persistentObject = persistentObject;
 53  0
         this.maximumResults = maximumResults;
 54  0
         parseQuery(query);
 55  0
     }
 56  
 
 57  
     public class QueryParseException extends RuntimeException {
 58  0
         public QueryParseException(String queryPart, String expected, int offset) {
 59  0
             super("Syntax error near: " + queryPart + ", at position: " + offset + ", expected: " + expected);
 60  0
         }
 61  
     }
 62  
 
 63  
     private class WhereClauseSplitter extends StringSplitter {
 64  
         private Collection delims;
 65  
 
 66  0
         public WhereClauseSplitter(String string) {
 67  0
             super(string, "(and|or)", false);
 68  0
         }
 69  
 
 70  0
         public WhereClauseSplitter(String string, String regex) {
 71  0
             super(string, regex, false);
 72  0
         }
 73  
 
 74  
         protected void split() {
 75  
             try {
 76  0
                 PatternCompiler compiler = new Perl5Compiler();
 77  
                 Pattern pattern;
 78  0
                 if (caseSensitive) {
 79  0
                     pattern = compiler.compile(delim);
 80  
                 } else {
 81  0
                     pattern = compiler.compile(delim, Perl5Compiler.CASE_INSENSITIVE_MASK);
 82  
                 }
 83  0
                 PatternMatcher partsMatcher = new Perl5Matcher();
 84  0
                 parts = new ArrayList(5);
 85  0
                 delims = new ArrayList(5);
 86  0
                 int prev = 0;
 87  0
                 PatternMatcherInput input = new PatternMatcherInput(string);
 88  0
                 while (partsMatcher.contains(input, pattern)) {
 89  0
                     MatchResult result = partsMatcher.getMatch();
 90  0
                     parts.add(string.substring(prev, result.beginOffset(1)));
 91  0
                     delims.add(result.group(1));
 92  0
                     prev = result.endOffset(1) + 1;
 93  0
                     input.setBeginOffset(prev);
 94  
                 }
 95  0
                 parts.add(string.substring(prev));
 96  0
             } catch (Exception e) {
 97  0
                 e.printStackTrace();
 98  0
                 throw new QueryParseException(string, "valid condition expression", 0);
 99  0
             }
 100  0
         }
 101  
 
 102  
         public Iterator iterator() {
 103  0
             return new WhereClauseIterator(parts.iterator(), delims.iterator());
 104  
         }
 105  
 
 106  
         public class WhereClauseIterator implements Iterator {
 107  
             private String matchedDelim;
 108  
             private Iterator internal;
 109  
             private Iterator delims;
 110  
 
 111  0
             public WhereClauseIterator(Iterator parts, Iterator delims) {
 112  0
                 this.internal = parts;
 113  0
                 this.delims = delims;
 114  0
             }
 115  
 
 116  
             public void remove() {
 117  0
                 delims.remove();
 118  0
                 internal.remove();
 119  0
             }
 120  
 
 121  
             public boolean hasNext() {
 122  0
                 return internal.hasNext();
 123  
             }
 124  
 
 125  
             public Object next() {
 126  0
                 if (delims.hasNext()) {
 127  0
                     matchedDelim = (String) delims.next();
 128  
                 }
 129  0
                 return internal.next();
 130  
             }
 131  
 
 132  
             public String getMatchedDelim() {
 133  0
                 return matchedDelim;
 134  
             }
 135  
         }
 136  
 
 137  
     }
 138  
 
 139  
     private class StringSplitter {
 140  
         protected Collection parts;
 141  
         protected String string;
 142  
         protected String delim;
 143  
         protected boolean caseSensitive;
 144  
 
 145  
         /**
 146  
          * Splits a string by delim.
 147  
          *
 148  
          * @param string
 149  
          * @param delim
 150  
          */
 151  0
         public StringSplitter(String string, String delim, boolean caseSensitive) {
 152  0
             this.string = string;
 153  0
             this.delim = delim;
 154  0
             this.caseSensitive = caseSensitive;
 155  0
             split();
 156  0
         }
 157  
 
 158  
         protected void split() {
 159  0
             String source = this.string;
 160  0
             if (!caseSensitive) {
 161  0
                 source = string.toLowerCase();
 162  0
                 delim = delim.toLowerCase();
 163  
             }
 164  0
             parts = new ArrayList();
 165  0
             int prev = 0;
 166  0
             int index = source.indexOf(delim);
 167  0
             while (index > 0) {
 168  0
                 String part = string.substring(prev, index);
 169  0
                 parts.add(part.trim());
 170  0
                 prev = index + delim.length() + 1;
 171  0
                 index = source.indexOf(delim, prev);
 172  
             }
 173  
             //last part...
 174  0
             parts.add(string.substring(prev).trim());
 175  0
         }
 176  
 
 177  
         public Iterator iterator() {
 178  0
             return parts.iterator();
 179  
         }
 180  
 
 181  
         public int countParts() {
 182  0
             return parts.size();
 183  
         }
 184  
     }
 185  
 
 186  
     public void parseQuery(String query) {
 187  
         //parse the query
 188  0
         StringSplitter whereSplitter = new StringSplitter(query, WHERE, false);
 189  0
         if (whereSplitter.countParts() != 2) {
 190  0
             throw new QueryParseException(query, WHERE, query.length());
 191  
         }
 192  0
         Iterator mainParts = whereSplitter.iterator();
 193  0
         String temp = (String) mainParts.next();
 194  0
         StringSplitter selectFromSplitter = new StringSplitter(temp, FROM, false);
 195  0
         if (selectFromSplitter.countParts() != 2) {
 196  0
             throw new QueryParseException(temp, FROM, query.length());
 197  
         }
 198  0
         Iterator selectFromParts = selectFromSplitter.iterator();
 199  0
         String selectClause = (String) selectFromParts.next();
 200  0
         selectClause = replaceFirst(selectClause, SELECT, "");
 201  0
         String fromClause = (String) selectFromParts.next();
 202  0
         String whereClause = (String) mainParts.next();
 203  
 
 204  0
         StringTokenizer fieldSelectionTokenizer = new StringTokenizer(selectClause, ",");
 205  0
         while (fieldSelectionTokenizer.hasMoreTokens()) {
 206  0
             String part = fieldSelectionTokenizer.nextToken().trim();
 207  0
             parseFieldSelection(part, query.indexOf(part));
 208  
         }
 209  
 
 210  
 
 211  0
         StringTokenizer fromTokenizer = new StringTokenizer(fromClause, ".");
 212  0
         if (fromTokenizer.countTokens() != 2) {
 213  0
             throw new QueryParseException(fromClause, "from SEARCHHELP.SELECTION_METHOD", fromClause.length());
 214  
         }
 215  0
         searchHelpName = fromTokenizer.nextToken();
 216  0
         selectionMethod = fromTokenizer.nextToken();
 217  
 
 218  0
         WhereClauseSplitter.WhereClauseIterator whereParts = (WhereClauseSplitter.WhereClauseIterator)
 219  
                 new WhereClauseSplitter(whereClause).iterator();
 220  0
         while (whereParts.hasNext()) {
 221  0
             String part = (String) whereParts.next();
 222  0
             String delim = whereParts.getMatchedDelim();
 223  0
             parseCriteria(part);
 224  
         }
 225  0
     }
 226  
 
 227  
     private String replaceFirst(String haystack, String needle, String replacement) {
 228  0
         int pos = haystack.indexOf(needle);
 229  0
         if (pos >= 0) {
 230  0
             return (pos > 0 ? haystack.substring(0, pos - 1) : "") +
 231  
                     replacement +
 232  
                     (((pos + needle.length()) < haystack.length()) ?
 233  
                             haystack.substring(pos + needle.length()) : "");
 234  
         }
 235  0
         return haystack;
 236  
     }
 237  
 
 238  
     /**
 239  
      * Parses expression of the form 'javaField = SAP_FIELD'.
 240  
      * spaces are optional (can be none or more between the parts of the expression)
 241  
      *
 242  
      * @param queryPart the part of the query to interprete as a field selection
 243  
      */
 244  
     private void parseFieldSelection(String queryPart, int offset) {
 245  0
         StringTokenizer tokenizer = new StringTokenizer(queryPart, "=");
 246  0
         if (tokenizer.countTokens() != 2) {
 247  0
             throw new QueryParseException(queryPart, "=", offset);
 248  
         }
 249  0
         String javaField = tokenizer.nextToken().trim();
 250  0
         String sapField = tokenizer.nextToken().trim();
 251  0
         javaFields.add(javaField);
 252  0
         sapFields.add(sapField);
 253  0
     }
 254  
 
 255  
     private void parseCriteria(String queryPart) {
 256  0
         WhereClauseSplitter splitter = new WhereClauseSplitter(queryPart, operatorRegex);
 257  0
         WhereClauseSplitter.WhereClauseIterator clauseParts = (WhereClauseSplitter.WhereClauseIterator) splitter.iterator();
 258  0
         if (splitter.countParts() != 2) {
 259  0
             throw new QueryParseException(queryPart, "'field [operator] value'", 0);
 260  
         } else {
 261  0
             String field = ((String) clauseParts.next()).trim();
 262  0
             String option = (String) optionMap.get(clauseParts.getMatchedDelim());
 263  0
             String lowLimit = ((String) clauseParts.next()).trim();
 264  0
             if (field.length() == 0) {
 265  0
                 throw new QueryParseException(queryPart, "valid field name before operator", 0);
 266  
             }
 267  0
             if (option == null) {
 268  0
                 throw new QueryParseException(queryPart, "valid operator", 0);
 269  
             }
 270  0
             if (lowLimit.length() == 0) {
 271  0
                 throw new QueryParseException(queryPart, "valid expression after operator", 0);
 272  
             }
 273  0
             if (lowLimit.charAt(0) == '\'') {
 274  0
                 lowLimit = lowLimit.substring(1);
 275  
             }
 276  0
             if (lowLimit.charAt(lowLimit.length() - 1) == '\'') {
 277  0
                 lowLimit = lowLimit.substring(0, lowLimit.length() - 1);
 278  
             }
 279  0
             lowLimit = lowLimit.replace('%', '*');
 280  0
             SearchCriterion criterion = new SearchCriterion();
 281  0
             criterion.setField(field);
 282  
             //criterion.setHighLimit();
 283  0
             criterion.setLowLimit(lowLimit);
 284  0
             criterion.setIncluded(true);
 285  0
             criterion.setOption(option);
 286  0
             criteria.add(criterion);
 287  
         }
 288  0
     }
 289  
 
 290  
     public void setParameter(String parameter) {
 291  0
         setParameter(0, parameter);
 292  0
     }
 293  
 
 294  
     public void setParameter(int position, String parameter) {
 295  0
         SearchCriterion criterion = (SearchCriterion) criteria.get(position);
 296  0
         if (criterion != null) {
 297  0
             String lowLimit = criterion.getLowLimit();
 298  0
             lowLimit = replaceFirst(lowLimit, "?", parameter);
 299  0
             criterion.setLowLimit(lowLimit);
 300  
         } else {
 301  0
             throw new IndexOutOfBoundsException("No parameter at position " + position);
 302  
         }
 303  0
     }
 304  
 
 305  
     public void setParameters(String[] params) {
 306  0
         for (int i = 0; i < params.length; i++) {
 307  0
             String param = params[i];
 308  0
             setParameter(i, param);
 309  
         }
 310  0
     }
 311  
 
 312  
     public List executeQuery(SapSearchHelp searchHelper) {
 313  0
         return searchHelper.search(searchHelpName, selectionMethod, maximumResults, criteria, persistentObject, javaFields, sapFields);
 314  
     }
 315  
 }