KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > dbforms > config > Table


1 /*
2  * $Header: /cvsroot/jdbforms/dbforms/src/org/dbforms/config/Table.java,v 1.62 2005/02/19 21:26:28 hkollmann Exp $
3  * $Revision: 1.62 $
4  * $Date: 2005/02/19 21:26:28 $
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.config;
25
26 import org.apache.commons.logging.Log;
27 import org.apache.commons.logging.LogFactory;
28
29 import org.dbforms.util.IEscaper;
30 import org.dbforms.util.MessageResourcesInternal;
31 import org.dbforms.util.ParseUtil;
32 import org.dbforms.util.ReflectionUtil;
33 import org.dbforms.util.SqlUtil;
34 import org.dbforms.util.StringUtil;
35 import org.dbforms.util.Util;
36
37 import java.sql.PreparedStatement JavaDoc;
38 import java.sql.ResultSet JavaDoc;
39 import java.sql.SQLException JavaDoc;
40 import java.sql.Statement JavaDoc;
41
42 import java.util.Collection JavaDoc;
43 import java.util.Hashtable JavaDoc;
44 import java.util.Iterator JavaDoc;
45 import java.util.Locale JavaDoc;
46 import java.util.StringTokenizer JavaDoc;
47 import java.util.Vector JavaDoc;
48
49 import java.io.Serializable JavaDoc;
50
51
52 import javax.servlet.http.HttpServletRequest JavaDoc;
53
54
55
56 /**
57  * This class represents a table tag in dbforms-config.xml (dbforms config xml
58  * file). <br>
59  * It also defines a lot of methods for preparing and actually performing
60  * operations (queries) on the table
61  *
62  * @author Joe Peer
63  */

