View Javadoc

1   /*
2    * $Header: /cvsroot/jdbforms/dbforms/src/org/dbforms/event/datalist/dao/DataSourceXML.java,v 1.35 2006/01/25 16:35:23 hkollmann Exp $
3    * $Revision: 1.35 $
4    * $Date: 2006/01/25 16:35:23 $
5    *
6    * DbForms - a Rapid Application Development Framework
7    * Copyright (C) 2001 Joachim Peer <joepeer@excite.com>
8    *
9    * This library is free software; you can redistribute it and/or
10   * modify it under the terms of the GNU Lesser General Public
11   * License as published by the Free Software Foundation; either
12   * version 2.1 of the License, or (at your option) any later version.
13   *
14   * This library is distributed in the hope that it will be useful,
15   * but WITHOUT ANY WARRANTY; without even the implied warranty of
16   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17   * Lesser General Public License for more details.
18   *
19   * You should have received a copy of the GNU Lesser General Public
20   * License along with this library; if not, write to the Free Software
21   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
22   */
23  
24  package org.dbforms.event.datalist.dao;
25  
26  import org.apache.commons.logging.Log;
27  import org.apache.commons.logging.LogFactory;
28  
29  import org.dbforms.config.Constants;
30  import org.dbforms.config.DbFormsConfigRegistry;
31  import org.dbforms.config.Field;
32  import org.dbforms.config.FieldValue;
33  import org.dbforms.config.FieldValues;
34  
35  import org.dbforms.dom.DOMFactory;
36  
37  import org.dbforms.util.Util;
38  
39  import org.w3c.dom.Document;
40  import org.w3c.dom.Element;
41  
42  import java.net.URL;
43  
44  import java.sql.Connection;
45  import java.sql.SQLException;
46  
47  import java.util.Hashtable;
48  import java.util.Iterator;
49  import java.util.Vector;
50  
51  
52  
53  /***
54   * Special implementation of DataSource. This class deals with xml data
55   *
56   * @author hkk
57   */
58  public class DataSourceXML extends AbstractDataSource {
59     private Hashtable     keys;
60     private Log           logCat           = LogFactory.getLog(this.getClass().getName());
61     private String        sqlFilter;
62     private XMLDataResult data;
63     private Object[][]    dataObject       = null;
64     private FieldValue[]  filterConstraint;
65     private FieldValue[]  orderConstraint;
66     private FieldValue[]  sqlFilterParams;
67  
68  
69     /***
70      * Set the filterConstraint and orderConstraint used to build the SQL Select
71      * condition.
72      *
73      * @param filterConstraint FieldValue array used to build a cumulation of
74      *        rules for filtering fields.
75      * @param orderConstraint FieldValue array used to build a cumulation of
76      *        rules for ordering (sorting) and restricting fields.
77      * @param sqlFilter sql condition to add to where clause
78      * @param sqlFilterParams list of FieldValues to fill the sqlFilter with
79      */
80     public void setSelect(FieldValue[] filterConstraint,
81                           FieldValue[] orderConstraint,
82                           String       sqlFilter,
83                           FieldValue[] sqlFilterParams) {
84        this.filterConstraint = filterConstraint;
85        this.orderConstraint  = orderConstraint;
86        this.sqlFilter        = sqlFilter;
87        this.sqlFilterParams  = sqlFilterParams;
88     }
89  
90  
91     /***
92      * performs an update into the DataSource
93      *
94      * @param con DOCUMENT ME!
95      * @param fieldValues FieldValues to update
96      * @param keyValuesStr keyValueStr to the row to update<br>
97      *        key format: FieldID ":" Length ":" Value<br>
98      *        example: if key id = 121 and field id=2 then keyValueStr contains "2:3:121"<br>
99      *        If the key consists of more than one fields, the key values are
100     *        seperated through "-"<br>
101     *        example: value of field 1=12, value of field 3=1992, then we'll
102     *        get "1:2:12-3:4:1992"
103     *
104     * @throws SQLException if any error occurs
105     */
106    public void doUpdate(Connection  con,
107                         FieldValues fieldValues,
108                         String      keyValuesStr) throws SQLException {
109       Integer row = (Integer) keys.get(keyValuesStr);
110 
111       if (row != null) {
112          int      r    = row.intValue();
113          Iterator iter = fieldValues.elements();
114 
115          while (iter.hasNext()) {
116             FieldValue fv = (FieldValue) iter.next();
117             Field      f = fv.getField();
118             data.setItemValue(r,
119                               Util.isNull(f.getExpression()) ? f.getName()
120                                                              : f.getExpression(),
121                               f.getType(), fv.getFieldValueAsObject());
122          }
123 
124          dataObject[r] = null;
125       }
126    }
127 
128 
129    /***
130     * should retrieve the row at an special index as an Object[]
131     *
132     * @param currRow index of row to fetch
133     *
134     * @return Object[] of the fetched row
135     *
136     * @throws SQLException
137     */
138    protected final Object[] getRow(int currRow) throws SQLException {
139       if ((currRow < 0) || (currRow >= size())) {
140          return null;
141       }
142 
143       if (dataObject[currRow] == null) {
144          Vector   fields = getTable()
145                               .getFields();
146          Object[] objectRow = new Object[fields.size()];
147          String[] stringRow = new String[fields.size()];
148 
149          for (int i = 0; i < fields.size(); i++) {
150             Field f = (Field) fields.elementAt(i);
151             objectRow[i] = data.getItemValue(currRow,
152                                              Util.isNull(f.getExpression())
153                                              ? f.getName()
154                                              : f.getExpression(), f.getType());
155             stringRow[i] = (objectRow[i] != null) ? objectRow[i].toString()
156                                                   : null;
157          }
158 
159          String key = getTable()
160                          .getKeyPositionString(stringRow);
161          keys.put(key, new Integer(currRow));
162          dataObject[currRow] = objectRow;
163       }
164 
165       return dataObject[currRow];
166    }
167 
168 
169    /***
170     * should close all open datasets
171     */
172    protected final void close() {
173       if ((data != null) && data.hasChanged()) {
174          try {
175             String url = getFilePath() + getQuery();
176             write(url, data.getRoot());
177          } catch (Exception e) {
178             logCat.error(e);
179          }
180       }
181 
182       if (keys != null) {
183          keys.clear();
184       }
185 
186       dataObject = null;
187    }
188 
189 
190    /***
191     * maps the startRow to the internal index
192     *
193     * @param startRow keyValueStr to the row<br>
194     *        key format: FieldID ":" Length ":" Value<br>
195     *        example: if key id = 121 and field id=2 then keyValueStr contains "2:3:121"<br>
196     *        If the key consists of more than one fields, the key values  are
197     *        seperated through "-"<br>
198     *        example: value of field 1=12, value of field 3=1992, then we'll
199     *        get "1:2:12-3:4:1992"
200     *
201     * @return the index of the row, 0 as first row if not found
202     *
203     * @throws SQLException
204     */
205    protected final int findStartRow(String startRow) throws SQLException {
206       Integer res = null;
207 
208       if (!Util.isNull(startRow)) {
209          res = (Integer) keys.get(startRow);
210       }
211 
212       return (res != null) ? res.intValue()
213                            : 0;
214    }
215 
216 
217    /***
218     * Will be called to open all datasets
219     *
220     * @throws SQLException
221     */
222    protected final void open() throws SQLException {
223       if (dataObject == null) {
224          try {
225             String qry = getQuery();
226             String url = getFilePath() + qry;
227 
228             try {
229                URL u = new URL(url);
230                qry = u.getQuery();
231             } catch (Exception e) {
232                logCat.info("open", e);
233             }
234 
235             Document doc = read(url);
236 
237             if (doc != null) {
238                Element elem = doc.getDocumentElement();
239                data = new XMLDataResult(elem, qry);
240             }
241          } catch (Exception e) {
242             logCat.error("open", e);
243             throw new SQLException(e.getMessage());
244          }
245 
246          keys       = new Hashtable();
247          dataObject = new Object[size()][];
248       }
249    }
250 
251 
252    /***
253     * Must return the size of the whole resultset with all data fetch
254     *
255     * @return size of whole resultset
256     *
257     * @throws SQLException
258     */
259    protected final int size() throws SQLException {
260       return (data != null) ? data.size()
261                             : 0;
262    }
263 
264 
265    /***
266     * return true if there are more records to fetch then the given record
267     * number
268     *
269     * @param i index of last fetched row.
270     *
271     * @return true if there are more records to fetch then the given record
272     *         number
273     *
274     * @throws SQLException
275     */
276    protected boolean hasMore(int i) throws SQLException {
277       return (i < size());
278    }
279 
280 
281    /***
282     * gets the document from the remote system.
283     *
284     * @param url the uri to query
285     *
286     * @return NODE the result
287     *
288     * @throws Exception Exception during processing IO
289     */
290    protected Document read(String url) throws Exception {
291       return DOMFactory.instance()
292                        .read(url);
293    }
294 
295 
296    /***
297     * saves the document to the remote system.
298     *
299     * @param url DOCUMENT ME!
300     * @param root DOCUMENT ME!
301     *
302     * @throws Exception Exception during processing IO
303     */
304    protected void write(String  url,
305                         Element root) throws Exception {
306       DOMFactory.instance()
307                 .write(url, root);
308    }
309 
310 
311    private String getFilePath() throws Exception {
312       return DbFormsConfigRegistry.instance().lookup().replaceVariables(getTable().getAlias());
313    }
314 
315 
316    private String getQuery() throws SQLException {
317       StringBuffer buf = new StringBuffer();
318 
319       String       filter     = getWhereClause();
320       String       psqlFilter = getSQLFilter();
321 
322       if (!Util.isNull(filter) || !Util.isNull(sqlFilter)) {
323          buf.append("[");
324          buf.append(filter);
325 
326          if (!Util.isNull(psqlFilter)) {
327             if (!Util.isNull(filter)) {
328                buf.append(" and ");
329             }
330 
331             buf.append(sqlFilter);
332          }
333 
334          buf.append("]");
335       }
336 
337       return buf.toString();
338    }
339 
340 
341    private String getSQLFilter() {
342       if (sqlFilter == null)
343 		   return null;
344 	   /*** substitute ? with corresponding value in list */
345       int          p1  = 0;
346       int          p2  = sqlFilter.indexOf('?', p1);
347       StringBuffer buf = new StringBuffer();
348       int          cnt = 0;
349 
350       while (p2 > -1) {
351          // add the string before the next ?
352          buf.append(sqlFilter.substring(p1, p2));
353 
354          // if values are exausted, then abort
355          if (cnt >= sqlFilterParams.length) {
356             logCat.error("reference to a missing filterValue in " + sqlFilter);
357 
358             return null;
359          }
360 
361          // retrieve value
362          String value = sqlFilterParams[cnt].getFieldValue();
363 
364          if (!Util.isNull(value)) {
365             // add value to string gbuffer
366             buf.append("\"");
367             buf.append(value);
368             buf.append("\"");
369          }
370 
371          // restart search from next char after ? 
372          p1 = p2 + 1;
373          p2 = sqlFilter.indexOf('?', p1);
374          cnt++;
375       }
376 
377       // add remaining part of string
378       buf.append(sqlFilter.substring(p1));
379 
380       return buf.toString();
381    }
382 
383 
384    private String getWhereClause() throws SQLException {
385       StringBuffer buf = new StringBuffer();
386 
387       if (!FieldValue.isNull(filterConstraint)) {
388          for (int i = 0; i < filterConstraint.length; i++) {
389             if (i != 0) {
390                if (filterConstraint[i].getLogicalOR()) {
391                   buf.append(" or ");
392                } else {
393                   buf.append(" and ");
394                }
395             }
396 
397             Field f = filterConstraint[i].getField();
398             buf.append(Util.isNull(f.getExpression()) ? f.getName()
399                                                       : f.getExpression());
400 
401             // Check what type of operator is required
402             switch (filterConstraint[i].getOperator()) {
403                case Constants.FILTER_EQUAL:
404                   buf.append("=");
405 
406                   break;
407 
408                case Constants.FILTER_NOT_EQUAL:
409                   buf.append("!=");
410 
411                   break;
412 
413                case Constants.FILTER_GREATER_THEN:
414                   buf.append("&gt;");
415 
416                   break;
417 
418                case Constants.FILTER_SMALLER_THEN:
419                   buf.append("&lt;");
420 
421                   break;
422 
423                case Constants.FILTER_GREATER_THEN_EQUAL:
424                   buf.append("&gt;=");
425 
426                   break;
427 
428                case Constants.FILTER_SMALLER_THEN_EQUAL:
429                   buf.append("&lt;=");
430 
431                   break;
432             }
433 
434             buf.append("\"");
435             buf.append(filterConstraint[i].getFieldValueAsObject().toString());
436             buf.append("\"");
437          }
438       }
439 
440       return buf.toString();
441    }
442 }