View Javadoc

1   /*   Copyright (C) 2004 Finalist IT Group
2    *
3    *   This file is part of JAG - the Java J2EE Application Generator
4    *
5    *   JAG is free software; you can redistribute it and/or modify
6    *   it under the terms of the GNU General Public License as published by
7    *   the Free Software Foundation; either version 2 of the License, or
8    *   (at your option) any later version.
9    *   JAG is distributed in the hope that it will be useful,
10   *   but WITHOUT ANY WARRANTY; without even the implied warranty of
11   *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12   *   GNU General Public License for more details.
13   *   You should have received a copy of the GNU General Public License
14   *   along with JAG; if not, write to the Free Software
15   *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16   */
17  
18  package com.finalist.tools.database;
19  
20  import java.util.*;
21  
22  /***
23   * Class that models a Query.
24   *
25   * @author  P.S.D.Reitsma, Finalist IT Group
26   * @version 1.0
27   */
28  public class Query {
29     String qName;    //name of the query
30     String qString;  // the query's definition
31     String oriqString; //the query's original definition
32  
33     ArrayList BindIdentifiers; //no encapsulation
34  
35     int argCount;    // the number of arguments to be bound
36     boolean givesResultSet; // determines "SELECT" or DML
37     boolean performsOrderBy; //determines whether a sort takes place
38     boolean isUpdate;
39     boolean isInsert;
40     boolean isDelete;
41     boolean isCallable;
42     boolean malformed = false;
43  
44  
45     private String replace(String text1, String text2, int pPosition) {
46        String repString = "<P" + pPosition + ">";
47  
48        int pos = text1.indexOf(repString);
49        if (pos == -1) {
50           return text1;
51        }
52        StringBuffer labelBuf = new StringBuffer(text1);
53        labelBuf.replace(pos, pos + repString.length(), text2);
54        return replace(labelBuf.toString(), text2, pPosition);
55     }
56  
57  
58     /*
59      * Method replaces the occurence of <P1> by String pReplacement
60      * and reparses the query definition.
61      *
62      * @param String pReplacement. The string that is to be substituted for <P1>.
63      */
64     public void fillInPlaceholder(Hashtable pReplacements) {
65        Enumeration E = pReplacements.keys();
66        String replacer;
67        Integer pos;
68  
69        //start with the original query definition
70        String qStr = oriqString;
71  
72        String workString = oriqString;
73  
74        while (E.hasMoreElements()) {
75           pos = (Integer) E.nextElement();
76           replacer = (String) pReplacements.get(pos);
77           qStr = replace(workString, replacer, pos.intValue());
78           workString = qStr;
79        }
80  
81        parse(qStr);
82     }
83  
84  
85     /***
86      * Constructor.
87      * Initializes the Query object by parsing the Query definition qStr.
88      *
89      * @param  qNm   defines the name of the query
90      * @param  qStr  defines the query's definition
91      */
92     public Query(String qNm, String qStr) {
93  
94        oriqString = qStr;
95  
96        qName = qNm;
97  
98        parse(qStr);
99  
100    }
101 
102 
103    /***
104     * Constructor
105     * Initializes the Query object by parsing the Query definition
106     *
107     * @param definition the definition of the query in SQL
108     */
109    public Query(String definition) {
110       oriqString = definition;
111       parse(definition);
112    }
113 
114 
115    void parse(String qStr) {
116 
117       BindIdentifiers = new ArrayList();
118 
119       try {
120          String BindIdentifyer = null;
121          StringBuffer q = new StringBuffer(qStr);
122          int startBI = qStr.indexOf("{{"); //determine startposition
123          int endBI = qStr.lastIndexOf("}}") + 2; //and endposition
124          if ((startBI != -1) && (endBI != -1)) { //a BindIdentifier is found.
125             BindIdentifyer = q.substring(startBI, endBI);
126             qString = q.delete(startBI, endBI).toString();
127             qString.toUpperCase();
128             qString.trim();
129             BindIdentifyer = BindIdentifyer.replace('{', ' ');
130             BindIdentifyer = BindIdentifyer.replace('}', ' ');
131             BindIdentifyer = BindIdentifyer.trim();
132 
133             StringTokenizer st = new StringTokenizer(BindIdentifyer, ",");
134             while (st.hasMoreTokens()) {
135                BindIdentifiers.add(st.nextToken().trim());
136             }
137 
138          }
139          else {
140             qString = qStr.trim();
141 
142             char[] querychars = qString.toCharArray();
143             Vector startpositions = new Vector();
144             //loop over the chars that make up the query.
145             for (int i = 1; i != querychars.length; i++) { //start with 1 !
146                //check if the colon is not part of a dateformat 'HH24:MI' e.g.
147                if ((querychars[i] == ':') && //look for ':'
148                   (
149                   (querychars[i - 1] == ' ') || //that is preceded by a blank
150                   (querychars[i - 1] == ',') || //or a ','
151                   (querychars[i - 1] == '=') || //or a '='
152                   (querychars[i - 1] == '(') || //or a '('
153                   (querychars[i - 1] == '-') || //or a '-'
154                   (querychars[i - 1] == '+') || //or a '+'
155                   (querychars[i - 1] == '{') || //or a '{'
156                   (querychars[i - 1] == '<') || //or a '<'
157                   (querychars[i - 1] == '>') || //or a '>'
158                   (querychars[i - 1] == '|') || //or a '|'
159                   (querychars[i - 1] == 13)//or a CR
160                   ) &&
161                   (
162                   (querychars[i + 1] != '=')//do not process ':='
163                   )
164                ) { //or a '+'
165                   //if such ':' is found loop over the trailing characters
166                   //until a non-letter character is found ((int)char<49).
167                   int j = i + 1;
168                   StringBuffer bindelement = new StringBuffer();
169                   while (
170                      (j < querychars.length)
171                      && (
172                      (querychars[j] >= 48) && (querychars[j] <= 57)  // 0..9
173                      || (querychars[j] >= 65) && (querychars[j] <= 90)  // A..Z
174                      || (querychars[j] >= 97) && (querychars[j] <= 122) // a..z
175                      || (querychars[j] == 95)// _
176                      )
177                      ) {
178                      //build up the bind identifyer element.
179                      bindelement.append(querychars[j]);
180                      startpositions.addElement(new Integer(i));
181                      j++;
182                   }
183                   //add it to the vector.
184                   BindIdentifiers.add(bindelement.toString().trim());
185                }
186             }
187             StringBuffer sb;
188             Iterator E = BindIdentifiers.iterator();
189             while (E.hasNext()) {
190                String bindElement = ":" + (String) E.next();
191                sb = new StringBuffer(qString);
192                for (int i = 0; i < qString.length(); i++) {
193                   if (qString.startsWith(bindElement, i)) {
194                      sb.replace(i, i + bindElement.length(), "?");
195                      //exit if one replacement has been made.
196                      break;
197                   }
198                }
199                qString = sb.toString();
200             }
201          }
202          givesResultSet = qString.toUpperCase().startsWith("SELECT");
203          performsOrderBy = (qString.toUpperCase().indexOf("ORDER BY") != -1);
204          isUpdate = qString.toUpperCase().startsWith("UPDATE");
205          isInsert = qString.toUpperCase().startsWith("INSERT");
206          isDelete = qString.toUpperCase().startsWith("DELETE");
207          isCallable = (
208             qString.toUpperCase().startsWith("BEGIN")
209             || qString.toUpperCase().startsWith("{")
210             );
211          argCount = 0;
212          for (int i = 0; i < qStr.length(); i++) {
213             if (qStr.charAt(i) == '?') {
214                argCount++;
215             }
216          }
217          if (BindIdentifyer != null) {
218             if (BindIdentifiers.size() < argCount) {
219                System.out.println("Query(): " + qName + " has not enough bind identifiers.");
220             }
221             if (BindIdentifiers.size() > argCount) {
222                System.out.println("Query(): " + qName + " has too many bind identifiers.");
223             }
224          }
225       }
226       catch (Exception E) {
227          malformed = true;
228          System.out.println("Query(): Exception ocurred during initialisation of query " + qName);
229          E.printStackTrace();
230       }
231    }
232 
233 
234    /*** Getter for property BindIdentifiers.
235     *
236     * @return Value of property BindIdentifiers.
237     */
238    public ArrayList getBindIdentifiers() {
239       return BindIdentifiers;
240    }
241 
242 
243    /*** Setter for property BindIdentifiers.
244     * @param BindIdentifiers New value of property BindIdentifiers.
245     */
246    public void setBindIdentifiers(ArrayList BindIdentifiers) {
247       this.BindIdentifiers = BindIdentifiers;
248    }
249 
250 
251    /*** Getter for property oriqString.
252     * @return Value of property oriqString.
253     */
254    public java.lang.String getOriqString() {
255       return oriqString;
256    }
257 
258 
259    /*** Setter for property oriqString.
260     * @param oriqString New value of property oriqString.
261     */
262    public void setOriqString(java.lang.String oriqString) {
263       this.oriqString = oriqString;
264    }
265 
266 }
267 
268