1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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.interfaces.DbEventInterceptorData;
30 import org.dbforms.interfaces.IDbEventInterceptor;
31 import org.dbforms.interfaces.IEscaper;
32 import org.dbforms.util.MessageResourcesInternal;
33 import org.dbforms.util.ParseUtil;
34 import org.dbforms.util.ReflectionUtil;
35 import org.dbforms.util.SqlUtil;
36 import org.dbforms.util.StringUtil;
37 import org.dbforms.util.Util;
38
39 import java.sql.PreparedStatement;
40 import java.sql.ResultSet;
41 import java.sql.SQLException;
42 import java.sql.Statement;
43
44 import java.util.Collection;
45 import java.util.Hashtable;
46 import java.util.Iterator;
47 import java.util.Locale;
48 import java.util.StringTokenizer;
49 import java.util.Vector;
50
51 import java.io.Serializable;
52
53 import javax.servlet.http.HttpServletRequest;
54
55 /***
56 * This class represents a table tag in dbforms-config.xml (dbforms config xml
57 * file). <br>
58 * It also defines a lot of methods for preparing and actually performing
59 * operations (queries) on the table
60 *
61 * @author Joe Peer
62 */
63 public class Table implements Serializable {
64 /*** either "classic" or "interceptor", default is "interceptor" */
65 public static final int BLOB_INTERCEPTOR = 0;
66
67 /*** DOCUMENT ME! */
68 public static final int BLOB_CLASSIC = 1;
69
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
87 private Hashtable calcFieldsNameHash = new Hashtable();
88
89 /*** structure for quick acessing of fields "by name" */
90 private Hashtable fieldNameHash = new Hashtable();
91
92 /*** access foreign key by name */
93 private Hashtable foreignKeyNameHash = new Hashtable();
94
95 private IEscaper escaper = null;
96
97 /*** log4j category */
98 private static Log logCat = LogFactory.getLog(Table.class.getName());
99
100 /*** some sort of alias to set in dbforms-config, not used yet */
101 private String alias = null;
102
103 private String blobHandling = null;
104
105 /*** reference to the DataAccess Class */
106 private String dataAccessClass = null;
107
108 /*** Holds value of property defaultVisibleFields. */
109 private String defaultVisibleFields;
110
111 /*** Holds value of property defaultVisibleFieldsFormat. */
112 private String defaultVisibleFieldsFormat;
113
114 private String escaperClass = null;
115
116 /*** the name of the Table */
117 private String name;
118
119 /***
120 * instance variables concerned with the ORDERING/SORTING characterstics of
121 * that table (ordering and sorting is used synonym here)
122 */
123 private String orderBy;
124
125 /*** reference to a TableEvents object */
126 private TableEvents tableEvents = null;
127
128 private Vector calcFields = new Vector();
129
130 /***
131 * subset of "fields", containting those keys which represent DISKBLOBs
132 * (wondering about that term? -> see docu)
133 */
134 private Vector diskblobs = new Vector();
135
136 /*** the Field-Objects this table constists of */
137 private Vector fields = new Vector();
138
139 private Vector foreignKeys = new Vector();
140
141 /*** application hookups */
142 private Vector interceptors = new Vector();
143
144 /*** subset of "fields", containting those keys which represent keys */
145 private Vector key = new Vector();
146
147 /*** the order-by clause, as specified in dbforms-config.xml (optional!) */
148 private FieldValue[] defaultOrder;
149
150 private int blobHandlingStrategy = BLOB_INTERCEPTOR;
151
152 /***
153 * id of this table (generated by DbFormsConfig when parsing
154 * dbforms-config.xml)
155 */
156 private int id;
157
158 /***
159 * DOCUMENT ME!
160 *
161 * @param alias
162 * the alias to set
163 */
164 public void setAlias(String alias) {
165 this.alias = alias;
166 }
167
168 /***
169 * DOCUMENT ME!
170 *
171 * @return String
172 */
173 public String getAlias() {
174 return alias;
175 }
176
177 /***
178 * for digester only, see blobHandlingStrategy
179 *
180 * @param blobHandling
181 * config parameter
182 */
183 public void setBlobHandling(String blobHandling) {
184 this.blobHandling = blobHandling;
185
186 if ("classic".equals(blobHandling)) {
187 this.blobHandlingStrategy = BLOB_CLASSIC;
188 } else {
189 this.blobHandlingStrategy = BLOB_INTERCEPTOR;
190 }
191 }
192
193 /***
194 * for digester only, see blobHandlingStrategy
195 *
196 * @return String
197 */
198 public String getBlobHandling() {
199 return blobHandling;
200 }
201
202 /***
203 * DOCUMENT ME!
204 *
205 * @return DOCUMENT ME!
206 */
207 public int getBlobHandlingStrategy() {
208 return this.blobHandlingStrategy;
209 }
210
211 /***
212 * DOCUMENT ME!
213 *
214 * @return
215 */
216 public Vector getCalcFields() {
217 return calcFields;
218 }
219
220 /***
221 * Sets the dataAccessClass.
222 *
223 * @param dataAccessClass
224 * The dataAccessClass to set
225 */
226 public void setDataAccessClass(String dataAccessClass) {
227 this.dataAccessClass = dataAccessClass;
228 }
229
230 /***
231 * DOCUMENT ME!
232 *
233 * @return String
234 */
235 public String getDataAccessClass() {
236 return dataAccessClass;
237 }
238
239 /***
240 * Return the datastructure containing info about the default sorting
241 * behavior of this table.
242 *
243 * @return the datastructure containing info about the default sorting
244 * behavior of this table.
245 */
246 public FieldValue[] getDefaultOrder() {
247 return defaultOrder;
248 }
249
250 /***
251 * Setter for property defaultVisibleFields.
252 *
253 * @param defaultVisibleFields
254 * New value of property defaultVisibleFields.
255 */
256 public void setDefaultVisibleFields(String defaultVisibleFields) {
257 this.defaultVisibleFields = defaultVisibleFields;
258 }
259
260 /***
261 * Getter for property defaultVisibleFields.
262 *
263 * @return Value of property defaultVisibleFields.
264 */
265 public String getDefaultVisibleFields() {
266 return this.defaultVisibleFields;
267 }
268
269 /***
270 * Setter for property defaultVisibleFieldsFormat.
271 *
272 * @param defaultVisibleFieldsFormat
273 * New value of property defaultVisibleFieldsFormat.
274 */
275 public void setDefaultVisibleFieldsFormat(String defaultVisibleFieldsFormat) {
276 this.defaultVisibleFieldsFormat = defaultVisibleFieldsFormat;
277 }
278
279 /***
280 * Getter for property defaultVisibleFieldsFormat.
281 *
282 * @return Value of property defaultVisibleFieldsFormat.
283 */
284 public String getDefaultVisibleFieldsFormat() {
285 return this.defaultVisibleFieldsFormat;
286 }
287
288 /***
289 * Returns SQL delete statement, used by deleteEvent.
290 *
291 * @return the SQL delete statement
292 */
293 public String getDeleteStatement(String keyValString) {
294
295 StringBuffer queryBuf = new StringBuffer();
296 queryBuf.append("DELETE FROM ");
297 queryBuf.append(getQueryToChange());
298 queryBuf.append(" WHERE ");
299 queryBuf.append(getWhereClauseForKeyFields(keyValString));
300
301 logCat.info("::deleteQuery - [" + queryBuf.toString() + "]");
302 return queryBuf.toString();
303 }
304
305 /***
306 * Generates part of a field list for a SQL SELECT clause selecting the
307 * DISKBLOB fields from a table (used by DeleteEvent to maintain data
308 * consistence).
309 *
310 * @return a part of a field list for a SQL SELECT clause selecting the
311 * DISKBLOB fields from a table
312 */
313 public String getDisblobSelectStatement() {
314 StringBuffer buf = new StringBuffer();
315 buf.append("SELECT ");
316
317 int cnt = diskblobs.size();
318
319 for (int i = 0; i < cnt; i++) {
320 Field diskblobField = (Field) diskblobs.elementAt(i);
321
322
323 buf.append(diskblobField.getName());
324
325 if (i < (cnt - 1)) {
326 buf.append(", ");
327 }
328 }
329
330 buf.append(" FROM ");
331 buf.append(getQueryFrom());
332
333 return buf.toString();
334 }
335
336 /***
337 * Returns a Vector of Field-Objects representing fields of type "DISKBLOB"
338 *
339 * @return a Vector of Field-Objects representing fields of type "DISKBLOB"
340 */
341 public Vector getDiskblobs() {
342 return diskblobs;
343 }
344
345 /***
346 * Get the SQL ResultSet from the query builded using the input data. Order
347 * of parts: 1. sqlFilter 2. where condition generated from searching 3.
348 * where condition generated from ordering Generating the query in
349 * getSelectQuery() must match this order!
350 *
351 * @param fvEqual
352 * FieldValue array used to restrict a set in a subform where all
353 * "childFields" in the resultset match their respective
354 * "parentFields" in main form
355 * @param fvOrder
356 * FieldValue array used to build a cumulation of rules for
357 * ordering (sorting) and restricting fields
358 * @param sqlFilterParams
359 * DOCUMENT ME!
360 * @param compareMode
361 * the value of the compare mode
362 * @param ps
363 * the PreparedStatement object
364 *
365 * @return a ResultSet object
366 *
367 * @throws SQLException
368 * if any error occurs
369 */
370 public ResultSet getDoSelectResultSet(FieldValue[] fvEqual,
371 FieldValue[] fvOrder, FieldValue[] sqlFilterParams,
372 int compareMode, PreparedStatement ps) throws SQLException {
373
374 int curCol = 1;
375
376 logCat.debug("###getDoSelectResultSet pos1");
377
378 if (!FieldValue.isNull(sqlFilterParams)) {
379 curCol = populateWhereEqualsClause(sqlFilterParams, ps, curCol);
380 }
381
382 logCat.debug("###getDoSelectResultSet pos2");
383
384 if (!FieldValue.isNull(fvEqual)) {
385 curCol = populateWhereEqualsClause(fvEqual, ps, curCol);
386 }
387
388 logCat.debug("###getDoSelectResultSet pos3");
389
390 if ((compareMode != Constants.COMPARE_NONE) && (fvOrder != null)
391 && (fvOrder.length > 0)) {
392 populateWhereAfterClause(fvOrder, ps, curCol);
393 }
394
395 logCat.debug("###getDoSelectResultSet pos3");
396
397 ResultSet result = null;
398
399 try {
400 result = ps.executeQuery();
401 } catch (SQLException sqle) {
402 SqlUtil.logSqlException(sqle);
403 throw sqle;
404 }
405
406 return result;
407 }
408
409 /***
410 * DOCUMENT ME!
411 *
412 * @return DOCUMENT ME!
413 */
414 public IEscaper getEscaper() {
415 if (escaper == null) {
416 String s = getEscaperClass();
417
418 if (!Util.isNull(s)) {
419 try {
420 escaper = (IEscaper) ReflectionUtil.newInstance(s);
421 } catch (Exception e) {
422 logCat
423 .error("cannot create the new escaper [" + s + "]",
424 e);
425 }
426 }
427
428 if ((escaper == null)) {
429 try {
430 escaper = DbFormsConfigRegistry.instance().lookup()
431 .getEscaper();
432 } catch (Exception e) {
433 logCat.error("cannot create the new default escaper", e);
434 }
435 }
436 }
437
438 return escaper;
439 }
440
441 /***
442 * DOCUMENT ME!
443 *
444 * @param string
445 */
446 public void setEscaperClass(String string) {
447 escaperClass = string;
448 }
449
450 /***
451 * DOCUMENT ME!
452 *
453 * @return
454 */
455 public String getEscaperClass() {
456 return escaperClass;
457 }
458
459 /***
460 * Returns the Field-Objet with specified id.
461 *
462 * @param fieldId
463 * The id of the field to be returned
464 *
465 * @return the Field object having the input id
466 */
467 public Field getField(int fieldId) {
468 Field f = null;
469
470 if (checkFieldId(CALC_FIELD, fieldId)) {
471 f = (Field) calcFields
472 .elementAt(decodeFieldId(CALC_FIELD, fieldId));
473 } else {
474 f = (Field) fields.elementAt(fieldId);
475 }
476
477 return f;
478 }
479
480 public boolean isCalcField(int fieldId) {
481 return checkFieldId(CALC_FIELD, fieldId);
482 }
483
484 /***
485 * Returns the field-objects as specified by name (or null if no field with
486 * the specified name exists in this table).
487 *
488 * @param name
489 * The name of the field
490 *
491 * @return Filed object having the input name
492 */
493 public Field getFieldByName(String 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 * We have the field ID - we need the field name
503 *
504 * @param fieldID
505 * fieldID to get field name from
506 *
507 * @return the field name
508 */
509 public String getFieldName(int fieldID) {
510 Field f = (Field) getFields().elementAt(fieldID);
511
512 return (f.getName());
513 }
514
515 /***
516 * This method parses a position string and build a data structure
517 * representing the values of the fields decoded from the position. <br>
518 * #fixme: replace seperator-based tokenization by better algoithm!
519 *
520 * @param position
521 * the position string
522 *
523 * @return the HashTable containing the FieldValues of the fields decoded,
524 * key of the HashTable is the fieldName!
525 */
526 public FieldValues getFieldValues(String position) {
527
528 if (Util.isNull(position)) {
529 return null;
530 }
531
532
533
534
535
536 FieldValues result = new FieldValues();
537
538 try {
539 int startIndex = 0;
540 boolean endOfString = false;
541
542
543 while (!endOfString) {
544 int firstColon = position.indexOf(':', startIndex);
545 int secondColon = position.indexOf(':', firstColon + 1);
546
547 if ((firstColon == -1) && (secondColon == -1)) {
548 return null;
549 }
550
551 String fieldIdStr = position.substring(startIndex, firstColon);
552 int fieldId = Integer.parseInt(fieldIdStr);
553
554 String valueLengthStr = position.substring(firstColon + 1,
555 secondColon);
556 int valueLength = Integer.parseInt(valueLengthStr);
557
558 int controlIndex = secondColon + 1 + valueLength;
559
560
561 String valueStr = (controlIndex < position.length()) ? position
562 .substring(secondColon + 1, controlIndex) : position
563 .substring(secondColon + 1);
564
565 Field f = getField(fieldId);
566 FieldValue fv = new FieldValue(f, valueStr);
567 result.put(fv);
568
569 if (controlIndex == position.length()) {
570 endOfString = true;
571 } else if (controlIndex > position.length()) {
572 logCat.warn("Controlbyte wrong but continuing execution");
573 endOfString = true;
574 } else {
575 char controlByte = position.charAt(controlIndex);
576
577 if (controlByte != '-') {
578 logCat.error("Controlbyte wrong, abandon execution");
579 throw new IllegalArgumentException();
580 }
581
582 startIndex = controlIndex + 1;
583
584 if (position.length() == startIndex) {
585 endOfString = true;
586 }
587 }
588 }
589 } catch (Exception e) {
590 logCat.error("::getFieldValuesFromPositionAsHt - exception:", e);
591 result = null;
592 }
593
594 return result;
595 }
596
597 /***
598 * Returns the vector of fields this table constists of
599 *
600 * @return the vector of fields this table constists of
601 */
602 public Vector getFields() {
603 return fields;
604 }
605
606 /***
607 * Initialize the filterFieldValues array.
608 *
609 * @param filter
610 * the filter string
611 * @param locale
612 * the table object
613 *
614 * @return an initialized FieldValue array
615 *
616 * @todo add MORE docs here !!!
617 */
618 public FieldValue[] getFilterFieldArray(String filter, Locale locale) {
619 if (Util.isNull(filter)) {
620 return null;
621 }
622
623 Vector keyValPairs = StringUtil.splitString(filter, ",;");
624
625
626 int len = keyValPairs.size();
627
628 FieldValue[] result = new FieldValue[len];
629
630 for (int i = 0; i < len; i++) {
631 int operator = 0;
632 boolean isLogicalOR = false;
633 int jump = 1;
634 String aKeyValPair = (String) keyValPairs.elementAt(i);
635
636
637 logCat.debug("initFilterFieldValues: aKeyValPair = " + aKeyValPair);
638
639
640
641 int n;
642
643
644 if ((n = aKeyValPair.indexOf("<>")) != -1) {
645
646 operator = Constants.FILTER_NOT_EQUAL;
647 jump = 2;
648 } else if ((n = aKeyValPair.indexOf(">=")) != -1) {
649
650
651
652 operator = Constants.FILTER_GREATER_THEN_EQUAL;
653 jump = 2;
654 } else if ((n = aKeyValPair.indexOf('>')) != -1) {
655
656
657 operator = Constants.FILTER_GREATER_THEN;
658 } else if ((n = aKeyValPair.indexOf("<=")) != -1) {
659
660
661
662 operator = Constants.FILTER_SMALLER_THEN_EQUAL;
663 jump = 2;
664 } else if ((n = aKeyValPair.indexOf('<')) != -1) {
665
666
667 operator = Constants.FILTER_SMALLER_THEN;
668 } else if ((n = aKeyValPair.indexOf('=')) != -1) {
669
670
671 operator = Constants.FILTER_EQUAL;
672 } else if ((n = aKeyValPair.indexOf('~')) != -1) {
673
674
675 operator = Constants.FILTER_LIKE;
676 } else if ((n = aKeyValPair.toUpperCase().indexOf("NOTISNULL")) != -1) {
677
678
679 jump = -1;
680 operator = Constants.FILTER_NOT_NULL;
681 } else if ((n = aKeyValPair.toUpperCase().indexOf("ISNULL")) != -1) {
682
683
684 jump = -1;
685 operator = Constants.FILTER_NULL;
686 }
687
688
689
690
691
692
693 String fieldName = aKeyValPair.substring(0, n).trim();
694
695
696 logCat.debug("Filter field=" + fieldName);
697
698 if (fieldName.charAt(0) == '|') {
699
700
701 fieldName = fieldName.substring(1);
702 isLogicalOR = true;
703 }
704
705 Field filterField = getFieldByName(fieldName);
706
707
708 String value = "";
709 if (jump >= 0)
710 value = aKeyValPair.substring(n + jump).trim();
711
712
713 logCat.debug("Filter value=" + value);
714
715
716 result[i] = FieldValue.createFieldValueForSearching(filterField,
717 value, locale, operator, Constants.SEARCHMODE_NONE,
718 Constants.SEARCH_ALGO_SHARP, isLogicalOR);
719 logCat.debug("and fv is =" + result[i].toString());
720 }
721
722 return result;
723 }
724
725 /***
726 * Get all the ForeignKey objects related to this table.
727 *
728 * @return a vector containing all the ForeignKey objects related to this
729 * table.
730 */
731 public Collection getForeignKeys() {
732 return foreignKeys;
733 }
734
735 /***
736 * Prepares the Querystring for the free form select statement
737 *
738 * @param fieldsToSelect
739 * vector of fields to be selected
740 * @param whereClause
741 * free-form whereClause to be appended to query
742 * @param tableList
743 * the list of tables involved into the query
744 *
745 * @return the query string
746 */
747 public String getFreeFormSelectQuery(Vector fieldsToSelect,
748 String whereClause, String tableList) {
749 StringBuffer buf = new StringBuffer();
750 buf.append("SELECT ");
751 buf.append(getQuerySelect(fieldsToSelect));
752 buf.append(" FROM ");
753
754 if (Util.isNull(tableList)) {
755 buf.append(getQueryFrom());
756 } else {
757 buf.append(tableList);
758 }
759
760 buf.append(" ");
761 buf.append(whereClause);
762 logCat.info("::getFreeFormSelectQuery -- [" + buf.toString() + "]");
763
764 return buf.toString();
765 }
766
767 /***
768 * Set GrantedPrivileges, if defined in dbforms-config-xml (this method gets
769 * called from XML-digester).
770 *
771 * @param grantedPrivileges
772 * the grantedPrivileges object
773 */
774 public void setGrantedPrivileges(GrantedPrivileges grantedPrivileges) {
775 this.grantedPrivileges = grantedPrivileges;
776 }
777
778 /***
779 * returns object containing info about rights mapped to user-roles.
780 * (context: this table object!)
781 *
782 * @return the GrantedPrivileges object
783 */
784 public GrantedPrivileges getGrantedPrivileges() {
785 return grantedPrivileges;
786 }
787
788 /***
789 * Sets the ID of this table (this method gets called from DbFormsConfig).
790 *
791 * @param id
792 * the id value to set
793 */
794 public void setId(int id) {
795 this.id = id;
796 }
797
798 /***
799 * Returns ID of this table.
800 *
801 * @return the id value
802 */
803 public int getId() {
804 return id;
805 }
806
807 /***
808 * Returns SQL insert statement, used by insertEvent.
809 *
810 * @param fieldValues
811 * the Hashtable containing the field values
812 *
813 * @return the SQL insert statement
814 */
815 public String getInsertStatement(FieldValues fieldValues) {
816 StringBuffer queryBuf = new StringBuffer();
817 queryBuf.append("INSERT INTO ");
818 queryBuf.append(getQueryToChange());
819 queryBuf.append(" (");
820
821
822 Iterator e = fieldValues.keys();
823 while (e.hasNext()) {
824 String fieldName = (String) e.next();
825 FieldValue fv = fieldValues.get(fieldName);
826 if (!isCalcField(fv.getField().getId()) && Util.isNull(fv.getField().getExpression()) ) {
827 queryBuf.append(fieldName);
828 if (e.hasNext()) {
829 queryBuf.append(",");
830 }
831 }
832 }
833
834
835 queryBuf.append(") VALUES (");
836 e = fieldValues.keys();
837 while (e.hasNext()) {
838 String fieldName = (String) e.next();
839 FieldValue fv = fieldValues.get(fieldName);
840 if (!isCalcField(fv.getField().getId()) && Util.isNull(fv.getField().getExpression()) ) {
841 queryBuf.append("?");
842 if (e.hasNext()) {
843 queryBuf.append(",");
844 }
845 }
846 }
847
848 queryBuf.append(")");
849 logCat.info("::insertQuery - [" + queryBuf.toString() + "]");
850
851 return queryBuf.toString();
852 }
853
854 /***
855 * Get all the interceptor objects related to this table.
856 *
857 * @return a vector containing all the interceptor objects related to this
858 * table.
859 */
860 public Vector getInterceptors() {
861
862
863
864 Vector res = null;
865
866
867 if ((getConfig() != null) && getConfig().hasInterceptors()) {
868
869
870
871 res = new Vector(interceptors);
872 res.addAll(getConfig().getInterceptors());
873 } else {
874 res = interceptors;
875 }
876
877 return res;
878 }
879
880 /***
881 * Returns the key of this table (consisting of Field-Objects representing
882 * key-fields).
883 *
884 * @return the key of this table (consisting of Field-Objects representing
885 * key-fields)
886 */
887 public Vector getKey() {
888 return key;
889 }
890
891 /***
892 * Does basically the same as getPositionString but only for key-fields.
893 * <br>
894 * #checkme: could be merged with getPositionString <br>
895 * #fixme: replace seperator-based tokenization by better algoithm!
896 *
897 * @param rsv
898 * the ResultSetVector object
899 *
900 * @return the position string for key fields
901 */
902 public String getKeyPositionString(ResultSetVector rsv) {
903 if (ResultSetVector.isNull(rsv)) {
904 return null;
905 }
906
907 String[] currentRow = rsv.getCurrentRow();
908
909 if (currentRow == null) {
910 return null;
911 }
912
913 return getKeyPositionString(currentRow);
914 }
915
916 /***
917 * Does basically the same as getPositionString but only for key-fields.
918 *
919 * @param currentRow
920 * the currentRow as String[]
921 *
922 * @return the position string
923 */
924 public String getKeyPositionString(String[] currentRow) {
925 StringBuffer buf = new StringBuffer();
926
927 if (currentRow != null) {
928 for (int i = 0; i < getKey().size(); i++) {
929 Field f = (Field) getKey().elementAt(i);
930
931 if (i > 0) {
932 buf.append("-");
933 }
934
935 buf.append(createToken(f, currentRow[f.getId()]));
936 }
937 }
938
939 return buf.toString();
940 }
941
942 /***
943 * Get key position from the input hash table
944 *
945 * @param fvHT
946 * has field as key and FieldValue as value!
947 *
948 * @return the key position string
949 *
950 * @throws IllegalArgumentException
951 * DOCUMENT ME!
952 */
953 public String getKeyPositionString(FieldValues fvHT) {
954 if (fvHT == null) {
955 return null;
956 }
957
958 StringBuffer buf = new StringBuffer();
959 int cnt = 0;
960
961 for (int i = 0; i < getKey().size(); i++) {
962 Field f = (Field) getKey().elementAt(i);
963 FieldValue fv = fvHT.get(f.getName());
964
965 if (fv != null) {
966 String value = fv.getFieldValue();
967
968 if (value == null) {
969 throw new IllegalArgumentException("wrong fields provided");
970 }
971
972 if (cnt > 0) {
973 buf.append("-");
974 }
975
976 buf.append(createToken(f, value));
977 cnt++;
978 }
979 }
980
981 return buf.toString();
982 }
983
984 /***
985 * Sets the name of the table (this method gets called from XML-digester)
986 *
987 * @param name
988 * the name of the table
989 */
990 public void setName(String name) {
991 this.name = name;
992 }
993
994 /***
995 * Returns name of the table
996 *
997 * @return the name of this table
998 */
999 public String getName() {
1000 return name;
1001 }
1002
1003 /***
1004 * returns the hash table. Moved from dbFormTag to table, so that you can
1005 * overload it!
1006 *
1007 * @param core
1008 * starting tag for the fields
1009 *
1010 * @return hash table of names in PHP slang we would call that an
1011 * "associative array" :=)
1012 */
1013 public Hashtable getNamesHashtable(String core) {
1014 Hashtable result = new Hashtable();
1015 Iterator e = getFields().iterator();
1016
1017 while (e.hasNext()) {
1018 Field f = (Field) e.next();
1019 result.put(f.getName(), f.getFieldName(core));
1020 }
1021
1022 return result;
1023 }
1024
1025 /***
1026 * Sets a default-orderBy clause from xml config (this method gets called
1027 * from XML-digester).
1028 *
1029 * @param orderBy
1030 * the orderBy clause
1031 */
1032 public void setOrderBy(String orderBy) {
1033 this.orderBy = orderBy;
1034 }
1035
1036 /***
1037 * Return default-orderBy clause from xml config or null if not specified.
1038 *
1039 * @return the default-orderBy clause from xml config or null if not
1040 * specified.
1041 */
1042 public String getOrderBy() {
1043 return orderBy;
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 to
1052 * 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
1057 * the ResultSetVector object
1058 *
1059 * @return the position string
1060 */
1061 public String getPositionString(ResultSetVector rsv) {
1062 if (ResultSetVector.isNull(rsv)) {
1063 return null;
1064 }
1065
1066 String[] currentRow = rsv.getCurrentRow();
1067
1068 if (currentRow == null) {
1069 return null;
1070 }
1071
1072 return getPositionString(currentRow);
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 to
1081 * keep track of the position the user comes from or goes to. <br>
1082 *
1083 * @param currentRow
1084 * the currentRow as String[]
1085 *
1086 * @return the position string
1087 */
1088 public String getPositionString(String[] currentRow) {
1089 StringBuffer buf = new StringBuffer();
1090 int cnt = 0;
1091
1092 for (int i = 0; i < getFields().size(); i++) {
1093 Field f = (Field) getFields().elementAt(i);
1094
1095 if (f.hasIsKeySet() || f.hasSortableSet()) {
1096 if (cnt > 0) {
1097 buf.append("-");
1098 }
1099
1100 buf.append(createToken(f, currentRow[f.getId()]));
1101 cnt++;
1102 }
1103 }
1104
1105 return buf.toString();
1106 }
1107
1108 /***
1109 * Used for instance by goto with prefix
1110 *
1111 * @param ht
1112 * the Hashtable object containing the field names used to build
1113 * the position string ht has fieldName as key and valueStr as
1114 * value!
1115 *
1116 * @return the position string
1117 */
1118 public String getPositionString(Hashtable ht) {
1119 StringBuffer buf = new StringBuffer();
1120 int cnt = 0;
1121 Iterator e = ht.keySet().iterator();
1122
1123 while (e.hasNext()) {
1124 String fieldName = (String) e.next();
1125 Field aField = getFieldByName(fieldName);
1126
1127 if (aField != null) {
1128 if (aField.hasIsKeySet() || aField.hasSortableSet()) {
1129 String fieldValue = (String) ht.get(fieldName);
1130
1131 if (cnt > 0) {
1132 buf.append('-');
1133 }
1134
1135 buf.append(createToken(aField, fieldValue));
1136 cnt++;
1137 } else {
1138 logCat.debug("provided goto field " + fieldName
1139 + " is not key/search field!");
1140 }
1141 } else {
1142 logCat
1143 .error("provided goto field " + fieldName
1144 + " not found!");
1145 }
1146 }
1147
1148 return buf.toString();
1149 }
1150
1151 /***
1152 * Get key position from the input hash table
1153 *
1154 * @param fvHT
1155 * has field as key and FieldValue as value!
1156 *
1157 * @return the key position string
1158 *
1159 * @throws IllegalArgumentException
1160 * DOCUMENT ME!
1161 */
1162 public String getPositionString(FieldValues fvHT) {
1163 String res = null;
1164 if (fvHT != null) {
1165 StringBuffer buf = new StringBuffer();
1166 int cnt = 0;
1167 Iterator e = fvHT.keys();
1168
1169 while (e.hasNext()) {
1170 String fieldName = (String) e.next();
1171 FieldValue fv = fvHT.get(fieldName);
1172 Field f = fv.getField();
1173
1174 if (f.hasIsKeySet() || f.hasSortableSet()) {
1175 String value = fv.getFieldValue();
1176
1177 if (value == null) {
1178 throw new IllegalArgumentException(
1179 "wrong fields provided");
1180 }
1181
1182 if (cnt > 0) {
1183 buf.append("-");
1184 }
1185
1186 buf.append(createToken(f, value));
1187 cnt++;
1188 }
1189 }
1190
1191 res = buf.toString();
1192 }
1193 return res;
1194 }
1195
1196 /***
1197 * Returns the FROM part of a query.
1198 *
1199 * @return the FROM part of a query
1200 */
1201 public String getQueryFrom() {
1202 String res = getAlias();
1203 if (Util.isNull(res)) {
1204 res = name;
1205 }
1206 return res;
1207 }
1208
1209 /***
1210 * Returns the select part of a query.
1211 *
1212 * @param fieldsToSelect
1213 * the vector containing the Field objects used to build the
1214 * elect part of the query
1215 *
1216 * @return the select part of a query
1217 */
1218 public String getQuerySelect(Vector fieldsToSelect) {
1219 if (fieldsToSelect != null) {
1220 StringBuffer buf = new StringBuffer();
1221 int fieldsToSelectSize = fieldsToSelect.size();
1222
1223
1224
1225
1226 for (int i = 0; i < fieldsToSelectSize; i++) {
1227 Field f = (Field) fieldsToSelect.elementAt(i);
1228 buf.append(f.getName());
1229 buf.append(", ");
1230 }
1231
1232 buf.deleteCharAt(buf.length() - 2);
1233
1234 return buf.toString();
1235 }
1236
1237 return "*";
1238 }
1239
1240 /***
1241 * Prepares the Querystring for the select statement Order of parts: 1.
1242 * sqlFilter (fild in getDoSelectResultSet!) 2. where condition generated
1243 * from having / ordering fields (fild in populateWhereEqualsClause)
1244 * Retrieving the parameters in getDoSelectResultSet() must match this
1245 * order!
1246 *
1247 * @param fieldsToSelect
1248 * vector of fields to be selected
1249 * @param fvEqual
1250 * fieldValues representing values we are looking for
1251 * @param fvOrder
1252 * fieldValues representing needs for order clauses
1253 * @param sqlFilter
1254 * sql condition to and with the where clause
1255 * @param compareMode
1256 * compare mode value for generating the order clause
1257 *
1258 * @return the query string
1259 */
1260 public String getSelectQuery(Vector fieldsToSelect, FieldValue[] fvEqual,
1261 FieldValue[] fvOrder, String sqlFilter, int compareMode) {
1262 StringBuffer buf = new StringBuffer();
1263
1264 buf.append("SELECT ");
1265 buf.append(getQuerySelect(fieldsToSelect));
1266 buf.append(" FROM ");
1267 buf.append(getQueryFrom());
1268
1269 String s = getQueryWhere(fvEqual, fvOrder, compareMode);
1270
1271 if (!Util.isNull(s) || !Util.isNull(sqlFilter)) {
1272 buf.append(" WHERE ");
1273 }
1274
1275
1276 if (!Util.isNull(sqlFilter)) {
1277 buf.append(" ( ");
1278 buf.append(sqlFilter);
1279 buf.append(" ) ");
1280 }
1281
1282
1283 if (!Util.isNull(s)) {
1284 if (!Util.isNull(sqlFilter)) {
1285 buf.append(" AND ");
1286 }
1287
1288 buf.append(" ( ");
1289 buf.append(s);
1290 buf.append(" ) ");
1291 }
1292
1293 s = getQueryOrderBy(fvOrder);
1294
1295 if (s.length() > 0) {
1296 buf.append(" ORDER BY ");
1297 buf.append(s);
1298 }
1299
1300 logCat.info("::getSelectQuery - [" + buf.toString() + "]");
1301
1302 return buf.toString();
1303 }
1304
1305
1306
1307
1308 /***
1309 * Get the SQL select statement.
1310 *
1311 * @return the SQL select statement
1312 */
1313 public String getSelectStatement() {
1314 StringBuffer queryBuf = new StringBuffer();
1315 queryBuf.append("SELECT ");
1316 queryBuf.append(getQuerySelect(fields));
1317 queryBuf.append(" FROM ");
1318 queryBuf.append(getQueryFrom());
1319 logCat.info(queryBuf.toString());
1320
1321 return queryBuf.toString();
1322 }
1323
1324 /***
1325 * Set the table events object related to this table.
1326 *
1327 * @param tableEvents
1328 * the table events object related to this table
1329 */
1330 public void setTableEvents(TableEvents tableEvents) {
1331 this.tableEvents = tableEvents;
1332 tableEvents.setTable(this);
1333 }
1334
1335 /***
1336 * Get the table events object related to this table. <br>
1337 * If it is null (because user didn't specify custom events), set a new
1338 * TableEvents object and return its reference.
1339 *
1340 * @return the table events object related to this table
1341 */
1342 public TableEvents getTableEvents() {
1343 if (tableEvents == null) {
1344 tableEvents = new TableEvents();
1345 }
1346
1347 return tableEvents;
1348 }
1349
1350 /***
1351 * Returns SQL update statement, used by updateEvent.
1352 *
1353 * @param fieldValues
1354 * the Hashtable object containing the field values
1355 *
1356 * @return the SQL update statement
1357 */
1358 public String getUpdateStatement(FieldValues fieldValues, String keyValStr) {
1359 StringBuffer queryBuf = new StringBuffer();
1360 queryBuf.append("UPDATE ");
1361 queryBuf.append(getQueryToChange());
1362 queryBuf.append(" SET ");
1363
1364
1365
1366
1367
1368
1369 boolean kommaNeeded = false;
1370 Iterator e = fieldValues.keys();
1371 while (e.hasNext()) {
1372 String fieldName = (String) e.next();
1373 FieldValue fv = fieldValues.get(fieldName);
1374 if (!isCalcField(fv.getField().getId()) && Util.isNull(fv.getField().getExpression())) {
1375 if (kommaNeeded) {
1376 queryBuf.append(", ");
1377 } else {
1378 kommaNeeded = true;
1379 }
1380 queryBuf.append(fieldName);
1381 queryBuf.append("= ?");
1382 }
1383 }
1384 queryBuf.append(" WHERE ");
1385 queryBuf.append(getWhereClauseForKeyFields(keyValStr));
1386 logCat.info("::updateQuery - [" + queryBuf.toString() + "]");
1387
1388 return queryBuf.toString();
1389 }
1390
1391 /***
1392 * Build the WHERE clause string using the input field values.
1393 *
1394 * @param fv
1395 * the array of FieldValue objects
1396 *
1397 * @return the WHERE clause string protected so that it can be tested
1398 */
1399 public String getWhereClause(FieldValue[] fv) {
1400 StringBuffer buf = new StringBuffer();
1401
1402 if ((fv != null) && (fv.length > 0)) {
1403
1404 buf.append(" ( ");
1405
1406 for (int i = 0; i < fv.length; i++) {
1407
1408
1409
1410 if (i != 0) {
1411 if (fv[i].getLogicalOR()) {
1412 buf.append(" OR ");
1413 } else {
1414 buf.append(" ) AND ( ");
1415 }
1416 }
1417
1418 buf.append(getSQLExpression(fv[i]));
1419 }
1420
1421 buf.append(" ) ");
1422 }
1423
1424 return buf.toString();
1425 }
1426
1427
1428
1429
1430 /***
1431 * Generates a part of the SQL where clause needed to select a distinguished
1432 * row form the table. This is done by querying for KEY VALUES !
1433 *
1434 * @return a part of the SQL where clause needed to select a distinguished
1435 * row form the table
1436 */
1437 public String getWhereClauseForKeyFields(String keyValuesStr) {
1438 StringBuffer buf = new StringBuffer();
1439 FieldValues keyValuesHt = getFieldValues(keyValuesStr);
1440
1441 int cnt = this.getKey().size();
1442
1443 for (int i = 0; i < cnt; i++) {
1444 Field keyField = (Field) this.getKey().elementAt(i);
1445
1446 FieldValue aFieldValue = keyValuesHt.get(keyField.getName());
1447 Object value = aFieldValue.getFieldValueAsObject();
1448
1449 buf.append(keyField.getName());
1450 if (value == null) {
1451 buf.append(" is null");
1452 } else {
1453 buf.append(" = ?");
1454 }
1455 if (i < (cnt - 1)) {
1456 buf.append(" AND ");
1457 }
1458 }
1459
1460 return buf.toString();
1461 }
1462
1463 /***
1464 * adds a Field-Object to this table and puts it into othere datastructure
1465 * for further references (this method gets called from DbFormsConfig)
1466 *
1467 * @param field
1468 * field to add
1469 *
1470 * @throws Exception
1471 * DOCUMENT ME!
1472 */
1473 public void addCalcField(Field field) throws Exception {
1474 field.setId(encodeFieldId(CALC_FIELD, calcFields.size()));
1475 field.setTable(this);
1476 calcFields.addElement(field);
1477
1478
1479 calcFieldsNameHash.put(field.getName(), field);
1480 }
1481
1482 /***
1483 * Adds a Field-Object to this table and puts it into othere datastructure
1484 * for further references (this method gets called from DbFormsConfig)
1485 *
1486 * @param field
1487 * the Field object to add
1488 *
1489 * @throws Exception
1490 * DOCUMENT ME!
1491 */
1492 public void addField(Field field) throws Exception {
1493 if (field.getType() == 0) {
1494 throw new Exception("Table " + getName() + " Field "
1495 + field.getName() + ": no type!");
1496 }
1497
1498 field.setId(encodeFieldId(DB_FIELD, fields.size()));
1499 field.setTable(this);
1500 fields.addElement(field);
1501
1502
1503 if (field.hasIsKeySet()) {
1504 logCat.info("wow - field " + getName() + "." + field.getName()
1505 + " is a key");
1506
1507
1508 key.addElement(field);
1509 } else {
1510 logCat.info("field " + getName() + "." + field.getName()
1511 + " is NO key");
1512 }
1513
1514
1515 fieldNameHash.put(field.getName(), field);
1516
1517
1518 if (field.getType() == FieldTypes.DISKBLOB) {
1519 diskblobs.addElement(field);
1520 }
1521 }
1522
1523 /***
1524 * Adds a ForeignKey-Object to this table and puts it into othere
1525 * datastructure for further references (this method gets called from
1526 * DbFormsConfig)
1527 *
1528 * @param fk
1529 * the foreign key object
1530 */
1531 public void addForeignKey(ForeignKey fk) {
1532 fk.setId(foreignKeys.size());
1533
1534
1535 foreignKeys.addElement(fk);
1536
1537
1538 foreignKeyNameHash.put(fk.getName(), fk);
1539 }
1540
1541 /***
1542 * Add an interceptor to this table.
1543 *
1544 * @param interceptor
1545 * the interceptor to add
1546 */
1547 public void addInterceptor(Interceptor interceptor) {
1548 interceptors.addElement(interceptor);
1549 }
1550
1551 /***
1552 * Determinates if this table contains a diskblob field. (this method is
1553 * used by DeleteEvent which needs to delete files referenced by a diskblob
1554 * field).
1555 *
1556 * @return true if this table contains a diskblob field, false otherwise
1557 */
1558 public boolean containsDiskblob() {
1559 return diskblobs.size() > 0;
1560 }
1561
1562 /***
1563 * Column ["ASC" | "DESC"] {"," Column ["ASC" | "DESC"] } (if neither ASC
1564 * nor DESC follow "Col", then ASC is choosen as default). <br>
1565 * this method assures, that ALL KEY FIELDs are part of the order criteria,
1566 * in any case (independly from the order-Str). if necessary it appends
1567 * them. WHY: to ensure correct scrollig (not getting STUCK if the search
1568 * criteria are not "sharp" enough). <br>
1569 * #fixme - better explaination #fixme - determinate illegal input and throw
1570 * IllegalArgumentException
1571 *
1572 * @param order
1573 * a String from JSP provided by the user in SQL-Style
1574 * @param request
1575 * the request object
1576 * @param includeKeys
1577 * true to include key fields, false otherwise
1578 *
1579 * @return ???
1580 */
1581 public FieldValue[] createOrderFieldValues(String order,
1582 HttpServletRequest request, boolean includeKeys) {
1583 Vector result = null;
1584
1585 if (request != null) {
1586 String paramStub = Constants.FIELDNAME_SORT + this.getId();
1587 Vector sortFields = ParseUtil.getParametersStartingWith(request,
1588 paramStub);
1589
1590 if (sortFields.size() > 0) {
1591 result = createOrderFVFromRequest(request, paramStub,
1592 sortFields);
1593 }
1594 }
1595
1596
1597
1598
1599 if (((result == null) || result.isEmpty())) {
1600
1601 if (order == null) {
1602 order = getOrderBy();
1603 }
1604
1605 result = createOrderFVFromAttribute(order);
1606 logCat.debug("@@@ 1");
1607
1608 for (int i = 0; i < result.size(); i++) {
1609 FieldValue fieldVal = (FieldValue) result.elementAt(i);
1610 logCat.debug("fieldValue " + fieldVal.toString());
1611 }
1612 }
1613
1614 if (includeKeys) {
1615
1616
1617 for (int i = 0; i < this.getKey().size(); i++) {
1618 Field keyField = (Field) getKey().elementAt(i);
1619 boolean found = false;
1620 int j = 0;
1621
1622 while (!found && (j < result.size())) {
1623 FieldValue fv = (FieldValue) result.elementAt(j);
1624
1625 if (fv.getField() == keyField) {
1626 found = true;
1627 }
1628
1629 j++;
1630 }
1631
1632 if (!found) {
1633 result.addElement(FieldValue.createFieldValueForSorting(
1634 keyField, Constants.ORDER_ASCENDING));
1635 }
1636 }
1637 }
1638
1639 FieldValue[] resultArray = new FieldValue[result.size()];
1640 result.copyInto(resultArray);
1641 logCat.debug("@@@ 2");
1642
1643 for (int i = 0; i < resultArray.length; i++) {
1644 logCat.debug("fieldValue " + resultArray[i].toString());
1645 }
1646
1647 return resultArray;
1648 }
1649
1650
1651
1652
1653 /***
1654 * Do a constrained select.
1655 *
1656 * @param fvEqual
1657 * FieldValue array used to restrict a set in a subform where all
1658 * "childFields" in the resultset match their respective
1659 * "parentFields" in main form
1660 * @param fvOrder
1661 * FieldValue array used to build a cumulation of rules for
1662 * ordering (sorting) and restricting fields
1663 * @param sqlFilter
1664 * sql condition to add to where clause
1665 * @param sqlFilterParams
1666 * DOCUMENT ME!
1667 * @param compareMode
1668 * the value of the compare mode
1669 * @param maxRows
1670 * the max number of rows to manage
1671 * @param interceptorData
1672 * the connection object
1673 *
1674 * @return a ResultSetVector object
1675 *
1676 * @throws SQLException
1677 * if any error occurs
1678 */
1679 public ResultSetVector doConstrainedSelect(FieldValue[] fvEqual,
1680 FieldValue[] fvOrder, String sqlFilter,
1681 FieldValue[] sqlFilterParams, int compareMode, int maxRows,
1682 DbEventInterceptorData interceptorData) throws SQLException {
1683 String query = getSelectQuery(getFields(), fvEqual, fvOrder, sqlFilter,
1684 compareMode);
1685 PreparedStatement ps = interceptorData.getConnection()
1686 .prepareStatement(query);
1687 ps.setMaxRows(maxRows);
1688
1689 ResultSet rs = getDoSelectResultSet(fvEqual, fvOrder, sqlFilterParams,
1690 compareMode, ps);
1691 ResultSetVector result = new ResultSetVector(this);
1692 result.addResultSet(interceptorData, rs);
1693 ps.close();
1694 logCat.info("::doConstrainedSelect - rsv size = " + result.size());
1695
1696 return result;
1697 }
1698
1699 /***
1700 * perform free-form select query
1701 *
1702 * @param whereClause
1703 * free-form whereClause to be appended to query
1704 * @param tableList
1705 * the list of tables involved into the query
1706 * @param maxRows
1707 * how many rows should be stored in the resultSet (zero means
1708 * unlimited)
1709 * @param interceptorData
1710 * the active db connection to use
1711 *
1712 * @return the ResultSetVector object
1713 *
1714 * @throws SQLException
1715 * if any error occurs
1716 */
1717 public ResultSetVector doFreeFormSelect(String whereClause,
1718 String tableList, int maxRows,
1719 DbEventInterceptorData interceptorData) throws SQLException {
1720 Statement stmt = interceptorData.getConnection().createStatement();
1721 String query = getFreeFormSelectQuery(getFields(), whereClause,
1722 tableList);
1723 stmt.setMaxRows(maxRows);
1724
1725 ResultSet rs;
1726
1727 try {
1728 rs = stmt.executeQuery(query);
1729 } catch (SQLException sqle) {
1730 SqlUtil.logSqlException(sqle);
1731 throw new SQLException(sqle.getMessage());
1732 }
1733
1734 ResultSetVector result = new ResultSetVector(this);
1735 result.addResultSet(interceptorData, rs);
1736
1737
1738
1739 stmt.close();
1740 logCat.info("rsv size=" + result.size());
1741
1742 return result;
1743 }
1744
1745 /***
1746 * in version 0.9 this method moved from FieldValue.fillWithValues to
1747 * Table.fillWithValues
1748 *
1749 * @param orderConstraint
1750 * FieldValue array used to build a cumulation of rules for
1751 * ordering (sorting) and restricting fields
1752 * @param aPosition
1753 * resultset position
1754 */
1755 public void fillWithValues(FieldValue[] orderConstraint, String aPosition) {
1756
1757 FieldValues ht = getFieldValues(aPosition);
1758
1759
1760 if (ht != null) {
1761 logCat.info("*** parsing through: " + aPosition);
1762
1763
1764 for (int i = 0; i < orderConstraint.length; i++) {
1765 Field f = orderConstraint[i].getField();
1766
1767 if (f != null) {
1768 FieldValue aFieldValue = ht.get(f.getName());
1769
1770 if (aFieldValue != null) {
1771 orderConstraint[i].setFieldValue(aFieldValue
1772 .getFieldValue());
1773 } else {
1774 logCat.warn("position entry has null value:"
1775 + f.getName());
1776 }
1777 }
1778 }
1779 }
1780 }
1781
1782 /***
1783 * Check if this table has got interceptors.
1784 *
1785 * @return true if the table contains interceptors, false otherwise
1786 */
1787 public boolean hasInterceptors() {
1788 return (getConfig() != null && getConfig().hasInterceptors())
1789 || ((interceptors != null) && (interceptors.size() > 0));
1790 }
1791
1792 /***
1793 * Checks if there exists a granted-privileges object and if so it queries
1794 * if access/operation is possible
1795 *
1796 * @param request
1797 * the request object
1798 * @param privileg
1799 * the privilege value
1800 *
1801 * @return true if the user has got privileges over this table, false
1802 * otherwise
1803 */
1804 public boolean hasUserPrivileg(HttpServletRequest request, int privileg) {
1805 return (grantedPrivileges == null) ? true : grantedPrivileges
1806 .hasUserPrivileg(request, privileg);
1807 }
1808
1809 /***
1810 * This method generates a datastructure holding sorting information from
1811 * "orderBy" clause in XML-config.
1812 */
1813 public void initDefaultOrder() {
1814
1815
1816 if (orderBy == null) {
1817 initDefaultOrderFromKeys();
1818 } else {
1819
1820 defaultOrder = createOrderFieldValues(orderBy, null, true);
1821 }
1822
1823 logCat.info("Table.initDefaultOrder done.");
1824 }
1825
1826 /***
1827 * maps child fields to parent fields
1828 *
1829 * @param parentTable
1830 * the parent table
1831 * @param parentFieldString
1832 * field names in parent table
1833 * @param childFieldString
1834 * field names in child table
1835 * @param aPosition
1836 * position to map as position string
1837 *
1838 * @return FieldValues with result
1839 *
1840 * @throws IllegalArgumentException
1841 * DOCUMENT ME!
1842 */
1843 public FieldValues mapChildFieldValues(Table parentTable,
1844 String parentFieldString, String childFieldString, String aPosition) {
1845
1846 Vector childFieldNames = StringUtil
1847 .splitString(childFieldString, ",;~");
1848 Vector parentFieldNames = StringUtil.splitString(parentFieldString,
1849 ",;~");
1850
1851
1852
1853 int len = childFieldNames.size();
1854
1855 if ((len == 0) || (len != parentFieldNames.size())) {
1856 return null;
1857 }
1858
1859
1860 FieldValues ht = parentTable.getFieldValues(aPosition);
1861
1862 if (ht == null) {
1863 return null;
1864 }
1865
1866 FieldValues childFieldValues = new FieldValues();
1867
1868 for (int i = 0; i < len; i++) {
1869 String parentFieldName = (String) parentFieldNames.elementAt(i);
1870 Field parentField = parentTable.getFieldByName(parentFieldName);
1871 String childFieldName = (String) childFieldNames.elementAt(i);
1872 Field childField = this.getFieldByName(childFieldName);
1873 FieldValue aFieldValue = ht.get(parentField.getName());
1874
1875 if (aFieldValue == null) {
1876 throw new IllegalArgumentException(
1877 "ERROR: Make sure that field "
1878 + parentField.getName()
1879 + " is a KEY of the table "
1880 + parentTable.getName()
1881 + "! Otherwise you can not use it as PARENT/CHILD LINK argument!");
1882 }
1883
1884 String currentParentFieldValue = aFieldValue.getFieldValue();
1885 childFieldValues.put(new FieldValue(childField,
1886 currentParentFieldValue));
1887 }
1888
1889 return childFieldValues;
1890 }
1891
1892 /***
1893 * POPULATES a part of the SQL where clause needed to select a distinguished
1894 * row form the table using values endcoded in a string. <br>
1895 * #fixme: replace seperator-based tokenization by better algoithm!
1896 *
1897 * @param keyValuesStr
1898 * the position string
1899 * @param ps
1900 * the PreparedStatement object
1901 * @param startColumn
1902 * PreparedStatement start column
1903 *
1904 * @throws SQLException
1905 * if any error occurs
1906 */
1907 public void populateWhereClauseWithKeyFields(String keyValuesStr,
1908 PreparedStatement ps, int startColumn) throws SQLException {
1909 int col = startColumn;
1910
1911
1912
1913
1914 FieldValues keyValuesHt = getFieldValues(keyValuesStr);
1915 int keyLength = this.getKey().size();
1916
1917 for (int i = 0; i < keyLength; i++) {
1918 Field curField = (Field) this.getKey().elementAt(i);
1919 FieldValue aFieldValue = keyValuesHt.get(curField.getName());
1920 Object value = aFieldValue.getFieldValueAsObject();
1921 if (value != null) {
1922 JDBCDataHelper.fillWithData(ps, curField.getEscaper(), col, value,
1923 curField.getType(), this.getBlobHandlingStrategy());
1924 col++;
1925 }
1926 }
1927 }
1928
1929 /***
1930 * situation: we have built a query (involving the getWhereEqualsClause()
1931 * method) and now we want to prepare the statemtent - provide actual values
1932 * for the the '?' placeholders
1933 *
1934 * @param fv
1935 * the array of FieldValue objects
1936 * @param ps
1937 * the PreparedStatement object
1938 * @param curCol
1939 * the current PreparedStatement column; points to a
1940 * PreparedStatement xxx value
1941 *
1942 * @return the current column value
1943 *
1944 * @exception SQLException
1945 * if any error occurs
1946 */
1947 public int populateWhereEqualsClause(FieldValue[] fv, PreparedStatement ps,
1948 int curCol) throws SQLException {
1949 if ((fv != null) && (fv.length > 0)) {
1950 for (int i = 0; i < fv.length; i++) {
1951 curCol = fillPreparedStatement(fv[i], ps, curCol);
1952 }
1953 }
1954
1955 return curCol;
1956 }
1957
1958 /***
1959 * Process the interceptor objects related to this table.
1960 *
1961 * @param action
1962 * the DbEventInterceptor identifier. See the DbEventInterceptor
1963 * class for the real values. Example:
1964 * <code>DbEventInterceptor.PRE_UPDATE</code>
1965 * @param data
1966 * the DbEventInterceptorData object
1967 *
1968 * @return the value that identifies if an operation should be granted,
1969 * denied or ignored. See
1970 * <code>DbEventInterceptor.GRANT_OPERATION</code>,
1971 * <code>DbEventInterceptor.DENY_OPERATION</code>,
1972 * <code>DbEventInterceptor.IGNORE_OPERATION</code>
1973 *
1974 * @throws SQLException
1975 * if any error occurs
1976 */
1977 public int processInterceptors(int action, DbEventInterceptorData data)
1978 throws MultipleValidationException {
1979 String s;
1980 try {
1981 Vector allInterceptors = getInterceptors();
1982 int interceptorsCnt = allInterceptors.size();
1983
1984 for (int i = 0; i < interceptorsCnt; i++) {
1985 Interceptor interceptor = (Interceptor) allInterceptors
1986 .elementAt(i);
1987 Class interceptorClass = Class.forName(interceptor
1988 .getClassName());
1989 IDbEventInterceptor dbi = (IDbEventInterceptor) interceptorClass
1990 .newInstance();
1991
1992
1993
1994 dbi.setParameterMap(interceptor.getParameterMap());
1995
1996
1997
1998 int operation = IDbEventInterceptor.GRANT_OPERATION;
1999 String denyMessage = null;
2000
2001 if (action == IDbEventInterceptor.PRE_INSERT) {
2002 operation = dbi.preInsert(data);
2003 denyMessage = "dbforms.events.insert.nogrant";
2004 } else if (action == IDbEventInterceptor.POST_INSERT) {
2005 dbi.postInsert(data);
2006 } else if (action == IDbEventInterceptor.PRE_UPDATE) {
2007 operation = dbi.preUpdate(data);
2008 denyMessage = "dbforms.events.update.nogrant";
2009 } else if (action == IDbEventInterceptor.POST_UPDATE) {
2010 dbi.postUpdate(data);
2011 } else if (action == IDbEventInterceptor.PRE_DELETE) {
2012 operation = dbi.preDelete(data);
2013 denyMessage = "dbforms.events.delete.nogrant";
2014 } else if (action == IDbEventInterceptor.POST_DELETE) {
2015 dbi.postDelete(data);
2016 } else if (action == IDbEventInterceptor.PRE_SELECT) {
2017 operation = dbi.preSelect(data);
2018 denyMessage = "dbforms.events.view.nogrant";
2019 } else if (action == IDbEventInterceptor.POST_SELECT) {
2020 dbi.postSelect(data);
2021 } else if (action == IDbEventInterceptor.PRE_ADDROW) {
2022 operation = dbi.preAddRow(data);
2023 denyMessage = "dbforms.events.addrow.nogrant";
2024 } else if (action == IDbEventInterceptor.POST_ADDROW) {
2025 dbi.postAddRow(data);
2026 }
2027
2028 switch (operation) {
2029 case IDbEventInterceptor.DENY_OPERATION:
2030 s = MessageResourcesInternal.getMessage(denyMessage, data
2031 .getRequest().getLocale(),
2032 new String[] { getName() });
2033 throw new MultipleValidationException(s);
2034
2035 case IDbEventInterceptor.IGNORE_OPERATION:
2036 return operation;
2037
2038 default:
2039 break;
2040 }
2041 }
2042 } catch (ClassNotFoundException cnfe) {
2043 logCat.warn("ClassNotFoundException: " + cnfe.getMessage());
2044 throw new MultipleValidationException(cnfe.getMessage());
2045 } catch (InstantiationException ie) {
2046 logCat.warn(" InstantiationException : " + ie.getMessage());
2047 throw new MultipleValidationException(ie.getMessage());
2048 } catch (IllegalAccessException iae) {
2049 logCat.warn(" IllegalAccessException : " + iae.getMessage());
2050 throw new MultipleValidationException(iae.getMessage());
2051 } catch (MultipleValidationException mve) {
2052 throw mve;
2053 } catch (ValidationException ve) {
2054 throw new MultipleValidationException(ve.getMessage());
2055 }
2056
2057 return IDbEventInterceptor.GRANT_OPERATION;
2058 }
2059
2060
2061
2062
2063 /***
2064 * This metod is useful for logging / debugging purposes only.
2065 *
2066 * @return a string containing the Table name and field values
2067 */
2068 public String toString() {
2069 StringBuffer buf = new StringBuffer();
2070 buf.append("\nname=");
2071 buf.append(name);
2072 buf.append(" ");
2073 buf.append("\nid=");
2074 buf.append(String.valueOf(getId()));
2075 buf.append(" ");
2076
2077 if (getFields() != null) {
2078 for (int i = 0; i < getFields().size(); i++) {
2079 Field f = (Field) getFields().elementAt(i);
2080 buf.append("\nfield: ");
2081 buf.append(f.toString());
2082 }
2083 }
2084
2085 return buf.toString();
2086 }
2087
2088 /***
2089 * Returns the part of the orderby-clause represented by this FieldValue
2090 * object. <br>
2091 * (ASC will be not printed because it is defined DEFAULT in SQL if there
2092 * are RDBMS which do not tolerate this please let me know; then i'll change
2093 * it).
2094 *
2095 * @param fvOrder
2096 * FieldValue array used to build a cumulation of rules for
2097 * ordering (sorting) and restricting fields
2098 *
2099 * @return the part of the orderby-clause represented by this FieldValue
2100 * object
2101 */
2102 protected String getQueryOrderBy(FieldValue[] fvOrder) {
2103 StringBuffer buf = new StringBuffer();
2104
2105 if (fvOrder != null) {
2106 for (int i = 0; i < fvOrder.length; i++) {
2107 buf.append(fvOrder[i].getField().getName());
2108
2109 if (fvOrder[i].getSortDirection() == Constants.ORDER_DESCENDING) {
2110 buf.append(" DESC");
2111 }
2112
2113 if (i < (fvOrder.length - 1)) {
2114 buf.append(",");
2115 }
2116 }
2117 }
2118
2119 return buf.toString();
2120 }
2121
2122 /***
2123 * Returns the FROM part of a insert/delete/update query.
2124 *
2125 * @return the FROM part of a insert/delete/update query
2126 */
2127 protected String getQueryToChange() {
2128 return getQueryFrom();
2129 }
2130
2131 /***
2132 * Returns the WHERE part of a query.
2133 *
2134 * @param fvEqual
2135 * FieldValue array used to restrict a set in a subform where all
2136 * "childFields" in the resultset match their respective
2137 * "parentFields" in main form
2138 * @param fvOrder
2139 * FieldValue array used to build a cumulation of rules for
2140 * ordering (sorting) and restricting fields
2141 * @param compareMode
2142 * compare mode value for generating the order clause
2143 *
2144 * @return the WHERE part of a query
2145 */
2146 protected String getQueryWhere(FieldValue[] fvEqual, FieldValue[] fvOrder,
2147 int compareMode) {
2148 boolean firstTermExists = false;
2149 StringBuffer buf = new StringBuffer();
2150
2151
2152 if (!FieldValue.isNull(fvEqual)) {
2153
2154 buf.append(" ( ");
2155
2156 if (fvEqual[0].getSearchMode() == Constants.SEARCHMODE_NONE) {
2157 buf.append(getWhereClause(fvEqual));
2158 } else {
2159 buf.append(getWhereEqualsSearchClause(fvEqual));
2160 }
2161
2162 buf.append(" ) ");
2163 firstTermExists = true;
2164 }
2165
2166
2167
2168
2169 if (!FieldValue.isNull(fvOrder)
2170 && (compareMode != Constants.COMPARE_NONE)) {
2171 buf.append(firstTermExists ? " AND ( " : "");
2172 buf.append(getWhereAfterClause(fvOrder, compareMode));
2173 buf.append(firstTermExists ? " ) " : "");
2174 }
2175
2176 return buf.toString();
2177 }
2178
2179 /***
2180 * DOCUMENT ME!
2181 *
2182 * @param type
2183 * DOCUMENT ME!
2184 * @param id
2185 * DOCUMENT ME!
2186 *
2187 * @return DOCUMENT ME!
2188 */
2189 protected boolean checkFieldId(int type, int aid) {
2190 int i = aid / MAXFIELDS;
2191 return i == type;
2192 }
2193
2194 /***
2195 * DOCUMENT ME!
2196 *
2197 * @param type
2198 * DOCUMENT ME!
2199 * @param id
2200 * DOCUMENT ME!
2201 *
2202 * @return DOCUMENT ME!
2203 */
2204 protected int decodeFieldId(int type, int aid) {
2205 return aid - (type * MAXFIELDS);
2206 }
2207
2208 /***
2209 * DOCUMENT ME!
2210 *
2211 * @param type
2212 * DOCUMENT ME!
2213 * @param id
2214 * DOCUMENT ME!
2215 *
2216 * @return DOCUMENT ME!
2217 */
2218 protected int encodeFieldId(int type, int aid) {
2219 return (type * MAXFIELDS) + aid;
2220 }
2221
2222 /***
2223 * returns an SQLExpression based on the given FieldValue
2224 *
2225 * @param fv
2226 * the FieldValue
2227 *
2228 * @return string holding the SQL Expression
2229 */
2230 private String getSQLExpression(FieldValue fv) {
2231 StringBuffer buf = new StringBuffer();
2232
2233
2234 Field f = fv.getField();
2235 String fieldName = Util.isNull(f.getExpression()) ? f.getName() : f
2236 .getExpression();
2237 buf.append(fieldName);
2238
2239
2240 switch (fv.getOperator()) {
2241 case Constants.FILTER_EQUAL:
2242 buf.append(" = ");
2243 buf.append(" ? ");
2244
2245 break;
2246
2247 case Constants.FILTER_NOT_EQUAL:
2248 buf.append(" <> ");
2249 buf.append(" ? ");
2250
2251 break;
2252
2253 case Constants.FILTER_GREATER_THEN:
2254 buf.append(" > ");
2255 buf.append(" ? ");
2256
2257 break;
2258
2259 case Constants.FILTER_SMALLER_THEN:
2260 buf.append(" < ");
2261 buf.append(" ? ");
2262
2263 break;
2264
2265 case Constants.FILTER_GREATER_THEN_EQUAL:
2266 buf.append(" >= ");
2267 buf.append(" ? ");
2268
2269 break;
2270
2271 case Constants.FILTER_SMALLER_THEN_EQUAL:
2272 buf.append(" <= ");
2273 buf.append(" ? ");
2274
2275 break;
2276
2277 case Constants.FILTER_LIKE:
2278
2279 if (FieldTypes.isCHAR(f.getType())) {
2280 buf.append(" LIKE ");
2281 } else {
2282 buf.append(" = ");
2283 }
2284
2285 buf.append(" ? ");
2286
2287 break;
2288
2289 case Constants.FILTER_NULL:
2290 buf.append(" IS NULL ");
2291
2292 break;
2293
2294 case Constants.FILTER_NOT_NULL:
2295 buf.append(" IS NOT NULL ");
2296
2297 break;
2298
2299 case Constants.FILTER_EMPTY:
2300
2301 if (FieldTypes.isCHAR(f.getType())) {
2302 buf.append(" = '' ");
2303 buf.append(" OR ");
2304 }
2305
2306 buf.append(fieldName);
2307 buf.append(" IS NULL ");
2308
2309 break;
2310
2311 case Constants.FILTER_NOT_EMPTY:
2312
2313 if (FieldTypes.isCHAR(f.getType())) {
2314 buf.append(" <> '' ");
2315 buf.append(" OR ");
2316 }
2317
2318 buf.append(fieldName);
2319 buf.append(" IS NOT NULL ");
2320
2321 break;
2322 }
2323
2324 return buf.toString();
2325 }
2326
2327 /***
2328 * situation: we have an array of fieldvalues which represents actual values
2329 * of order-determinating-fields. we want to build a part of the WHERE
2330 * clause which restricts the query to rows coming AFTER the row containing
2331 * the actual data. <br>
2332 * shortly described the following rule is applied:
2333 *
2334 * <pre>
2335 *
2336 *
2337 *
2338 *
2339 *
2340 *
2341 *
2342 *
2343 *
2344 * +--------------------------------------------------------------------------------------------------+
2345 * | RULE = R1 AND R2 AND ... AND Rn |
2346 * | 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* |
2347 * +--------------------------------------------------------------------------------------------------+
2348 * For background info email joepeer@wap-force.net
2349 *
2350 *
2351 *
2352 *
2353 *
2354 *
2355 *
2356 *
2357 *
2358 * </pre>
2359 *
2360 * IMPORTANT NOTE: the indizes of the fv-array indicate implicitly the
2361 * order-priority of the fields. <br>
2362 * example: if we have ORDER BY id,name,age -> then fv[0] should contain
2363 * field id, fv[1] should contain field name, fv[2] should contain field age
2364 *
2365 * @param fv
2366 * the array of FieldValue objects
2367 * @param compareMode
2368 * the comparison mode
2369 *
2370 * @return _part_ of a WHERE-clause
2371 */
2372 private String getWhereAfterClause(FieldValue[] fv, int compareMode) {
2373 String conj;
2374 String disj;
2375 String opA1;
2376 String opA2;
2377 String opB1;
2378 String opB2;
2379
2380
2381 if (compareMode == Constants.COMPARE_INCLUSIVE) {
2382 opA1 = ">=";
2383 opA2 = "<=";
2384 opB1 = ">";
2385 opB2 = "<";
2386 conj = " AND ";
2387 disj = " OR ";
2388 } else {
2389 opA1 = ">";
2390 opA2 = "<";
2391 opB1 = ">=";
2392 opB2 = "<=";
2393 conj = " OR ";
2394 disj = " AND ";
2395 }
2396
2397 StringBuffer buf = new StringBuffer();
2398
2399 if ((fv != null) && (fv.length > 0)) {
2400
2401 for (int i = 0; i < fv.length; i++) {
2402
2403 buf.append("(");
2404 buf.append(fv[i].getField().getName());
2405 buf
2406 .append((fv[i].getSortDirection() == Constants.ORDER_ASCENDING) ? opA1
2407 : opA2);
2408
2409
2410 buf.append(" ? ");
2411
2412
2413
2414 if (i > 0) {
2415 for (int j = i - 1; j >= 0; j--) {
2416 buf.append(disj);
2417 buf.append(fv[j].getField().getName());
2418 buf
2419 .append((fv[j].getSortDirection() == Constants.ORDER_ASCENDING) ? opB1
2420 : opB2);
2421
2422
2423 buf.append(" ? ");
2424 }
2425 }
2426
2427 buf.append(" ) ");
2428
2429 if (i < (fv.length - 1)) {
2430 buf.append(conj);
2431
2432
2433 }
2434 }
2435 }
2436
2437 return buf.toString();
2438 }
2439
2440 /***
2441 * situation: we have an array of fieldvalues (== fields + actual value )
2442 * with search information and we want to build a where - clause [that
2443 * should restrict the resultset in matching to the search fields].
2444 *
2445 * <pre>
2446 *
2447 *
2448 *
2449 *
2450 *
2451 *
2452 *
2453 *
2454 *
2455 * convention: index 0-n => AND
2456 * index (n+1)-m => OR
2457 * examples
2458 * (A = 'meier' AND X = 'joseph') AND (AGE = '10')
2459 * (A = 'meier' ) AND (X = 'joseph' OR AGE = '10')
2460 * (X = 'joseph' OR AGE = '10')
2461 * (A = 'meier' AND X = 'joseph')
2462 * for comparing to code:
2463 * §1 §2 §3 §2 §4 §5 §6 §2 §7
2464 * ( A = 'smith' AND X LIKE 'jose%' ) AND ( AGE = '10' )
2465 *
2466 *
2467 *
2468 *
2469 *
2470 *
2471 *
2472 *
2473 *
2474 * </pre>
2475 *
2476 * @param fv
2477 * Description of the Parameter
2478 *
2479 * @return _part_ of a WHERE-clause
2480 *
2481 * @todo hkk checkme: implementation is different to comment! comment says
2482 * that all or fields will be anded to all and fields (second
2483 * example!) implementation do an or instead????
2484 */
2485 private String getWhereEqualsSearchClause(FieldValue[] fv) {
2486 StringBuffer buf = new StringBuffer();
2487
2488 if ((fv != null) && (fv.length > 0)) {
2489 int mode;
2490 int oldMode = -1;
2491
2492 for (int i = 0; i < fv.length; i++) {
2493 mode = fv[i].getSearchMode();
2494
2495 if (oldMode != mode) {
2496 oldMode = mode;
2497 buf.append("(");
2498
2499
2500 }
2501
2502
2503 buf.append(getSQLExpression(fv[i]));
2504
2505 if ((i < (fv.length - 1))
2506 && (fv[i + 1].getSearchMode() == mode)) {
2507 buf.append((mode == Constants.SEARCHMODE_AND) ? "AND "
2508 : "OR ");
2509
2510
2511 } else {
2512
2513 buf.append(")");
2514
2515
2516 if (i != (fv.length - 1)) {
2517 buf.append(" OR ");
2518
2519
2520 }
2521 }
2522 }
2523 }
2524
2525 return buf.toString();
2526 }
2527
2528 /***
2529 * The orderBy clause usually defaults to ASCending order. A user may add,
2530 * if we/she wishes the keyword ASC (ascending) or DESC (descending) to
2531 * specify a particular direction. <br>
2532 * Code in this method parses the orderBy clause and finds an occurence of
2533 * either ASC or DESC. Suppose your field name is "DESCRIPTION" !<br>
2534 * This name contains "DESC" therefore causing unexpected behaviour. This
2535 * bug fix consists of fine-tunning the parsing function to take into
2536 * consideration the sequence of parameters: 1-Field 2-Command
2537 *
2538 * @param order
2539 * order string
2540 *
2541 * @return a vector of Field objects
2542 */
2543 private Vector createOrderFVFromAttribute(String order) {
2544 Vector result = new Vector();
2545
2546 if (order != null) {
2547 StringTokenizer st = new StringTokenizer(order, ",");
2548
2549 while (st.hasMoreTokens()) {
2550
2551 String token = st.nextToken().trim();
2552 logCat.info("token = " + token);
2553
2554 int sortDirection = Constants.ORDER_ASCENDING;
2555
2556
2557
2558 int index = token.indexOf(" ");
2559
2560
2561 if (index != -1)
2562
2563 {
2564 String command = token.substring(index).toUpperCase();
2565 int pos = command.indexOf("ASC");
2566
2567 if (pos == -1)
2568 {
2569 pos = command.indexOf("DESC");
2570
2571 if (index != -1) {
2572 sortDirection = Constants.ORDER_DESCENDING;
2573
2574
2575 }
2576 }
2577 }
2578
2579 String fieldName;
2580
2581 if (index == -1) {
2582 fieldName = token.trim();
2583 } else {
2584 fieldName = token.substring(0, index).trim();
2585 }
2586
2587 Field f = this.getFieldByName(fieldName);
2588
2589 if (f != null) {
2590 FieldValue fv = FieldValue.createFieldValueForSorting(f,
2591 sortDirection);
2592 logCat.info("Field '" + fieldName + "' is ordered in mode:"
2593 + sortDirection);
2594 result.addElement(fv);
2595 }
2596 }
2597 }
2598
2599 return result;
2600 }
2601
2602 /***
2603 * DOCUMENT ME!
2604 *
2605 * @param request
2606 * @param paramStub
2607 * @param sortFields
2608 *
2609 * @return
2610 */
2611 private Vector createOrderFVFromRequest(HttpServletRequest request,
2612 String paramStub, Vector sortFields) {
2613 Vector result = new Vector();
2614 int fieldIndex = paramStub.length() + 1;
2615
2616
2617 for (int i = 0; i < sortFields.size(); i++) {
2618 String dataParam = (String) sortFields.elementAt(i);
2619 int fieldId = Integer.parseInt(dataParam.substring(fieldIndex));
2620 String sortState = ParseUtil.getParameter(request, dataParam);
2621 logCat.info("### dataparam=" + dataParam);
2622 logCat.info("### fieldId=" + fieldId);
2623 logCat.info("### sortState=" + sortState);
2624
2625 if (sortState.equalsIgnoreCase("asc")
2626 || sortState.equalsIgnoreCase("desc")) {
2627 int sortDirection = sortState.equalsIgnoreCase("asc") ? Constants.ORDER_ASCENDING
2628 : Constants.ORDER_DESCENDING;
2629 FieldValue fv = FieldValue.createFieldValueForSorting(
2630 getField(fieldId), sortDirection);
2631 result.addElement(fv);
2632 }
2633 }
2634
2635 return result;
2636 }
2637
2638
2639
2640
2641 /***
2642 * Creates a token string with the format:
2643 *
2644 * <pre>
2645 *
2646 *
2647 *
2648 *
2649 *
2650 *
2651 *
2652 *
2653 *
2654 * field.id : field.length : field.value
2655 *
2656 *
2657 *
2658 *
2659 *
2660 *
2661 *
2662 *
2663 *
2664 * </pre>
2665 *
2666 * @param field
2667 * the field object
2668 * @param fieldValue
2669 * the field value
2670 *
2671 * @return the token string
2672 */
2673 private String createToken(Field field, String fieldValue) {
2674 StringBuffer buf = new StringBuffer();
2675
2676 buf.append(field.getId());
2677 buf.append(":");
2678
2679 if (!Util.isNull(fieldValue)) {
2680 buf.append(fieldValue.length());
2681 buf.append(":");
2682 buf.append(fieldValue);
2683 } else {
2684 buf.append(0);
2685 buf.append(":");
2686 }
2687
2688 return buf.toString();
2689 }
2690
2691 /***
2692 * Fill the input PreparedStatement object
2693 *
2694 * @param cur
2695 * the FieldValue object
2696 * @param ps
2697 * the PreparedStatement object
2698 * @param curCol
2699 * the current PreparedStatement column; points to a
2700 * PreparedStatement xxx value
2701 *
2702 * @return DOCUMENT ME!
2703 *
2704 * @exception SQLException
2705 * if any error occurs
2706 */
2707 private int fillPreparedStatement(FieldValue cur, PreparedStatement ps,
2708 int curCol) throws SQLException {
2709 logCat.info("setting col " + curCol + " with name "
2710 + cur.getField().getName() + " to value " + cur.getFieldValue()
2711 + " of type " + cur.getField().getType() + " operator "
2712 + cur.getOperator());
2713
2714 Field curField = cur.getField();
2715 Object curValue = cur.getFieldValueAsObject();
2716
2717
2718
2719
2720 if (FieldTypes.isCHAR(curField.getType())) {
2721 String valueStr = cur.getFieldValue();
2722
2723 switch (cur.getSearchAlgorithm()) {
2724 case Constants.SEARCH_ALGO_WEAK_START:
2725 valueStr = '%' + valueStr;
2726
2727 break;
2728
2729 case Constants.SEARCH_ALGO_WEAK_END:
2730 valueStr = valueStr + '%';
2731
2732 break;
2733
2734 case Constants.SEARCH_ALGO_WEAK_START_END:
2735 valueStr = '%' + valueStr + '%';
2736
2737 break;
2738 }
2739
2740 curValue = valueStr;
2741 }
2742
2743 switch (cur.getOperator()) {
2744 case Constants.FILTER_NULL:
2745 break;
2746
2747 case Constants.FILTER_NOT_NULL:
2748 break;
2749
2750 case Constants.FILTER_EMPTY:
2751 break;
2752
2753 case Constants.FILTER_NOT_EMPTY:
2754 break;
2755
2756 default:
2757 JDBCDataHelper.fillWithData(ps, curField.getEscaper(), curCol,
2758 curValue, curField.getType(), getBlobHandlingStrategy());
2759 curCol++;
2760 }
2761
2762 return curCol;
2763 }
2764
2765 /***
2766 * This method generated a datastructure holding sorting information from
2767 * "orderBy" only the keys are used as order criteria. By default all
2768 * ascending (check SQL spec + docu).
2769 */
2770 private void initDefaultOrderFromKeys() {
2771 defaultOrder = new FieldValue[getKey().size()];
2772
2773 for (int i = 0; i < this.getKey().size(); i++) {
2774 Field keyField = (Field) getKey().elementAt(i);
2775 defaultOrder[i] = FieldValue.createFieldValueForSorting(keyField,
2776 Constants.ORDER_ASCENDING);
2777 }
2778
2779 logCat.info("Table.initDefaultOrderfromKey done.");
2780 }
2781
2782 /***
2783 * situation: we have built a query (involving the getWhereEqualsClause()
2784 * method) and now we want to prepare the statemtent - provide actual values
2785 * for the the '?' placeholders.
2786 *
2787 * @param fv
2788 * the array of FieldValue objects
2789 * @param ps
2790 * the PreparedStatement object
2791 * @param curCol
2792 * the current PreparedStatement column; points to a
2793 * PreparedStatement xxx value
2794 *
2795 * @return the value of the current column
2796 *
2797 * @exception SQLException
2798 * if any error occurs
2799 */
2800 private int populateWhereAfterClause(FieldValue[] fv, PreparedStatement ps,
2801 int curCol) throws SQLException {
2802 if ((fv != null) && (fv.length > 0)) {
2803
2804 for (int i = 0; i < fv.length; i++) {
2805
2806 curCol = fillPreparedStatement(fv[i], ps, curCol);
2807
2808
2809
2810 if (i > 0) {
2811 for (int j = i - 1; j >= 0; j--) {
2812 curCol = fillPreparedStatement(fv[j], ps, curCol);
2813 }
2814 }
2815 }
2816 }
2817
2818 return curCol;
2819 }
2820
2821 protected static DbFormsConfig getConfig() {
2822 DbFormsConfig config = null;
2823 try {
2824 config = DbFormsConfigRegistry.instance().lookup();
2825 } catch (Exception e) {
2826 logCat.error("no config object", e);
2827 }
2828 return config;
2829 }
2830
2831 }