64 public class Table implements Serializable JavaDoc {
65    /** either "classic" or "interceptor", default is "interceptor" */
66    public static final int BLOB_INTERCEPTOR = 0;
67
68    /** DOCUMENT ME! */
69    public static final int BLOB_CLASSIC = 1;
70    private static final int MAXFIELDS = 1000;
71
72    /** DOCUMENT ME! */
73    protected static final int DB_FIELD = 0;
74
75    /** DOCUMENT ME! */
76    protected static final int SEARCH_FIELD = 1;
77
78    /** DOCUMENT ME! */
79    protected static final int CALC_FIELD = 2;
80
81    /**
82     * access control list for this object (if null, then its open to all users
83     * for all operations). Defined in dbforms-config.xml
84     */

85    private GrantedPrivileges grantedPrivileges = null;
86    private Hashtable JavaDoc calcFieldsNameHash = new Hashtable JavaDoc();
87
88    /** structure for quick acessing of fields "by name" */
89    private Hashtable JavaDoc fieldNameHash = new Hashtable JavaDoc();
90
91    /** access foreign key by name */
92    private Hashtable JavaDoc foreignKeyNameHash = new Hashtable JavaDoc();
93    private IEscaper escaper = null;
94
95    /** log4j category */
96    private static Log logCat = LogFactory.getLog(Table.class.getName());
97
98    /** some sort of alias to set in dbforms-config, not used yet */
99    private String JavaDoc alias = null;
100    private String JavaDoc blobHandling = null;
101
102    /** reference to the DataAccess Class */
103    private String JavaDoc dataAccessClass = null;
104
105    /** Holds value of property defaultVisibleFields. */
106    private String JavaDoc defaultVisibleFields;
107
108    /** Holds value of property defaultVisibleFieldsFormat. */
109    private String JavaDoc defaultVisibleFieldsFormat;
110    private String JavaDoc escaperClass = null;
111
112    /** the name of the Table */
113    private String JavaDoc name;
114
115    /**
116     * instance variables concerned with the ORDERING/SORTING characterstics of
117     * that table (ordering and sorting is used synonym here)
118     */

119    private String JavaDoc orderBy;
120
121    /** reference to a TableEvents object */
122    private TableEvents tableEvents = null;
123    private Vector JavaDoc calcFields = new Vector JavaDoc();
124
125    /**
126     * subset of "fields", containting those keys which represent DISKBLOBs
127     * (wondering about that term? -> see docu)
128     */

129    private Vector JavaDoc diskblobs = new Vector JavaDoc();
130
131    /** the Field-Objects this table constists of */
132    private Vector JavaDoc fields = new Vector JavaDoc();
133    private Vector JavaDoc foreignKeys = new Vector JavaDoc();
134
135    /** application hookups */
136    private Vector JavaDoc interceptors = new Vector JavaDoc();
137
138    /** subset of "fields", containting those keys which represent keys */
139    private Vector JavaDoc key = new Vector JavaDoc();
140
141    /** the order-by clause, as specified in dbforms-config.xml (optional!) */
142    private FieldValue[] defaultOrder;
143    private int blobHandlingStrategy = BLOB_INTERCEPTOR;
144
145    /**
146     * id of this table (generated by DbFormsConfig when parsing
147     * dbforms-config.xml)
148     */

149    private int id;
150
151    /**
152     * DOCUMENT ME!
153     *
154     * @param alias the alias to set
155     */

156    public void setAlias(String JavaDoc alias) {
157       this.alias = alias;
158    }
159
160
161    /**
162     * DOCUMENT ME!
163     *
164     * @return String
165     */

166    public String JavaDoc getAlias() {
167       return alias;
168    }
169
170
171    /**
172     * for digester only, see blobHandlingStrategy
173     *
174     * @param blobHandling config parameter
175     */

176    public void setBlobHandling(String JavaDoc blobHandling) {
177       this.blobHandling = blobHandling;
178
179       if ("classic".equals(blobHandling)) {
180          this.blobHandlingStrategy = BLOB_CLASSIC;
181       } else {
182          this.blobHandlingStrategy = BLOB_INTERCEPTOR;
183       }
184    }
185
186
187    /**
188     * for digester only, see blobHandlingStrategy
189     *
190     * @return String
191     */

192    public String JavaDoc getBlobHandling() {
193       return blobHandling;
194    }
195
196
197    /**
198     * DOCUMENT ME!
199     *
200     * @return DOCUMENT ME!
201     */

202    public int getBlobHandlingStrategy() {
203       return this.blobHandlingStrategy;
204    }
205
206
207    /**
208     * DOCUMENT ME!
209     *
210     * @return
211     */

212    public Vector JavaDoc getCalcFields() {
213       return calcFields;
214    }
215
216
217    /**
218     * Sets the dataAccessClass.
219     *
220     * @param dataAccessClass The dataAccessClass to set
221     */

222    public void setDataAccessClass(String JavaDoc dataAccessClass) {
223       this.dataAccessClass = dataAccessClass;
224    }
225
226
227    /**
228     * DOCUMENT ME!
229     *
230     * @return String
231     */

232    public String JavaDoc getDataAccessClass() {
233       return dataAccessClass;
234    }
235
236
237    /**
238     * Return the datastructure containing info about the default sorting
239     * behavior of this table.
240     *
241     * @return the datastructure containing info about the default sorting
242     * behavior of this table.
243     */

244    public FieldValue[] getDefaultOrder() {
245       return defaultOrder;
246    }
247
248
249    /**
250     * Setter for property defaultVisibleFields.
251     *
252     * @param defaultVisibleFields New value of property defaultVisibleFields.
253     */

254    public void setDefaultVisibleFields(String JavaDoc defaultVisibleFields) {
255       this.defaultVisibleFields = defaultVisibleFields;
256    }
257
258
259    /**
260     * Getter for property defaultVisibleFields.
261     *
262     * @return Value of property defaultVisibleFields.
263     */

264    public String JavaDoc getDefaultVisibleFields() {
265       return this.defaultVisibleFields;
266    }
267
268
269    /**
270     * Setter for property defaultVisibleFieldsFormat.
271     *
272     * @param defaultVisibleFieldsFormat New value of property
273     * defaultVisibleFieldsFormat.
274     */

275    public void setDefaultVisibleFieldsFormat(String JavaDoc defaultVisibleFieldsFormat) {
276       this.defaultVisibleFieldsFormat = defaultVisibleFieldsFormat;
277    }
278
279
280    /**
281     * Getter for property defaultVisibleFieldsFormat.
282     *
283     * @return Value of property defaultVisibleFieldsFormat.
284     */

285    public String JavaDoc getDefaultVisibleFieldsFormat() {
286       return this.defaultVisibleFieldsFormat;
287    }
288
289
290    /**
291     * Returns SQL delete statement, used by deleteEvent.
292     *
293     * @return the SQL delete statement
294     */

295    public String JavaDoc getDeleteStatement() {
296       // now we start building the DELETE statement
297
StringBuffer JavaDoc queryBuf = new StringBuffer JavaDoc();
298       queryBuf.append("DELETE FROM ");
299       queryBuf.append(getQueryToChange());
300       queryBuf.append(" WHERE ");
301       queryBuf.append(getWhereClauseForKeyFields());
302       logCat.info(queryBuf.toString());
303
304       return queryBuf.toString();
305    }
306
307
308    /**
309     * Generates part of a field list for a SQL SELECT clause selecting the
310     * DISKBLOB fields from a table (used by DeleteEvent to maintain data
311     * consistence).
312     *
313     * @return a part of a field list for a SQL SELECT clause selecting the
314     * DISKBLOB fields from a table
315     */

316    public String JavaDoc getDisblobSelectStatement() {
317       StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
318       buf.append("SELECT ");
319
320       int cnt = diskblobs.size();
321
322       for (int i = 0; i < cnt; i++) {
323          Field diskblobField = (Field) diskblobs.elementAt(i);
324
325          // get the name of the encoded key field
326
buf.append(diskblobField.getName());
327
328          if (i < (cnt - 1)) {
329             buf.append(", ");
330          }
331       }
332
333       buf.append(" FROM ");
334       buf.append(getQueryFrom());
335
336       return buf.toString();
337    }
338
339
340    /**
341     * Returns a Vector of Field-Objects representing fields of type "DISKBLOB"
342     *
343     * @return a Vector of Field-Objects representing fields of type "DISKBLOB"
344     */

345    public Vector JavaDoc getDiskblobs() {
346       return diskblobs;
347    }
348
349
350    /**
351     * Get the SQL ResultSet from the query builded using the input data. Order
352     * of parts: 1. sqlFilter 2. where condition generated from searching 3.
353     * where condition generated from ordering Generating the query in
354     * getSelectQuery() must match this order!
355     *
356     * @param fvEqual FieldValue array used to restrict a set in a subform where
357     * all "childFields" in the resultset match their respective
358     * "parentFields" in main form
359     * @param fvOrder FieldValue array used to build a cumulation of rules for
360     * ordering (sorting) and restricting fields
361     * @param sqlFilterParams DOCUMENT ME!
362     * @param compareMode the value of the compare mode
363     * @param ps the PreparedStatement object
364     *
365     * @return a ResultSet object
366     *
367     * @throws SQLException if any error occurs
368     */

369    public ResultSet JavaDoc getDoSelectResultSet(FieldValue[] fvEqual,
370                                          FieldValue[] fvOrder,
371                                          FieldValue[] sqlFilterParams,
372                                          int compareMode,
373                                          PreparedStatement JavaDoc ps)
374                                   throws SQLException JavaDoc {
375       // the index of the first NOT POPULATED placeholder;
376
int curCol = 1;
377
378       logCat.debug("###getDoSelectResultSet pos1");
379
380       if (!FieldValue.isNull(sqlFilterParams)) {
381          curCol = populateWhereEqualsClause(sqlFilterParams, ps, curCol);
382       }
383
384       logCat.debug("###getDoSelectResultSet pos2");
385
386       if (!FieldValue.isNull(fvEqual)) {
387          curCol = populateWhereEqualsClause(fvEqual, ps, curCol);
388       }
389
390       logCat.debug("###getDoSelectResultSet pos3");
391
392       if ((compareMode != Constants.COMPARE_NONE)
393                 && (fvOrder != null)
394                 && (fvOrder.length > 0)) {
395          populateWhereAfterClause(fvOrder, ps, curCol);
396       }
397
398       logCat.debug("###getDoSelectResultSet pos3");
399
400       ResultSet JavaDoc result = null;
401
402       try {
403          result = ps.executeQuery();
404       } catch (SQLException JavaDoc sqle) {
405          SqlUtil.logSqlException(sqle);
406          throw sqle;
407       }
408
409       return result;
410    }
411
412
413    /**
414     * DOCUMENT ME!
415     *
416     * @return DOCUMENT ME!
417     */

418    public IEscaper getEscaper() {
419       if (escaper == null) {
420          String JavaDoc s = getEscaperClass();
421
422          if (!Util.isNull(s)) {
423             try {
424                escaper = (IEscaper) ReflectionUtil.newInstance(s);
425             } catch (Exception JavaDoc e) {
426                logCat.error("cannot create the new escaper [" + s + "]", e);
427             }
428          }
429
430          if ((escaper == null)) {
431             try {
432                escaper = DbFormsConfigRegistry.instance()
433                                               .lookup()
434                                               .getEscaper();
435             } catch (Exception JavaDoc e) {
436                logCat.error("cannot create the new default escaper", e);
437             }
438          }
439       }
440
441       return escaper;
442    }
443
444
445    /**
446     * DOCUMENT ME!
447     *
448     * @param string
449     */

450    public void setEscaperClass(String JavaDoc string) {
451       escaperClass = string;
452    }
453
454
455    /**
456     * DOCUMENT ME!
457     *
458     * @return
459     */

460    public String JavaDoc getEscaperClass() {
461       return escaperClass;
462    }
463
464
465    /**
466     * Returns the Field-Objet with specified id.
467     *
468     * @param fieldId The id of the field to be returned
469     *
470     * @return the Field object having the input id
471     */

472    public Field getField(int fieldId) {
473       Field f = null;
474
475       if (checkFieldId(CALC_FIELD, fieldId)) {
476          f = (Field) calcFields.elementAt(decodeFieldId(CALC_FIELD, fieldId));
477       } else {
478          f = (Field) fields.elementAt(fieldId);
479       }
480
481       return f;
482    }
483
484
485    /**
486     * Returns the field-objects as specified by name (or null if no field with
487     * the specified name exists in this table).
488     *
489     * @param name The name of the field
490     *
491     * @return Filed object having the input name
492     */

493    public Field getFieldByName(String JavaDoc aname) {
494       Field f = (Field) fieldNameHash.get(aname);
495       if (f == null) {
496          f = (Field) calcFieldsNameHash.get(aname);
497       }
498       return f;
499    }
500
501
502    /**
503     * We have the field ID - we need the field name
504     *
505     * @param fieldID fieldID to get field name from
506     *
507     * @return the field name
508     */

509    public String JavaDoc getFieldName(int fieldID) {
510       Field f = (Field) getFields()
511                            .elementAt(fieldID);
512
513       return (f.getName());
514    }
515
516
517    /**
518     * This method parses a position string and build a data structure
519     * representing the values of the fields decoded from the position. <br>
520     * #fixme: replace seperator-based tokenization by better algoithm!
521     *
522     * @param position the position string
523     *
524     * @return the HashTable containing the FieldValues of the fields decoded,
525     * key of the HashTable is the fieldName!
526     */

527    public FieldValues getFieldValues(String JavaDoc position) {
528       // 20020705-HKK: Position maybe string with length = 0!!!!
529
if (Util.isNull(position)) {
530          return null;
531       }
532
533       // trailing blanks are significant for CHAR database fields
534
// position = position.trim();
535
// 20021128-HKK: catch errors!
536
// 2003-03-29 HKK: Change from Hashtable to FieldValueTable
537
FieldValues result = new FieldValues();
538
539       try {
540          int startIndex = 0;
541          boolean endOfString = false;
542
543          // looping through the string
544
while (!endOfString) {
545             int firstColon = position.indexOf(':', startIndex);
546             int secondColon = position.indexOf(':', firstColon + 1);
547
548             if ((firstColon == -1) && (secondColon == -1)) {
549                return null;
550             }
551
552             String JavaDoc fieldIdStr = position.substring(startIndex, firstColon);
553             int fieldId = Integer.parseInt(fieldIdStr);
554
555             String JavaDoc valueLengthStr = position.substring(firstColon + 1,
556                                                        secondColon);
557             int valueLength = Integer.parseInt(valueLengthStr);
558
559             int controlIndex = secondColon + 1 + valueLength;
560
561             // make already be trimmed ... avoid substring exception
562
String JavaDoc valueStr = (controlIndex < position.length())
563                               ? position.substring(secondColon + 1, controlIndex)
564                               : position.substring(secondColon + 1);
565
566             Field f = getField(fieldId);
567             FieldValue fv = new FieldValue(f, valueStr);
568             result.put(fv);
569
570             if (controlIndex == position.length()) {
571                endOfString = true;
572             } else if (controlIndex > position.length()) {
573                logCat.warn("Controlbyte wrong but continuing execution");
574                endOfString = true;
575             } else {
576                char controlByte = position.charAt(controlIndex);
577
578                if (controlByte != '-') {
579                   logCat.error("Controlbyte wrong, abandon execution");
580                   throw new IllegalArgumentException JavaDoc();
581                }
582
583                startIndex = controlIndex + 1;
584
585                if (position.length() == startIndex) {
586                   endOfString = true;
587                }
588             }
589          }
590       } catch (Exception JavaDoc e) {
591          logCat.error("::getFieldValuesFromPositionAsHt - exception:", e);
592          result = null;
593       }
594
595       return result;
596    }
597
598
599    /**
600     * Returns the vector of fields this table constists of
601     *
602     * @return the vector of fields this table constists of
603     */

604    public Vector JavaDoc getFields() {
605       return fields;
606    }
607
608
609    /**
610     * Initialize the filterFieldValues array.
611     *
612     * @param filter the filter string
613     * @param locale the table object
614     *
615     * @return an initialized FieldValue array
616     *
617     * @todo add MORE docs here !!!
618     */

619    public FieldValue[] getFilterFieldArray(String JavaDoc filter,
620                                            Locale JavaDoc locale) {
621       // 1 to n fields may be mapped
622
Vector JavaDoc keyValPairs = StringUtil.splitString(filter, ",;");
623
624       // ~ no longer used as separator!
625
int len = keyValPairs.size();
626
627       FieldValue[] result = new FieldValue[len];
628
629       for (int i = 0; i < len; i++) {
630          int operator = 0;
631          boolean isLogicalOR = false;
632          int jump = 1;
633          String JavaDoc aKeyValPair = (String JavaDoc) keyValPairs.elementAt(i);
634
635          // i.e "id=2"
636
logCat.debug("initFilterFieldValues: aKeyValPair = " + aKeyValPair);
637
638          // Following code could be optimized, however I did not want to make
639
// too many changes...
640
int n;
641
642          // Check for Not Equal
643
if ((n = aKeyValPair.indexOf("<>")) != -1) {
644             // Not Equal found! - Store the operation for use later on
645
operator = Constants.FILTER_NOT_EQUAL;
646             jump = 2;
647          } else if ((n = aKeyValPair.indexOf(">=")) != -1) {
648             // Check for GreaterThanEqual
649
// GreaterThenEqual found! - Store the operation for use later
650
// on
651
operator = Constants.FILTER_GREATER_THEN_EQUAL;
652             jump = 2;
653          } else if ((n = aKeyValPair.indexOf('>')) != -1) {
654             // Check for GreaterThan
655
// GreaterThen found! - Store the operation for use later on
656
operator = Constants.FILTER_GREATER_THEN;
657          } else if ((n = aKeyValPair.indexOf("<=")) != -1) {
658             // Check for SmallerThenEqual
659
// SmallerThenEqual found! - Store the operation for use later
660
// on
661
operator = Constants.FILTER_SMALLER_THEN_EQUAL;
662             jump = 2;
663          } else if ((n = aKeyValPair.indexOf('<')) != -1) {
664             // Check for SmallerThen
665
// SmallerThen found! - Store the operation for use later on
666
operator = Constants.FILTER_SMALLER_THEN;
667          } else if ((n = aKeyValPair.indexOf('=')) != -1) {
668             // Check for equal
669
// Equal found! - Store the operator for use later on
670
operator = Constants.FILTER_EQUAL;
671          } else if ((n = aKeyValPair.indexOf('~')) != -1) {
672             // Check for LIKE
673
// LIKE found! - Store the operator for use later on
674
operator = Constants.FILTER_LIKE;
675          } else if ((n = aKeyValPair.toUpperCase()
676                                           .indexOf("NOTISNULL")) != -1) {
677             // Check for not is null
678
// LIKE found! - Store the operator for use later on
679
jump = 9;
680             operator = Constants.FILTER_NOT_NULL;
681          } else if ((n = aKeyValPair.toUpperCase()
682                                           .indexOf("ISNULL")) != -1) {
683             // Check for null
684
// LIKE found! - Store the operator for use later on
685
jump = 6;
686             operator = Constants.FILTER_NULL;
687          }
688
689          // PG - At this point, I have set my operator and I should have a
690
// valid index.
691
// Note that the original code did not handle the posibility of not
692
// finding an index
693
// (value = -1)...
694
String JavaDoc fieldName = aKeyValPair.substring(0, n)
695                                        .trim();
696
697          // i.e "id"
698
logCat.debug("Filter field=" + fieldName);
699
700          if (fieldName.charAt(0) == '|') {
701             // This filter must be associated to a logical OR, clean out the
702
// indicator...
703
fieldName = fieldName.substring(1);
704             isLogicalOR = true;
705          }
706
707          Field filterField = getFieldByName(fieldName);
708
709          // Increment by 1 or 2 depending on operator
710
String JavaDoc value = aKeyValPair.substring(n + jump)
711                                    .trim();
712
713          // i.e. "2"
714
logCat.debug("Filter value=" + value);
715
716          // Create a new instance of FieldValue and set the operator variable
717
result[i] = FieldValue.createFieldValueForSearching(filterField,
718                                                              value, locale,
719                                                              operator,
720                                                              Constants.SEARCHMODE_NONE,
721                                                              Constants.SEARCH_ALGO_SHARP,
722                                                              isLogicalOR);
723          logCat.debug("and fv is =" + result[i].toString());
724       }
725
726       return result;
727    }
728
729
730    /**
731     * Get all the ForeignKey objects related to this table.
732     *
733     * @return a vector containing all the ForeignKey objects related to this
734     * table.
735     */

736    public Collection JavaDoc getForeignKeys() {
737       return foreignKeys;
738    }
739
740
741    /**
742     * Prepares the Querystring for the free form select statement
743     *
744     * @param fieldsToSelect vector of fields to be selected
745     * @param whereClause free-form whereClause to be appended to query
746     * @param tableList the list of tables involved into the query
747     *
748     * @return the query string
749     */

750    public String JavaDoc getFreeFormSelectQuery(Vector JavaDoc fieldsToSelect,
751                                         String JavaDoc whereClause,
752                                         String JavaDoc tableList) {
753       StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
754       buf.append("SELECT ");
755       buf.append(getQuerySelect(fieldsToSelect));
756       buf.append(" FROM ");
757
758       if (Util.isNull(tableList)) {
759          buf.append(getQueryFrom());
760       } else {
761          buf.append(tableList);
762       }
763
764       buf.append(" ");
765       buf.append(whereClause);
766       logCat.info("::getFreeFormSelectQuery -- [" + buf.toString() + "]");
767
768       return buf.toString();
769    }
770
771
772    /**
773     * Set GrantedPrivileges, if defined in dbforms-config-xml (this method gets
774     * called from XML-digester).
775     *
776     * @param grantedPrivileges the grantedPrivileges object
777     */

778    public void setGrantedPrivileges(GrantedPrivileges grantedPrivileges) {
779       this.grantedPrivileges = grantedPrivileges;
780    }
781
782
783    /**
784     * returns object containing info about rights mapped to user-roles.
785     * (context: this table object!)
786     *
787     * @return the GrantedPrivileges object
788     */

789    public GrantedPrivileges getGrantedPrivileges() {
790       return grantedPrivileges;
791    }
792
793
794    /**
795     * Sets the ID of this table (this method gets called from DbFormsConfig).
796     *
797     * @param id the id value to set
798     */

799    public void setId(int id) {
800       this.id = id;
801    }
802
803
804    /**
805     * Returns ID of this table.
806     *
807     * @return the id value
808     */

809    public int getId() {
810       return id;
811    }
812
813
814    /**
815     * Returns SQL insert statement, used by insertEvent.
816     *
817     * @param fieldValues the Hashtable containing the field values
818     *
819     * @return the SQL insert statement
820     */

821    public String JavaDoc getInsertStatement(FieldValues fieldValues) {
822       StringBuffer JavaDoc queryBuf = new StringBuffer JavaDoc();
823       queryBuf.append("INSERT INTO ");
824       queryBuf.append(getQueryToChange());
825       queryBuf.append(" (");
826
827       // list the names of fields we'll include into the insert operation
828
Iterator JavaDoc e = fieldValues.keys();
829
830       while (e.hasNext()) {
831          String JavaDoc fieldName = (String JavaDoc) e.next();
832          queryBuf.append(fieldName);
833
834          if (e.hasNext()) {
835             queryBuf.append(",");
836          }
837       }
838
839       // list the place-holders for the fields to include
840
queryBuf.append(") VALUES (");
841
842       for (int i = 0; i < fieldValues.size(); i++) {
843          if (i != 0) {
844             queryBuf.append(",");
845          }
846
847          queryBuf.append("?");
848       }
849
850       queryBuf.append(")");
851       logCat.info(queryBuf.toString());
852
853       return queryBuf.toString();
854    }
855
856
857    /**
858     * Get all the interceptor objects related to this table.
859     *
860     * @return a vector containing all the interceptor objects related to this
861     * table.
862     */

863    public Vector JavaDoc getInterceptors() {
864     Vector JavaDoc res = interceptors;
865     if ((getConfig() != null) && getConfig().hasInterceptors()) {
866          res = new Vector JavaDoc(interceptors);
867          res.addAll(getConfig().getInterceptors());
868          res.addAll(interceptors);
869       }
870      return res;
871    }
872
873
874    /**
875     * Returns the key of this table (consisting of Field-Objects representing
876     * key-fields).
877     *
878     * @return the key of this table (consisting of Field-Objects representing
879     * key-fields)
880     */

881    public Vector JavaDoc getKey() {
882       return key;
883    }
884
885
886    /**
887     * Does basically the same as getPositionString but only for key-fields. <br>
888     * #checkme: could be merged with getPositionString <br>
889     * #fixme: replace seperator-based tokenization by better algoithm!
890     *
891     * @param rsv the ResultSetVector object
892     *
893     * @return the position string for key fields
894     */

895    public String JavaDoc getKeyPositionString(ResultSetVector rsv) {
896       if (ResultSetVector.isNull(rsv)) {
897          return null;
898       }
899
900       String JavaDoc[] currentRow = rsv.getCurrentRow();
901
902       if (currentRow == null) {
903          return null;
904       }
905
906       return getKeyPositionString(currentRow);
907    }
908
909
910    /**
911     * Does basically the same as getPositionString but only for key-fields.
912     *
913     * @param currentRow the currentRow as String[]
914     *
915     * @return the position string
916     */

917    public String JavaDoc getKeyPositionString(String JavaDoc[] currentRow) {
918       StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
919
920       if (currentRow != null) {
921          for (int i = 0; i < getKey()
922                                       .size(); i++) {
923             Field f = (Field) getKey()
924                                  .elementAt(i);
925
926             if (i > 0) {
927                buf.append("-"); // control byte
928
}
929
930             buf.append(createToken(f, currentRow[f.getId()]));
931          }
932       }
933
934       return buf.toString();
935    }
936
937
938    /**
939     * Get key position from the input hash table
940     *
941     * @param fvHT has field as key and FieldValue as value!
942     *
943     * @return the key position string
944     *
945     * @throws IllegalArgumentException DOCUMENT ME!
946     */

947    public String JavaDoc getKeyPositionString(FieldValues fvHT) {
948       if (fvHT == null) {
949          return null;
950       }
951
952       StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
953       int cnt = 0;
954
955       for (int i = 0; i < getKey()
956                                    .size(); i++) {
957          Field f = (Field) getKey()
958                                    .elementAt(i);
959          FieldValue fv = fvHT.get(f.getName());
960
961          if (fv != null) {
962             String JavaDoc value = fv.getFieldValue();
963
964             if (value == null) {
965                throw new IllegalArgumentException JavaDoc("wrong fields provided");
966             }
967
968             if (cnt > 0) {
969                buf.append("-"); // control byte
970
}
971
972             buf.append(createToken(f, value));
973             cnt++;
974          }
975       }
976
977       return buf.toString();
978    }
979
980
981    /**
982     * Sets the name of the table (this method gets called from XML-digester)
983     *
984     * @param name the name of the table
985     */

986    public void setName(String JavaDoc name) {
987       this.name = name;
988    }
989
990
991    /**
992     * Returns name of the table
993     *
994     * @return the name of this table
995     */

996    public String JavaDoc getName() {
997       return name;
998    }
999
1000
1001   /**
1002    * returns the hash table. Moved from dbFormTag to table, so that you can
1003    * overload it!
1004    *
1005    * @param core starting tag for the fields
1006    *
1007    * @return hash table of names in PHP slang we would call that an
1008    * "associative array" :=)
1009    */

1010   public Hashtable JavaDoc getNamesHashtable(String JavaDoc core) {
1011      Hashtable JavaDoc result = new Hashtable JavaDoc();
1012      Iterator JavaDoc e = getFields()
1013                       .iterator();
1014
1015      while (e.hasNext()) {
1016         Field f = (Field) e.next();
1017         result.put(f.getName(), f.getFieldName(core));
1018      }
1019
1020      return result;
1021   }
1022
1023
1024   /**
1025    * Sets a default-orderBy clause from xml config (this method gets called
1026    * from XML-digester).
1027    *
1028    * @param orderBy the orderBy clause
1029    */

1030   public void setOrderBy(String JavaDoc orderBy) {
1031      this.orderBy = orderBy;
1032   }
1033
1034
1035   /**
1036    * Return default-orderBy clause from xml config or null if not specified.
1037    *
1038    * @return the default-orderBy clause from xml config or null if not
1039    * specified.
1040    */

1041   public String JavaDoc getOrderBy() {
1042      return orderBy;
1043   }
1044
1045
1046   /**
1047    * Builds a "position- string" representing the values of the current row in
1048    * the given ResultSetVector. <br>
1049    * Not all field-values get explicitl listed in this string. only fields
1050    * important for navigation and sorting are listed. <br>
1051    * Position strings are used as request parameters allowing the framework
1052    * to keep track of the position the user comes from or goes to. <br>
1053    * Look into com.itp.tablib.DbFormTag for better understanding changed
1054    * 0-04-2001 by joe #note: enhanced algorithm since version 0.9!
1055    *
1056    * @param rsv the ResultSetVector object
1057    *
1058    * @return the position string
1059    */

1060   public String JavaDoc getPositionString(ResultSetVector rsv) {
1061      if (ResultSetVector.isNull(rsv)) {
1062         return null;
1063      }
1064
1065      String JavaDoc[] currentRow = rsv.getCurrentRow();
1066
1067      if (currentRow == null) {
1068         return null;
1069      }
1070
1071      return getPositionString(currentRow);
1072   }
1073
1074
1075   /**
1076    * Builds a "position- string" representing the values of the current row in
1077    * the given ResultSetVector. <br>
1078    * Not all field-values get explicitly listed in this string. only fields
1079    * important for navigation and sorting are listed. <br>
1080    * Position strings are used as request parameters allowing the framework
1081    * to keep track of the position the user comes from or goes to. <br>
1082    *
1083    * @param currentRow the currentRow as String[]
1084    *
1085    * @return the position string
1086    */

1087   public String JavaDoc getPositionString(String JavaDoc[] currentRow) {
1088      StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
1089      int cnt = 0;
1090
1091      for (int i = 0; i < getFields()
1092                                   .size(); i++) {
1093         Field f = (Field) getFields()
1094                              .elementAt(i);
1095
1096         if (f.hasIsKeySet() || f.hasSortableSet()) {
1097            if (cnt > 0) {
1098               buf.append("-"); // control byte
1099
}
1100
1101            buf.append(createToken(f, currentRow[f.getId()]));
1102            cnt++;
1103         }
1104      }
1105
1106      return buf.toString();
1107   }
1108
1109
1110   /**
1111    * Used for instance by goto with prefix
1112    *
1113    * @param ht the Hashtable object containing the field names used to build
1114    * the position string ht has fieldName as key and valueStr as
1115    * value!
1116    *
1117    * @return the position string
1118    */

1119   public String JavaDoc getPositionString(Hashtable JavaDoc ht) {
1120      StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
1121      int cnt = 0;
1122      Iterator JavaDoc e = ht.keySet()
1123                           .iterator();
1124
1125      while (e.hasNext()) {
1126         String JavaDoc fieldName = (String JavaDoc) e.next();
1127         Field aField = getFieldByName(fieldName);
1128
1129         if (aField != null) {
1130            if (aField.hasIsKeySet() || aField.hasSortableSet()) {
1131               String JavaDoc fieldValue = (String JavaDoc) ht.get(fieldName);
1132
1133               if (cnt > 0) {
1134                  buf.append('-'); // control byte
1135
}
1136
1137               buf.append(createToken(aField, fieldValue));
1138               cnt++;
1139            } else {
1140               logCat.debug("provided goto field " + fieldName
1141                            + " is not key/search field!");
1142            }
1143         } else {
1144            logCat.error("provided goto field " + fieldName + " not found!");
1145         }
1146      }
1147
1148      return buf.toString();
1149   }
1150
1151
1152   /**
1153    * Get key position from the input hash table
1154    *
1155    * @param fvHT has field as key and FieldValue as value!
1156    *
1157    * @return the key position string
1158    *
1159    * @throws IllegalArgumentException DOCUMENT ME!
1160    */

1161   public String JavaDoc getPositionString(FieldValues fvHT) {
1162      String JavaDoc res = null;
1163      if (fvHT != null) {
1164         StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
1165         int cnt = 0;
1166         Iterator JavaDoc e = fvHT.keys();
1167
1168         while (e.hasNext()) {
1169            String JavaDoc fieldName = (String JavaDoc) e.next();
1170            FieldValue fv = fvHT.get(fieldName);
1171            Field f = fv.getField();
1172
1173            if (f.hasIsKeySet() || f.hasSortableSet()) {
1174               String JavaDoc value = fv.getFieldValue();
1175
1176               if (value == null) {
1177                  throw new IllegalArgumentException JavaDoc("wrong fields provided");
1178               }
1179
1180               if (cnt > 0) {
1181                  buf.append("-"); // control byte
1182
}
1183
1184               buf.append(createToken(f, value));
1185               cnt++;
1186            }
1187         }
1188
1189         res = buf.toString();
1190      }
1191      return res;
1192   }
1193
1194
1195   /**
1196    * Returns the FROM part of a query.
1197    *
1198    * @return the FROM part of a query
1199    */

1200   public String JavaDoc getQueryFrom() {
1201      return name;
1202   }
1203
1204
1205   /**
1206    * Returns the select part of a query.
1207    *
1208    * @param fieldsToSelect the vector containing the Field objects used to
1209    * build the elect part of the query
1210    *
1211    * @return the select part of a query
1212    */

1213   public String JavaDoc getQuerySelect(Vector JavaDoc fieldsToSelect) {
1214      if (fieldsToSelect != null) {
1215         StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
1216         int fieldsToSelectSize = fieldsToSelect.size();
1217
1218         // #checkme: do i need this when using Hotspot ?
1219
// we scroll through vector directly (no enumeration!)
1220
// to maintain correct order of elements
1221
for (int i = 0; i < fieldsToSelectSize; i++) {
1222            Field f = (Field) fieldsToSelect.elementAt(i);
1223            buf.append(f.getName());
1224            buf.append(", ");
1225         }
1226
1227         buf.deleteCharAt(buf.length() - 2);
1228
1229         return buf.toString();
1230      }
1231
1232      return "*";
1233   }
1234
1235
1236   /**
1237    * Prepares the Querystring for the select statement Order of parts: 1.
1238    * sqlFilter (fild in getDoSelectResultSet!) 2. where condition generated
1239    * from having / ordering fields (fild in populateWhereEqualsClause)
1240    * Retrieving the parameters in getDoSelectResultSet() must match this
1241    * order!
1242    *
1243    * @param fieldsToSelect vector of fields to be selected
1244    * @param fvEqual fieldValues representing values we are looking for
1245    * @param fvOrder fieldValues representing needs for order clauses
1246    * @param sqlFilter sql condition to and with the where clause
1247    * @param compareMode compare mode value for generating the order clause
1248    *
1249    * @return the query string
1250    */

1251   public String JavaDoc getSelectQuery(Vector JavaDoc fieldsToSelect,
1252                                FieldValue[] fvEqual,
1253                                FieldValue[] fvOrder,
1254                                String JavaDoc sqlFilter,
1255                                int compareMode) {
1256      StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
1257
1258      buf.append("SELECT ");
1259      buf.append(getQuerySelect(fieldsToSelect));
1260      buf.append(" FROM ");
1261      buf.append(getQueryFrom());
1262
1263      String JavaDoc s = getQueryWhere(fvEqual, fvOrder, compareMode);
1264
1265      if (!Util.isNull(s) || !Util.isNull(sqlFilter)) {
1266         buf.append(" WHERE ");
1267      }
1268
1269      // where condition from DbFormTag's sqlFilter attribute
1270
if (!Util.isNull(sqlFilter)) {
1271         buf.append(" ( ");
1272         buf.append(sqlFilter);
1273         buf.append(" ) ");
1274      }
1275
1276      // where condition generated from searching / ordering
1277
if (!Util.isNull(s)) {
1278         if (!Util.isNull(sqlFilter)) {
1279            buf.append(" AND ");
1280         }
1281
1282         buf.append(" ( ");
1283         buf.append(s);
1284         buf.append(" ) ");
1285      }
1286
1287      s = getQueryOrderBy(fvOrder);
1288
1289      if (s.length() > 0) {
1290         buf.append(" ORDER BY ");
1291         buf.append(s);
1292      }
1293
1294      logCat.info("::getSelectQuery - [" + buf.toString() + "]");
1295
1296      return buf.toString();
1297   }
1298
1299
1300   //------------------------------ SQL methods
1301
// ---------------------------------
1302

1303   /**
1304    * Get the SQL select statement.
1305    *
1306    * @return the SQL select statement
1307    */

1308   public String JavaDoc getSelectStatement() {
1309      StringBuffer JavaDoc queryBuf = new StringBuffer JavaDoc();
1310      queryBuf.append("SELECT ");
1311      queryBuf.append(getQuerySelect(fields));
1312      queryBuf.append(" FROM ");
1313      queryBuf.append(getQueryFrom());
1314      logCat.info(queryBuf.toString());
1315
1316      return queryBuf.toString();
1317   }
1318
1319
1320   /**
1321    * Set the table events object related to this table.
1322    *
1323    * @param tableEvents the table events object related to this table
1324    */

1325   public void setTableEvents(TableEvents tableEvents) {
1326      this.tableEvents = tableEvents;
1327      tableEvents.setTable(this);
1328   }
1329
1330
1331   /**
1332    * Get the table events object related to this table. <br>
1333    * If it is null (because user didn't specify custom events), set a new
1334    * TableEvents object and return its reference.
1335    *
1336    * @return the table events object related to this table
1337    */

1338   public TableEvents getTableEvents() {
1339      if (tableEvents == null) {
1340         tableEvents = new TableEvents();
1341      }
1342
1343      return tableEvents;
1344   }
1345
1346
1347   /**
1348    * Returns SQL update statement, used by updateEvent.
1349    *
1350    * @param fieldValues the Hashtable object containing the field values
1351    *
1352    * @return the SQL update statement
1353    */

1354   public String JavaDoc getUpdateStatement(FieldValues fieldValues) {
1355      StringBuffer JavaDoc queryBuf = new StringBuffer JavaDoc();
1356      queryBuf.append("UPDATE ");
1357      queryBuf.append(getQueryToChange());
1358      queryBuf.append(" SET ");
1359
1360      // list the names of fields and the place holder for their new values
1361
// important: these are the fields which are sent through the current
1362
// request;
1363
// this list may be only a subset of the field list,
1364
// it is not necessarily the complete field list of a table!
1365
boolean kommaNeeded = false;
1366      Iterator JavaDoc e = fieldValues.keys();
1367
1368      while (e.hasNext()) {
1369         String JavaDoc fieldName = (String JavaDoc) e.next();
1370
1371         if (kommaNeeded) {
1372            queryBuf.append(", ");
1373         } else {
1374            kommaNeeded = true;
1375         }
1376
1377         queryBuf.append(fieldName);
1378         queryBuf.append("= ?");
1379      }
1380
1381      queryBuf.append(" WHERE ");
1382      queryBuf.append(getWhereClauseForKeyFields());
1383      logCat.info(queryBuf.toString());
1384
1385      return queryBuf.toString();
1386   }
1387
1388
1389   /**
1390    * Build the WHERE clause string using the input field values.
1391    *
1392    * @param fv the array of FieldValue objects
1393    *
1394    * @return the WHERE clause string protected so that it can be tested
1395    */

1396   public String JavaDoc getWhereClause(FieldValue[] fv) {
1397      StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
1398
1399      if ((fv != null) && (fv.length > 0)) {
1400         // SM 2003-08-08: added brackets for each and-ed condition
1401
buf.append(" ( ");
1402
1403         for (int i = 0; i < fv.length; i++) {
1404            // depending on the value of isLogicalOR in FieldValue,
1405
// prefix the filter definition with either OR or AND
1406
// (Skip first entry!)
1407
if (i != 0) {
1408               if (fv[i].getLogicalOR()) {
1409                  buf.append(" OR ");
1410               } else {
1411                  buf.append(" ) AND ( ");
1412               }
1413            }
1414
1415            buf.append(getSQLExpression(fv[i]));
1416         }
1417
1418         buf.append(" ) ");
1419      }
1420
1421      return buf.toString();
1422   }
1423
1424
1425   // ----------------- some convenience methods
1426
// ---------------------------------------------
1427

1428   /**
1429    * Generates a part of the SQL where clause needed to select a distinguished
1430    * row form the table. This is done by querying for KEY VALUES !
1431    *
1432    * @return a part of the SQL where clause needed to select a distinguished
1433    * row form the table
1434    */

1435   public String JavaDoc getWhereClauseForKeyFields() {
1436      StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
1437      int cnt = this.getKey()
1438                             .size();
1439
1440      for (int i = 0; i < cnt; i++) {
1441         Field keyField = (Field) this.getKey()
1442                                      .elementAt(i);
1443
1444         // get the name of the encoded key field
1445
buf.append(keyField.getName());
1446         buf.append(" = ?");
1447
1448         if (i < (cnt - 1)) {
1449            buf.append(" AND ");
1450         }
1451      }
1452
1453      return buf.toString();
1454   }
1455
1456
1457   /**
1458    * adds a Field-Object to this table and puts it into othere datastructure
1459    * for further references (this method gets called from DbFormsConfig)
1460    *
1461    * @param field field to add
1462    *
1463    * @throws Exception DOCUMENT ME!
1464    */

1465   public void addCalcField(Field field) throws Exception JavaDoc {
1466      if (field.getType() == 0) {
1467         throw new Exception JavaDoc("no type!");
1468      }
1469
1470      field.setId(encodeFieldId(CALC_FIELD, calcFields.size()));
1471      field.setTable(this);
1472      calcFields.addElement(field);
1473
1474      // for quicker lookup by name:
1475
calcFieldsNameHash.put(field.getName(), field);
1476   }
1477
1478
1479   /**
1480    * Adds a Field-Object to this table and puts it into othere datastructure
1481    * for further references (this method gets called from DbFormsConfig)
1482    *
1483    * @param field the Field object to add
1484    *
1485    * @throws Exception DOCUMENT ME!
1486    */

1487   public void addField(Field field) throws Exception JavaDoc {
1488      if (field.getType() == 0) {
1489         throw new Exception JavaDoc("no type!");
1490      }
1491
1492      field.setId(encodeFieldId(DB_FIELD, fields.size()));
1493      field.setTable(this);
1494      fields.addElement(field);
1495
1496      // if the field is (part of) the key
1497
if (field.hasIsKeySet()) {
1498         logCat.info("wow - field " + getName() + "." + field.getName()
1499                     + " is a key");
1500         // use key not getKey! getKey will return key Vector of parent
1501
// table in case of query!
1502
key.addElement(field);
1503      } else {
1504         logCat.info("field " + getName() + "." + field.getName()
1505                     + " is NO key");
1506      }
1507
1508      // for quicker lookup by name:
1509
fieldNameHash.put(field.getName(), field);
1510
1511      // for quicker check for diskblobs
1512
if (field.getType() == FieldTypes.DISKBLOB) {
1513         diskblobs.addElement(field);
1514      }
1515   }
1516
1517
1518   /**
1519    * Adds a ForeignKey-Object to this table and puts it into othere
1520    * datastructure for further references (this method gets called from
1521    * DbFormsConfig)
1522    *
1523    * @param fk the foreign key object
1524    */

1525   public void addForeignKey(ForeignKey fk) {
1526      fk.setId(foreignKeys.size());
1527
1528      // add to vector containing all foreign keys:
1529
foreignKeys.addElement(fk);
1530
1531      // for quicker lookup by name:
1532
foreignKeyNameHash.put(fk.getName(), fk);
1533   }
1534
1535
1536   /**
1537    * Add an interceptor to this table.
1538    *
1539    * @param interceptor the interceptor to add
1540    */

1541   public void addInterceptor(Interceptor interceptor) {
1542      interceptors.addElement(interceptor);
1543   }
1544
1545
1546   /**
1547    * Determinates if this table contains a diskblob field. (this method is
1548    * used by DeleteEvent which needs to delete files referenced by a diskblob
1549    * field).
1550    *
1551    * @return true if this table contains a diskblob field, false otherwise
1552    */

1553   public boolean containsDiskblob() {
1554      return diskblobs.size() > 0;
1555   }
1556
1557
1558   /**
1559    * Column ["ASC" | "DESC"] {"," Column ["ASC" | "DESC"] } (if neither ASC
1560    * nor DESC follow "Col", then ASC is choosen as default). <br>
1561    * this method assures, that ALL KEY FIELDs are part of the order criteria,
1562    * in any case (independly from the order-Str). if necessary it appends
1563    * them. WHY: to ensure correct scrollig (not getting STUCK if the search
1564    * criteria are not "sharp" enough). <br>
1565    * #fixme - better explaination #fixme - determinate illegal input and
1566    * throw IllegalArgumentException
1567    *
1568    * @param order a String from JSP provided by the user in SQL-Style
1569    * @param request the request object
1570    * @param includeKeys true to include key fields, false otherwise
1571    *
1572    * @return ???
1573    */

1574   public FieldValue[] createOrderFieldValues(String JavaDoc order,
1575                                              HttpServletRequest JavaDoc request,
1576                                              boolean includeKeys) {
1577      Vector JavaDoc result = null;
1578
1579      if (request != null) {
1580         String JavaDoc paramStub = Constants.FIELDNAME_SORT + this.getId();
1581         Vector JavaDoc sortFields = ParseUtil.getParametersStartingWith(request,
1582                                                                 paramStub);
1583
1584         if (sortFields.size() > 0) {
1585            result = createOrderFVFromRequest(request, paramStub, sortFields);
1586         }
1587      }
1588
1589      // 20020703-HKK: use the default order if result.size == 0, not only if
1590
// result == null
1591
// This happens if all parameters with sort_ are set to none
1592
if (((result == null) || result.isEmpty())) {
1593         // 20021104-HKK: use default order from table if form has no order!
1594
if (order == null) {
1595            order = getOrderBy();
1596         }
1597
1598         result = createOrderFVFromAttribute(order);
1599         logCat.debug("@@@ 1");
1600
1601         for (int i = 0; i < result.size(); i++) {
1602            FieldValue fieldVal = (FieldValue) result.elementAt(i);
1603            logCat.debug("fieldValue " + fieldVal.toString());
1604         }
1605      }
1606
1607      if (includeKeys) {
1608         // scroll through keys and append to order criteria, if not already
1609
// included
1610
for (int i = 0; i < this.getKey()
1611                                       .size(); i++) {
1612            Field keyField = (Field) getKey()
1613                                          .elementAt(i);
1614            boolean found = false;
1615            int j = 0;
1616
1617            while (!found && (j < result.size())) {
1618               FieldValue fv = (FieldValue) result.elementAt(j);
1619
1620               if (fv.getField() == keyField) {
1621                  found = true;
1622               }
1623
1624               j++;
1625            }
1626
1627            if (!found) {
1628               result.addElement(FieldValue.createFieldValueForSorting(keyField,
1629                                                                       Constants.ORDER_ASCENDING));
1630            }
1631         }
1632      }
1633
1634      FieldValue[] resultArray = new FieldValue[result.size()];
1635      result.copyInto(resultArray);
1636      logCat.debug("@@@ 2");
1637
1638      for (int i = 0; i < resultArray.length; i++) {
1639         logCat.debug("fieldValue " + resultArray[i].toString());
1640      }
1641
1642      return resultArray;
1643   }
1644
1645
1646   //------------------------------ Old ResultSetVector stuff
1647
// ---------------------------------
1648

1649   /**
1650    * Do a constrained select.
1651    *
1652    * @param fvEqual FieldValue array used to restrict a set in a subform where
1653    * all "childFields" in the resultset match their respective
1654    * "parentFields" in main form
1655    * @param fvOrder FieldValue array used to build a cumulation of rules for
1656    * ordering (sorting) and restricting fields
1657    * @param sqlFilter sql condition to add to where clause
1658    * @param sqlFilterParams DOCUMENT ME!
1659    * @param compareMode the value of the compare mode
1660    * @param maxRows the max number of rows to manage
1661    * @param interceptorData the connection object
1662    *
1663    * @return a ResultSetVector object
1664    *
1665    * @throws SQLException if any error occurs
1666    */

1667   public ResultSetVector doConstrainedSelect(FieldValue[] fvEqual,
1668                                              FieldValue[] fvOrder,
1669                                              String JavaDoc sqlFilter,
1670                                              FieldValue[] sqlFilterParams,
1671                                              int compareMode,
1672                                              int maxRows,
1673                                              DbEventInterceptorData interceptorData)
1674                                       throws SQLException JavaDoc {
1675      String JavaDoc query = getSelectQuery(getFields(), fvEqual, fvOrder,
1676                                               sqlFilter, compareMode);
1677      PreparedStatement JavaDoc ps = interceptorData.getConnection()
1678                                            .prepareStatement(query);
1679      ps.setMaxRows(maxRows); // important when quering huge tables
1680

1681      ResultSet JavaDoc rs = getDoSelectResultSet(fvEqual, fvOrder,
1682                                                sqlFilterParams, compareMode, ps);
1683      ResultSetVector result = new ResultSetVector(this);
1684      result.addResultSet(interceptorData, rs);
1685      ps.close();
1686      logCat.info("::doConstrainedSelect - rsv size = " + result.size());
1687
1688      return result;
1689   }
1690
1691
1692   /**
1693    * perform free-form select query
1694    *
1695    * @param whereClause free-form whereClause to be appended to query
1696    * @param tableList the list of tables involved into the query
1697    * @param maxRows how many rows should be stored in the resultSet (zero
1698    * means unlimited)
1699    * @param interceptorData the active db connection to use
1700    *
1701    * @return the ResultSetVector object
1702    *
1703    * @throws SQLException if any error occurs
1704    */

1705   public ResultSetVector doFreeFormSelect(String JavaDoc whereClause,
1706                                           String JavaDoc tableList,
1707                                           int maxRows,
1708                                           DbEventInterceptorData interceptorData)
1709                                    throws SQLException JavaDoc {
1710      Statement JavaDoc stmt = interceptorData.getConnection()
1711                                      .createStatement();
1712      String JavaDoc query = getFreeFormSelectQuery(getFields(), whereClause,
1713                                               tableList);
1714      stmt.setMaxRows(maxRows); // important when quering huge tables
1715

1716      ResultSet JavaDoc rs;
1717
1718      try {
1719         rs = stmt.executeQuery(query);
1720      } catch (SQLException JavaDoc sqle) {
1721         SqlUtil.logSqlException(sqle);
1722         throw new SQLException JavaDoc(sqle.getMessage());
1723      }
1724
1725      ResultSetVector result = new ResultSetVector(this);
1726      result.addResultSet(interceptorData, rs);
1727
1728      // 20021115-HKK: resultset is closed in ResultSetVector()
1729
// rs.close();
1730
stmt.close();
1731      logCat.info("rsv size=" + result.size());
1732
1733      return result;
1734   }
1735
1736
1737   /**
1738    * in version 0.9 this method moved from FieldValue.fillWithValues to
1739    * Table.fillWithValues
1740    *
1741    * @param orderConstraint FieldValue array used to build a cumulation of
1742    * rules for ordering (sorting) and restricting fields
1743    * @param aPosition resultset position
1744    */

1745   public void fillWithValues(FieldValue[] orderConstraint,
1746                              String JavaDoc aPosition) {
1747      // 2003-03-29 HKK: Change from Hashtable to FieldValueTable
1748
FieldValues ht = getFieldValues(aPosition);
1749
1750      // 20021104-HKK: Error handling if aPosition is not given!
1751
if (ht != null) {
1752         logCat.info("*** parsing through: " + aPosition);
1753
1754         // then we copy some of those values into the orderConstraint
1755
for (int i = 0; i < orderConstraint.length; i++) {
1756            Field f = orderConstraint[i].getField();
1757
1758            if (f != null) {
1759               FieldValue aFieldValue = ht.get(f.getName());
1760
1761               if (aFieldValue != null) {
1762                  orderConstraint[i].setFieldValue(aFieldValue.getFieldValue());
1763               } else {
1764                  logCat.warn("position entry has null value:" + f.getName());
1765               }
1766            }
1767         }
1768      }
1769   }
1770
1771
1772   /**
1773    * Check if this table has got interceptors.
1774    *
1775    * @return true if the table contains interceptors, false otherwise
1776    */

1777   public boolean hasInterceptors() {
1778      return (getConfig() != null && getConfig().hasInterceptors())
1779             || ((interceptors != null) && (interceptors.size() > 0));
1780   }
1781
1782
1783   /**
1784    * Checks if there exists a granted-privileges object and if so it queries
1785    * if access/operation is possible
1786    *
1787    * @param request the request object
1788    * @param privileg the privilege value
1789    *
1790    * @return true if the user has got privileges over this table, false
1791    * otherwise
1792    */

1793   public boolean hasUserPrivileg(HttpServletRequest JavaDoc request,
1794                                  int privileg) {
1795      return (grantedPrivileges == null) ? true
1796                                         : grantedPrivileges.hasUserPrivileg(request,
1797                                                                             privileg);
1798   }
1799
1800
1801   /**
1802    * This method generates a datastructure holding sorting information from
1803    * "orderBy" clause in XML-config.
1804    */

1805   public void initDefaultOrder() {
1806      // if developer specified no orderBy in XML, then we set the KEYs as
1807
// DEFAULT ORDER
1808
if (orderBy == null) {
1809         initDefaultOrderFromKeys();
1810      } else {
1811         // build the datastructure, containing Fields, and infos about sort
1812
defaultOrder = createOrderFieldValues(orderBy, null, true);
1813      }
1814
1815      logCat.info("Table.initDefaultOrder done.");
1816   }
1817
1818
1819   /**
1820    * maps child fields to parent fields
1821    *
1822    * @param parentTable the parent table
1823    * @param parentFieldString field names in parent table
1824    * @param childFieldString field names in child table
1825    * @param aPosition position to map as position string
1826    *
1827    * @return FieldValues with result
1828    *
1829    * @throws IllegalArgumentException DOCUMENT ME!
1830    */

1831   public FieldValues mapChildFieldValues(Table parentTable,
1832                                          String JavaDoc parentFieldString,
1833                                          String JavaDoc childFieldString,
1834                                          String JavaDoc aPosition) {
1835      // 1 to n fields may be mapped
1836
Vector JavaDoc childFieldNames = StringUtil.splitString(childFieldString, ",;~");
1837      Vector JavaDoc parentFieldNames = StringUtil.splitString(parentFieldString, ",;~");
1838
1839      // do some basic checks
1840
// deeper checks like Datatyp-compatibility,etc not done yet
1841
int len = childFieldNames.size();
1842
1843      if ((len == 0) || (len != parentFieldNames.size())) {
1844         return null;
1845      }
1846
1847      // 2003-03-29 HKK: Change from Hashtable to FieldValueTable
1848
FieldValues ht = parentTable.getFieldValues(aPosition);
1849
1850      if (ht == null) {
1851         return null;
1852      }
1853
1854      FieldValues childFieldValues = new FieldValues();
1855
1856      for (int i = 0; i < len; i++) {
1857         String JavaDoc parentFieldName = (String JavaDoc) parentFieldNames.elementAt(i);
1858         Field parentField = parentTable.getFieldByName(parentFieldName);
1859         String JavaDoc childFieldName = (String JavaDoc) childFieldNames.elementAt(i);
1860         Field childField = this.getFieldByName(childFieldName);
1861         FieldValue aFieldValue = ht.get(parentField.getName());
1862
1863         if (aFieldValue == null) {
1864            throw new IllegalArgumentException JavaDoc("ERROR: Make sure that field "
1865                                               + parentField.getName()
1866                                               + " is a KEY of the table "
1867                                               + parentTable.getName()
1868                                               + "! Otherwise you can not use it as PARENT/CHILD LINK argument!");
1869         }
1870
1871         String JavaDoc currentParentFieldValue = aFieldValue.getFieldValue();
1872         childFieldValues.put(new FieldValue(childField, currentParentFieldValue));
1873      }
1874
1875      return childFieldValues;
1876   }
1877
1878
1879   /**
1880    * POPULATES a part of the SQL where clause needed to select a distinguished
1881    * row form the table using values endcoded in a string. <br>
1882    * #fixme: replace seperator-based tokenization by better algoithm!
1883    *
1884    * @param keyValuesStr the position string
1885    * @param ps the PreparedStatement object
1886    * @param startColumn PreparedStatement start column
1887    *
1888    * @throws SQLException if any error occurs
1889    */

1890   public void populateWhereClauseWithKeyFields(String JavaDoc keyValuesStr,
1891                                                PreparedStatement JavaDoc ps,
1892                                                int startColumn)
1893                                         throws SQLException JavaDoc {
1894      int col = startColumn;
1895
1896      // then we list the values of the key-fields, so that the WHERE clause
1897
// matches the right dataset
1898
// 2003-03-29 HKK: Change from Hashtable to FieldValueTable
1899
FieldValues keyValuesHt = getFieldValues(keyValuesStr);
1900      int keyLength = this.getKey()
1901                                  .size();
1902
1903      for (int i = 0; i < keyLength; i++) {
1904         Field curField = (Field) this.getKey()
1905                                           .elementAt(i);
1906         FieldValue aFieldValue = keyValuesHt.get(curField.getName());
1907         Object JavaDoc value = aFieldValue.getFieldValueAsObject();
1908         JDBCDataHelper.fillWithData(ps, curField.getEscaper(), col, value,
1909                                     curField.getType(),
1910                                     this.getBlobHandlingStrategy());
1911         col++;
1912      }
1913   }
1914
1915
1916   /**
1917    * situation: we have built a query (involving the getWhereEqualsClause()
1918    * method) and now we want to prepare the statemtent - provide actual
1919    * values for the the '?' placeholders
1920    *
1921    * @param fv the array of FieldValue objects
1922    * @param ps the PreparedStatement object
1923    * @param curCol the current PreparedStatement column; points to a
1924    * PreparedStatement xxx value
1925    *
1926    * @return the current column value
1927    *
1928    * @exception SQLException if any error occurs
1929    */

1930   public int populateWhereEqualsClause(FieldValue[] fv,
1931                                        PreparedStatement JavaDoc ps,
1932                                        int curCol)
1933                                 throws SQLException JavaDoc {
1934      if ((fv != null) && (fv.length > 0)) {
1935         for (int i = 0; i < fv.length; i++) {
1936            curCol = fillPreparedStatement(fv[i], ps, curCol);
1937         }
1938      }
1939
1940      return curCol;
1941   }
1942
1943
1944   /**
1945    * Process the interceptor objects related to this table.
1946    *
1947    * @param action DOCUMENT ME!
1948    * @param data the request object
1949    *
1950    * @return DOCUMENT ME!
1951    *
1952    * @throws SQLException if any error occurs
1953    */

1954   public int processInterceptors(int action,
1955                                  DbEventInterceptorData data)
1956                           throws SQLException JavaDoc {
1957      String JavaDoc s;
1958
1959      try {
1960         Vector JavaDoc allInterceptors = getInterceptors();
1961         int interceptorsCnt = allInterceptors.size();
1962
1963         for (int i = 0; i < interceptorsCnt; i++) {
1964            Interceptor interceptor = (Interceptor) allInterceptors
1965                                             .elementAt(i);
1966            Class JavaDoc interceptorClass = Class.forName(interceptor
1967                                                                .getClassName());
1968            DbEventInterceptor dbi = (DbEventInterceptor) interceptorClass
1969                                     .newInstance();
1970
1971            // J.Peer 03/18/2004 - plug in some additional config data for
1972
// interceptor
1973
dbi.setParameterMap(interceptor.getParameterMap());
1974
1975            // (Sunil_Mishra@adp.com) - The return type to check for the
1976
// IGNORE_OPERATION
1977
int operation = DbEventInterceptor.GRANT_OPERATION;
1978            String JavaDoc denyMessage = null;
1979
1980            if (action == DbEventInterceptor.PRE_INSERT) {
1981               operation = dbi.preInsert(data);
1982               denyMessage = "dbforms.events.insert.nogrant";
1983            } else if (action == DbEventInterceptor.POST_INSERT) {
1984               dbi.postInsert(data);
1985            } else if (action == DbEventInterceptor.PRE_UPDATE) {
1986               operation = dbi.preUpdate(data);
1987               denyMessage = "dbforms.events.update.nogrant";
1988            } else if (action == DbEventInterceptor.POST_UPDATE) {
1989               dbi.postUpdate(data);
1990            } else if (action == DbEventInterceptor.PRE_DELETE) {
1991               operation = dbi.preDelete(data);
1992               denyMessage = "dbforms.events.delete.nogrant";
1993            } else if (action == DbEventInterceptor.POST_DELETE) {
1994               dbi.postDelete(data);
1995            } else if (action == DbEventInterceptor.PRE_SELECT) {
1996               operation = dbi.preSelect(data);
1997               denyMessage = "dbforms.events.view.nogrant";
1998            } else if (action == DbEventInterceptor.POST_SELECT) {
1999               dbi.postSelect(data);
2000            } else if (action == DbEventInterceptor.PRE_ADDROW) {
2001               operation = dbi.preAddRow(data);
2002               denyMessage = "dbforms.events.addrow.nogrant";
2003            } else if (action == DbEventInterceptor.POST_ADDROW) {
2004               dbi.postAddRow(data);
2005            }
2006
2007            switch (operation) {
2008               case DbEventInterceptor.DENY_OPERATION:
2009                  s = MessageResourcesInternal.getMessage(denyMessage,
2010                                                          data.getRequest().getLocale(),
2011                                                          new String JavaDoc[] {
2012                                                             getName()
2013                                                          });
2014                  throw new SQLException JavaDoc(s);
2015
2016               case DbEventInterceptor.IGNORE_OPERATION:
2017                  return operation;
2018
2019               default:
2020                  break;
2021            }
2022         }
2023      } catch (ClassNotFoundException JavaDoc cnfe) {
2024         logCat.warn(" ClassNotFoundException : " + cnfe.getMessage());
2025         throw new SQLException JavaDoc(cnfe.getMessage());
2026      } catch (InstantiationException JavaDoc ie) {
2027         logCat.warn(" InstantiationException : " + ie.getMessage());
2028         throw new SQLException JavaDoc(ie.getMessage());
2029      } catch (IllegalAccessException JavaDoc iae) {
2030         logCat.warn(" IllegalAccessException : " + iae.getMessage());
2031         throw new SQLException JavaDoc(iae.getMessage());
2032      } catch (SQLException JavaDoc sqle) {
2033         throw sqle;
2034      } catch (MultipleValidationException ve) {
2035         throw new SQLException JavaDoc(ve.getMessage());
2036      } catch (ValidationException ve) {
2037         throw new SQLException JavaDoc(ve.getMessage());
2038      }
2039
2040      return DbEventInterceptor.GRANT_OPERATION;
2041   }
2042
2043
2044   //------------------------------ utility / helper methods
2045
// ---------------------------------
2046

2047   /**
2048    * This metod is useful for logging / debugging purposes only.
2049    *
2050    * @return a string containing the Table name and field values
2051    */

2052   public String JavaDoc toString() {
2053      StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
2054      buf.append("\nname=");
2055      buf.append(name);
2056      buf.append(" ");
2057      buf.append("\nid=");
2058      buf.append(String.valueOf(getId()));
2059      buf.append(" ");
2060
2061      if (getFields() != null) {
2062         for (int i = 0; i < getFields()
2063                                      .size(); i++) {
2064            Field f = (Field) getFields()
2065                                 .elementAt(i);
2066            buf.append("\nfield: ");
2067            buf.append(f.toString());
2068         }
2069      }
2070
2071      return buf.toString();
2072   }
2073
2074
2075   /**
2076    * Returns the part of the orderby-clause represented by this FieldValue
2077    * object. <br>
2078    * (ASC will be not printed because it is defined DEFAULT in SQL if there
2079    * are RDBMS which do not tolerate this please let me know; then i'll
2080    * change it).
2081    *
2082    * @param fvOrder FieldValue array used to build a cumulation of rules for
2083    * ordering (sorting) and restricting fields
2084    *
2085    * @return the part of the orderby-clause represented by this FieldValue
2086    * object
2087    */

2088   protected String JavaDoc getQueryOrderBy(FieldValue[] fvOrder) {
2089      StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
2090
2091      if (fvOrder != null) {
2092         for (int i = 0; i < fvOrder.length; i++) {
2093            buf.append(fvOrder[i].getField().getName());
2094
2095            if (fvOrder[i].getSortDirection() == Constants.ORDER_DESCENDING) {
2096               buf.append(" DESC");
2097            }
2098
2099            if (i < (fvOrder.length - 1)) {
2100               buf.append(",");
2101            }
2102         }
2103      }
2104
2105      return buf.toString();
2106   }
2107
2108
2109   /**
2110    * Returns the FROM part of a insert/delete/update query.
2111    *
2112    * @return the FROM part of a insert/delete/update query
2113    */

2114   protected String JavaDoc getQueryToChange() {
2115      return getQueryFrom();
2116   }
2117
2118
2119   /**
2120    * Returns the WHERE part of a query.
2121    *
2122    * @param fvEqual FieldValue array used to restrict a set in a subform where
2123    * all "childFields" in the resultset match their respective
2124    * "parentFields" in main form
2125    * @param fvOrder FieldValue array used to build a cumulation of rules for
2126    * ordering (sorting) and restricting fields
2127    * @param compareMode compare mode value for generating the order clause
2128    *
2129    * @return the WHERE part of a query
2130    */

2131   protected String JavaDoc getQueryWhere(FieldValue[] fvEqual,
2132                                  FieldValue[] fvOrder,
2133                                  int compareMode) {
2134      boolean firstTermExists = false;
2135      StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
2136
2137      // build the first term;
2138
if (!FieldValue.isNull(fvEqual)) {
2139         // check if the fieldvalues contain _search_ information
2140
buf.append(" ( ");
2141
2142         if (fvEqual[0].getSearchMode() == Constants.SEARCHMODE_NONE) {
2143            buf.append(getWhereClause(fvEqual));
2144         } else {
2145            buf.append(getWhereEqualsSearchClause(fvEqual));
2146         }
2147
2148         buf.append(" ) ");
2149         firstTermExists = true;
2150      }
2151
2152      // build the second term;
2153
// this SHOULD be the WHERE clause which restricts
2154
// the query to rows coming AFTER the row containing the actual data.
2155
if (!FieldValue.isNull(fvOrder)
2156                && (compareMode != Constants.COMPARE_NONE)) {
2157         buf.append(firstTermExists ? " AND ( "
2158                                    : "");
2159         buf.append(getWhereAfterClause(fvOrder, compareMode));
2160         buf.append(firstTermExists ? " ) "
2161                                    : "");
2162      }
2163
2164      return buf.toString();
2165   }
2166
2167
2168   /**
2169    * DOCUMENT ME!
2170    *
2171    * @param type DOCUMENT ME!
2172    * @param id DOCUMENT ME!
2173    *
2174    * @return DOCUMENT ME!
2175    */

2176   protected boolean checkFieldId(int type,
2177                                  int aid) {
2178      int i = aid / MAXFIELDS;
2179      return i == type;
2180   }
2181
2182
2183   /**
2184    * DOCUMENT ME!
2185    *
2186    * @param type DOCUMENT ME!
2187    * @param id DOCUMENT ME!
2188    *
2189    * @return DOCUMENT ME!
2190    */

2191   protected int decodeFieldId(int type,
2192                               int aid) {
2193      return aid - (type * MAXFIELDS);
2194   }
2195
2196
2197   /**
2198    * DOCUMENT ME!
2199    *
2200    * @param type DOCUMENT ME!
2201    * @param id DOCUMENT ME!
2202    *
2203    * @return DOCUMENT ME!
2204    */

2205   protected int encodeFieldId(int type,
2206                               int aid) {
2207      return (type * MAXFIELDS) + aid;
2208   }
2209
2210
2211   /**
2212    * returns an SQLExpression based on the given FieldValue
2213    *
2214    * @param fv the FieldValue
2215    *
2216    * @return string holding the SQL Expression
2217    */

2218   private String JavaDoc getSQLExpression(FieldValue fv) {
2219      StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
2220
2221      // 20021104-HKK: Check for expression.
2222
Field f = fv.getField();
2223      String JavaDoc fieldName = Util.isNull(f.getExpression()) ? f.getName()
2224                                                        : f.getExpression();
2225      buf.append(fieldName);
2226
2227      // Check what type of operator is required
2228
switch (fv.getOperator()) {
2229         case Constants.FILTER_EQUAL:
2230            buf.append(" = ");
2231            buf.append(" ? ");
2232
2233            break;
2234
2235         case Constants.FILTER_NOT_EQUAL:
2236            buf.append(" <> ");
2237            buf.append(" ? ");
2238
2239            break;
2240
2241         case Constants.FILTER_GREATER_THEN:
2242            buf.append(" > ");
2243            buf.append(" ? ");
2244
2245            break;
2246
2247         case Constants.FILTER_SMALLER_THEN:
2248            buf.append(" < ");
2249            buf.append(" ? ");
2250
2251            break;
2252
2253         case Constants.FILTER_GREATER_THEN_EQUAL:
2254            buf.append(" >= ");
2255            buf.append(" ? ");
2256
2257            break;
2258
2259         case Constants.FILTER_SMALLER_THEN_EQUAL:
2260            buf.append(" <= ");
2261            buf.append(" ? ");
2262
2263            break;
2264
2265         case Constants.FILTER_LIKE:
2266
2267            if (f.getType() == FieldTypes.CHAR) {
2268               buf.append(" LIKE ");
2269            } else {
2270               buf.append(" = ");
2271            }
2272
2273            buf.append(" ? ");
2274
2275            break;
2276
2277         case Constants.FILTER_NULL:
2278            buf.append(" IS NULL ");
2279
2280            break;
2281
2282         case Constants.FILTER_NOT_NULL:
2283            buf.append(" IS NOT NULL ");
2284
2285            break;
2286
2287         case Constants.FILTER_EMPTY:
2288
2289            if (f.getType() == FieldTypes.CHAR) {
2290               buf.append(" = '' ");
2291               buf.append(" OR ");
2292            }
2293
2294            buf.append(fieldName);
2295            buf.append(" IS NULL ");
2296
2297            break;
2298
2299         case Constants.FILTER_NOT_EMPTY:
2300
2301            if (f.getType() == FieldTypes.CHAR) {
2302               buf.append(" <> '' ");
2303               buf.append(" OR ");
2304            }
2305
2306            buf.append(fieldName);
2307            buf.append(" IS NOT NULL ");
2308
2309            break;
2310      }
2311
2312      return buf.toString();
2313   }
2314
2315
2316   /**
2317    * situation: we have an array of fieldvalues which represents actual values
2318    * of order-determinating-fields. we want to build a part of the WHERE
2319    * clause which restricts the query to rows coming AFTER the row containing
2320    * the actual data. <br>
2321    * shortly described the following rule is applied:
2322    * <pre>
2323    *
2324    *
2325    *
2326    *
2327    *
2328    *
2329    *
2330    *
2331    *
2332    * +--------------------------------------------------------------------------------------------------+
2333    * | RULE = R1 AND R2 AND ... AND Rn |
2334    * | Ri = fi OpA(i) fi* OR f(i-1) OpB(i-1) f(i-1)* OR f(i-2) OpB(i-2) f(i-2)* OR ... OR f1 OpB f1* |
2335    * +--------------------------------------------------------------------------------------------------+
2336    * For background info email joepeer@wap-force.net
2337    *
2338    *
2339    *
2340    *
2341    *
2342    *
2343    *
2344    *
2345    *
2346    * </pre>
2347    * IMPORTANT NOTE: the indizes of the fv-array indicate implicitly the
2348    * order-priority of the fields. <br>
2349    * example: if we have ORDER BY id,name,age -> then fv[0] should contain
2350    * field id, fv[1] should contain field name, fv[2] should contain field
2351    * age
2352    *
2353    * @param fv the array of FieldValue objects
2354    * @param compareMode the comparison mode
2355    *
2356    * @return _part_ of a WHERE-clause
2357    */

2358   private String JavaDoc getWhereAfterClause(FieldValue[] fv,
2359                                      int compareMode) {
2360      String JavaDoc conj;
2361      String JavaDoc disj;
2362      String JavaDoc opA1;
2363      String JavaDoc opA2;
2364      String JavaDoc opB1;
2365      String JavaDoc opB2;
2366
2367      // COMPARE_INCLUSIVE
2368
if (compareMode == Constants.COMPARE_INCLUSIVE) {
2369         opA1 = ">=";
2370         opA2 = "<=";
2371         opB1 = ">";
2372         opB2 = "<";
2373         conj = " AND ";
2374         disj = " OR ";
2375      } else {
2376         opA1 = ">";
2377         opA2 = "<";
2378         opB1 = ">=";
2379         opB2 = "<=";
2380         conj = " OR ";
2381         disj = " AND ";
2382      }
2383
2384      StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
2385
2386      if ((fv != null) && (fv.length > 0)) {
2387         // generate the Ri's
2388
for (int i = 0; i < fv.length; i++) {
2389            // generate a "fi OpA(i) fi*"
2390
buf.append("(");
2391            buf.append(fv[i].getField().getName());
2392            buf.append((fv[i].getSortDirection() == Constants.ORDER_ASCENDING)
2393                       ? opA1
2394                       : opA2);
2395
2396            // OpA
2397
buf.append(" ? ");
2398
2399            // generate the "f(i-1) OpB(i-1) f(i-1)* OR f(i-2) OpB(i-2)
2400
// f(i-2)* OR ... OR f1 OpB f1*"
2401
if (i > 0) {
2402               for (int j = i - 1; j >= 0; j--) {
2403                  buf.append(disj);
2404                  buf.append(fv[j].getField().getName());
2405                  buf.append((fv[j].getSortDirection() == Constants.ORDER_ASCENDING)
2406                             ? opB1
2407                             : opB2);
2408
2409                  // OpB
2410
buf.append(" ? ");
2411               }
2412            }
2413
2414            buf.append(" ) ");
2415
2416            if (i < (fv.length - 1)) {
2417               buf.append(conj);
2418
2419               // link the R's together (conjunction)
2420
}
2421         }
2422      }
2423
2424      return buf.toString();
2425   }
2426
2427
2428   /**
2429    * situation: we have an array of fieldvalues (== fields + actual value )
2430    * with search information and we want to build a where - clause [that
2431    * should restrict the resultset in matching to the search fields].
2432    * <pre>
2433    *
2434    *
2435    *
2436    *
2437    *
2438    *
2439    *
2440    *
2441    *
2442    * convention: index 0-n =&gt; AND
2443    * index (n+1)-m =&gt; OR
2444    * examples
2445    * (A = 'meier' AND X = 'joseph') AND (AGE = '10')
2446    * (A = 'meier' ) AND (X = 'joseph' OR AGE = '10')
2447    * (X = 'joseph' OR AGE = '10')
2448    * (A = 'meier' AND X = 'joseph')
2449    * for comparing to code:
2450    * 1 2 3 2 4 5 6 2 7
2451    * ( A = 'smith' AND X LIKE 'jose%' ) AND ( AGE = '10' )
2452    *
2453    *
2454    *
2455    *
2456    *
2457    *
2458    *
2459    *
2460    *
2461    * </pre>
2462    *
2463    * @param fv Description of the Parameter
2464    *
2465    * @return _part_ of a WHERE-clause
2466    *
2467    * @todo hkk checkme: implementation is different to comment! comment says
2468    * that all or fields will be anded to all and fields (second
2469    * example!) implementation do an or instead????
2470    */

2471   private String JavaDoc getWhereEqualsSearchClause(FieldValue[] fv) {
2472      StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
2473
2474      if ((fv != null) && (fv.length > 0)) {
2475         int mode;
2476         int oldMode = -1;
2477
2478         for (int i = 0; i < fv.length; i++) {
2479            mode = fv[i].getSearchMode();
2480
2481            if (oldMode != mode) {
2482               oldMode = mode;
2483               buf.append("(");
2484
2485               // 1, 6
2486
}
2487
2488            // 2, i.e "A = 'smith'" or "X LIKE 'jose%'"
2489
buf.append(getSQLExpression(fv[i]));
2490
2491            if ((i < (fv.length - 1)) && (fv[i + 1].getSearchMode() == mode)) {
2492               buf.append((mode == Constants.SEARCHMODE_AND) ? "AND "
2493                                                             : "OR ");
2494
2495               // 3
2496
} else {
2497               //if(i==fv.length-1 || fv[i+1].getSearchMode()!=mode) {
2498
buf.append(")");
2499
2500               // 4, 7
2501
if (i != (fv.length - 1)) {
2502                  buf.append(" OR ");
2503
2504                  // 5 #checkme
2505
}
2506            }
2507         }
2508      }
2509
2510      return buf.toString();
2511   }
2512
2513
2514   /**
2515    * The orderBy clause usually defaults to ASCending order. A user may add,
2516    * if we/she wishes the keyword ASC (ascending) or DESC (descending) to
2517    * specify a particular direction. <br>
2518    * Code in this method parses the orderBy clause and finds an occurence of
2519    * either ASC or DESC. Suppose your field name is "DESCRIPTION" !<br>
2520    * This name contains "DESC" therefore causing unexpected behaviour. This
2521    * bug fix consists of fine-tunning the parsing function to take into
2522    * consideration the sequence of parameters: 1-Field 2-Command
2523    *
2524    * @param order order string
2525    *
2526    * @return a vector of Field objects
2527    */

2528   private Vector JavaDoc createOrderFVFromAttribute(String JavaDoc order) {
2529      Vector JavaDoc result = new Vector JavaDoc();
2530
2531      if (order != null) {
2532         StringTokenizer JavaDoc st = new StringTokenizer JavaDoc(order, ",");
2533
2534         while (st.hasMoreTokens()) {
2535            //Remove leading and trailing white space characters.
2536
String JavaDoc token = st.nextToken()
2537                             .trim();
2538            logCat.info("token = " + token);
2539
2540            int sortDirection = Constants.ORDER_ASCENDING;
2541
2542            // we propose the default
2543
//Separate field from command
2544
int index = token.indexOf(" ");
2545
2546            // Blank space used between field and command
2547
if (index != -1) // Do we have a command, if not assume ASC order
2548
{
2549               String JavaDoc command = token.substring(index)
2550                                     .toUpperCase();
2551               int pos = command.indexOf("ASC");
2552
2553               if (pos == -1) // ASC not found, try descending
2554
{
2555                  pos = command.indexOf("DESC");
2556
2557                  if (index != -1) {
2558                     sortDirection = Constants.ORDER_DESCENDING;
2559
2560                     // ... we set DESC.
2561
}
2562               }
2563            }
2564
2565            String JavaDoc fieldName;
2566
2567            if (index == -1) {
2568               fieldName = token.trim();
2569            } else {
2570               fieldName = token.substring(0, index)
2571                                .trim();
2572            }
2573
2574            Field f = this.getFieldByName(fieldName);
2575
2576            if (f != null) {
2577               FieldValue fv = FieldValue.createFieldValueForSorting(f,
2578                                                                     sortDirection);
2579               logCat.info("Field '" + fieldName + "' is ordered in mode:"
2580                           + sortDirection);
2581               result.addElement(fv);
2582            }
2583         }
2584      }
2585
2586      return result;
2587   }
2588
2589
2590   /**
2591    * DOCUMENT ME!
2592    *
2593    * @param request
2594    * @param paramStub
2595    * @param sortFields
2596    *
2597    * @return
2598    */

2599   private Vector JavaDoc createOrderFVFromRequest(HttpServletRequest JavaDoc request,
2600                                           String JavaDoc paramStub,
2601                                           Vector JavaDoc sortFields) {
2602      Vector JavaDoc result = new Vector JavaDoc();
2603      int fieldIndex = paramStub.length() + 1;
2604
2605      // "sort_1" -> fieldindex= 8 (length of paramStub "order_1" is 7)
2606
for (int i = 0; i < sortFields.size(); i++) {
2607         String JavaDoc dataParam = (String JavaDoc) sortFields.elementAt(i);
2608         int fieldId = Integer.parseInt(dataParam.substring(fieldIndex));
2609         String JavaDoc sortState = ParseUtil.getParameter(request, dataParam);
2610         logCat.info("### dataparam=" + dataParam);
2611         logCat.info("### fieldId=" + fieldId);
2612         logCat.info("### sortState=" + sortState);
2613
2614         if (sortState.equalsIgnoreCase("asc")
2615                   || sortState.equalsIgnoreCase("desc")) {
2616            int sortDirection = sortState.equalsIgnoreCase("asc")
2617                                ? Constants.ORDER_ASCENDING
2618                                : Constants.ORDER_DESCENDING;
2619            FieldValue fv = FieldValue.createFieldValueForSorting(getField(fieldId),
2620                                                                  sortDirection);
2621            result.addElement(fv);
2622         }
2623      }
2624
2625      return result;
2626   }
2627
2628
2629   //------------------------------ dealing with Postion and key Strings
2630
// ---------------------------------
2631

2632   /**
2633    * Creates a token string with the format:
2634    * <pre>
2635    *
2636    *
2637    *
2638    *
2639    *
2640    *
2641    *
2642    *
2643    *
2644    * field.id : field.length : field.value
2645    *
2646    *
2647    *
2648    *
2649    *
2650    *
2651    *
2652    *
2653    *
2654    * </pre>
2655    *
2656    * @param field the field object
2657    * @param fieldValue the field value
2658    *
2659    * @return the token string
2660    */

2661   private String JavaDoc createToken(Field field,
2662                              String JavaDoc fieldValue) {
2663      StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
2664
2665      buf.append(field.getId());
2666      buf.append(":");
2667
2668      if (!Util.isNull(fieldValue)) {
2669         buf.append(fieldValue.length());
2670         buf.append(":");
2671         buf.append(fieldValue);
2672      } else {
2673         buf.append(0);
2674         buf.append(":");
2675      }
2676
2677      return buf.toString();
2678   }
2679
2680
2681   /**
2682    * Fill the input PreparedStatement object
2683    *
2684    * @param cur the FieldValue object
2685    * @param ps the PreparedStatement object
2686    * @param curCol the current PreparedStatement column; points to a
2687    * PreparedStatement xxx value
2688    *
2689    * @return DOCUMENT ME!
2690    *
2691    * @exception SQLException if any error occurs
2692    */

2693   private int fillPreparedStatement(FieldValue cur,
2694                                     PreparedStatement JavaDoc ps,
2695                                     int curCol)
2696                              throws SQLException JavaDoc {
2697      logCat.info("setting col " + curCol + " with name "
2698                  + cur.getField().getName() + " to value "
2699                  + cur.getFieldValue() + " of type "
2700                  + cur.getField().getType() + " operator " + cur.getOperator());
2701
2702      Field curField = cur.getField();
2703      Object JavaDoc curValue = cur.getFieldValueAsObject();
2704
2705      // 20020703-HKK: Extending search algorithm with WEAK_START, WEAK_END,
2706
// WEAK_START_END
2707
// results in like '%search', 'search%', '%search%'
2708
if (curField.getType() == FieldTypes.CHAR) {
2709         String JavaDoc valueStr = cur.getFieldValue();
2710
2711         switch (cur.getSearchAlgorithm()) {
2712            case Constants.SEARCH_ALGO_WEAK_START:
2713               valueStr = '%' + valueStr;
2714
2715               break;
2716
2717            case Constants.SEARCH_ALGO_WEAK_END:
2718               valueStr = valueStr + '%';
2719
2720               break;
2721
2722            case Constants.SEARCH_ALGO_WEAK_START_END:
2723               valueStr = '%' + valueStr + '%';
2724
2725               break;
2726         }
2727
2728         curValue = valueStr;
2729      }
2730
2731      switch (cur.getOperator()) {
2732         case Constants.FILTER_NULL:
2733            break;
2734
2735         case Constants.FILTER_NOT_NULL:
2736            break;
2737
2738         case Constants.FILTER_EMPTY:
2739            break;
2740
2741         case Constants.FILTER_NOT_EMPTY:
2742            break;
2743
2744         default:
2745            JDBCDataHelper.fillWithData(ps, curField.getEscaper(), curCol,
2746                                        curValue, curField.getType(),
2747                                        getBlobHandlingStrategy());
2748            curCol++;
2749      }
2750
2751      return curCol;
2752   }
2753
2754
2755   /**
2756    * This method generated a datastructure holding sorting information from
2757    * "orderBy" only the keys are used as order criteria. By default all
2758    * ascending (check SQL spec + docu).
2759    */

2760   private void initDefaultOrderFromKeys() {
2761      defaultOrder = new FieldValue[getKey()
2762                                       .size()];
2763
2764      for (int i = 0; i < this.getKey()
2765                                    .size(); i++) {
2766         Field keyField = (Field) getKey()
2767                                     .elementAt(i);
2768         defaultOrder[i] = FieldValue.createFieldValueForSorting(keyField,
2769                                                                 Constants.ORDER_ASCENDING);
2770      }
2771
2772      logCat.info("Table.initDefaultOrderfromKey done.");
2773   }
2774
2775
2776   /**
2777    * situation: we have built a query (involving the getWhereEqualsClause()
2778    * method) and now we want to prepare the statemtent - provide actual
2779    * values for the the '?' placeholders.
2780    *
2781    * @param fv the array of FieldValue objects
2782    * @param ps the PreparedStatement object
2783    * @param curCol the current PreparedStatement column; points to a
2784    * PreparedStatement xxx value
2785    *
2786    * @return the value of the current column
2787    *
2788    * @exception SQLException if any error occurs
2789    */

2790   private int populateWhereAfterClause(FieldValue[] fv,
2791                                        PreparedStatement JavaDoc ps,
2792                                        int curCol)
2793                                 throws SQLException JavaDoc {
2794      if ((fv != null) && (fv.length > 0)) {
2795         // populate the Ri's
2796
for (int i = 0; i < fv.length; i++) {
2797            // populate a "fi OpA(i) fi*"
2798
curCol = fillPreparedStatement(fv[i], ps, curCol);
2799
2800            // populate the "f(i-1) OpB(i-1) f(i-1)* OR f(i-2) OpB(i-2)
2801
// f(i-2)* OR ... OR f1 OpB f1*"
2802
if (i > 0) {
2803               for (int j = i - 1; j >= 0; j--) {
2804                  curCol = fillPreparedStatement(fv[j], ps, curCol);
2805               }
2806            }
2807         }
2808      }
2809
2810      return curCol;
2811   }
2812   
2813   protected static DbFormsConfig getConfig() {
2814    DbFormsConfig config = null;
2815    try {
2816        config = DbFormsConfigRegistry.instance().lookup();
2817    } catch (Exception JavaDoc e) {
2818        logCat.error("no config object", e);
2819    }
2820    return config;
2821 }
2822
2823}
2824
Popular Tags