View Javadoc

1   /*
2    * $Header: /cvsroot/jdbforms/dbforms/src/org/dbforms/config/ResultSetVector.java,v 1.25 2005/12/03 08:09:47 hkollmann Exp $
3    * $Revision: 1.25 $
4    * $Date: 2005/12/03 08:09:47 $
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.interfaces.DbEventInterceptorData;
30  import org.dbforms.interfaces.IDbEventInterceptor;
31  import org.dbforms.interfaces.IEscaper;
32  
33  import org.dbforms.util.Util;
34  
35  import java.sql.ResultSet;
36  import java.sql.ResultSetMetaData;
37  import java.sql.SQLException;
38  
39  import java.util.HashMap;
40  import java.util.Hashtable;
41  import java.util.Map;
42  import java.util.Vector;
43  
44  /***
45   * <p>
46   * In version 0.5, this class held the actual data of a ResultSet (SELECT from a
47   * table). The main weakness of this class was that it used too much memory and
48   * processor time:
49   * 
50   * <ul>
51   * <li>1. every piece of data gots stored in an array (having a table with a
52   * million datasets will mean running into trouble because all the memory gets
53   * allocated at one time.)</li>
54   * <li>2. every piece of data gots converted into a String and trim()ed</li>
55   * </ul>
56   * </p>
57   * 
58   * <p>
59   * since version 0.7 DbForms queries only those record from the database the
60   * user really wants to see. this way you can query from a table with millions
61   * of records and you will still have no memory problems, [exception: you choose
62   * count="" in DbForms-tag :=) -> see org.dbforms.taglib.DbFormTag]
63   * </p>
64   * 
65   * @author Joe Peer
66   */
67  public class ResultSetVector implements java.io.Serializable {
68  	private static Log logCat = LogFactory.getLog(ResultSetVector.class
69  			.getName());
70  
71  	private Hashtable selectFieldsHashtable;
72  
73  	private Map attributes = new HashMap();
74  
75  	private Table table = null;
76  
77  	private Vector objectVector = new Vector();
78  
79  	private Vector selectFields = new Vector();
80  
81  	private boolean firstPage = false;
82  
83  	private boolean lastPage = false;
84  
85  	// logging category for this class
86  	private int pointer = 0;
87  
88  	/***
89  	 * Creates a new, empty ResultSetVector object.
90  	 */
91  	public ResultSetVector() {
92  	}
93  
94  	/***
95  	 * Creates a new ResultSetVector object with the given FieldList
96  	 * 
97  	 * @param table
98  	 *            The FieldList to use
99  	 */
100 	public ResultSetVector(Table table) {
101 		this.table = table;
102 
103 		if (table != null) {
104 			setupSelectFieldsHashtable(table.getFields());
105 			setupSelectFieldsHashtable(table.getCalcFields());
106 		}
107 	}
108 
109 	/***
110 	 * Creates a new ResultSetVector object.
111 	 * 
112 	 * @param table
113 	 *            DOCUMENT ME!
114 	 * @param selectedFields
115 	 *            DOCUMENT ME!
116 	 */
117 	public ResultSetVector(Table table, Vector selectedFields) {
118 		this.table = table;
119 		setupSelectFieldsHashtable(selectedFields);
120 	}
121 
122 	/***
123 	 * Checks if the given ResultSetVector is null
124 	 * 
125 	 * @param rsv
126 	 *            ResultSetVector to check
127 	 * 
128 	 * @return true if ResultSetVector is null
129 	 */
130 	public static final boolean isNull(ResultSetVector rsv) {
131 		return ((rsv == null) || (rsv.size() == 0));
132 	}
133 
134 	/***
135 	 * Stores a value in the attributes list
136 	 * 
137 	 * @param key
138 	 *            key for the value
139 	 * @param value
140 	 *            value to store
141 	 */
142 	public void setAttribute(String key, Object value) {
143 		attributes.put(key, value);
144 	}
145 
146 	/***
147 	 * reads a value from the attributes list
148 	 * 
149 	 * @param key
150 	 *            key to read
151 	 * 
152 	 * @return The value. If not found null
153 	 */
154 	public Object getAttribute(String key) {
155 		return attributes.get(key);
156 	}
157 
158 	/***
159 	 * DOCUMENT ME!
160 	 * 
161 	 * @return Returns the attributes.
162 	 */
163 	public Map getAttributes() {
164 		return attributes;
165 	}
166 
167 	public String getTableName() {
168 		String result = null;
169 		if (table != null)
170 		   result = table.getName();
171 		return result;
172 	}
173 	
174 	/***
175 	 * DOCUMENT ME!
176 	 * 
177 	 * @return DOCUMENT ME!
178 	 */
179 	public String[] getCurrentRow() {
180 		Object[] obj = getCurrentRowAsObjects();
181 		String[] res = null;
182 
183 		if (obj != null) {
184 			res = new String[obj.length];
185 
186 			for (int i = 0; i < obj.length; i++) {
187 				res[i] = getField(i);
188 			}
189 		}
190 
191 		return res;
192 	}
193 
194 	/***
195 	 * DOCUMENT ME!
196 	 * 
197 	 * @return DOCUMENT ME!
198 	 * 
199 	 * @throws IllegalArgumentException
200 	 *             DOCUMENT ME!
201 	 */
202 	public FieldValues getCurrentRowAsFieldValues() {
203 		if (selectFields == null) {
204 			throw new IllegalArgumentException(
205 					"no field vector was provided to this result");
206 		}
207 
208 		String[] rowData = getCurrentRow();
209 
210 		if (rowData == null) {
211 			return null;
212 		}
213 
214 		FieldValues fvHT = new FieldValues();
215 
216 		for (int i = 0; i < selectFields.size(); i++) {
217 			Field f = (Field) selectFields.elementAt(i);
218 			FieldValue fv = new FieldValue(f, rowData[i]);
219 			fvHT.put(fv);
220 		}
221 
222 		return fvHT;
223 	}
224 
225 	/***
226 	 * DOCUMENT ME!
227 	 * 
228 	 * @return DOCUMENT ME!
229 	 * 
230 	 * @throws IllegalArgumentException
231 	 *             DOCUMENT ME!
232 	 */
233 	public Map getCurrentRowAsMap() {
234 		if (selectFields == null) {
235 			throw new IllegalArgumentException(
236 					"no field vector was provided to this result");
237 		}
238 
239 		String[] rowData = getCurrentRow();
240 
241 		if (rowData == null) {
242 			return null;
243 		}
244 
245 		Hashtable ht = new Hashtable();
246 
247 		for (int i = 0; i < selectFields.size(); i++) {
248 			Field f = (Field) selectFields.elementAt(i);
249 			ht.put(f.getName(), rowData[i]);
250 		}
251 
252 		return ht;
253 	}
254 
255 	/***
256 	 * DOCUMENT ME!
257 	 * 
258 	 * @return DOCUMENT ME!
259 	 */
260 	public Object[] getCurrentRowAsObjects() {
261 		Object[] res = null;
262 		if (isPointerLegal(pointer)) {
263 			res = (Object[]) objectVector.elementAt(pointer);
264 		} 
265 		return res;
266 	}
267 
268 	/***
269 	 * returns the fieldValues String representation given by index i
270 	 * 
271 	 * @param i
272 	 *            Index into the objectArray
273 	 * 
274 	 * @return the object
275 	 */
276 	public String getField(int i) {
277 		Object obj = getFieldAsObject(i);
278 
279 		return (obj != null) ? obj.toString() : "";
280 	}
281 
282 	/***
283 	 * returns the fieldValues string representation given by it's name
284 	 * 
285 	 * @param fieldName
286 	 *            name of the field
287 	 * 
288 	 * @return the object
289 	 */
290 	public String getField(String fieldName) {
291 		int fieldIndex = getFieldIndex(fieldName);
292 
293 		if (fieldIndex < 0) {
294 			return null;
295 		}
296 
297 		return getField(fieldIndex);
298 	}
299 
300 	/***
301 	 * returns the fieldValues Object given by index i
302 	 * 
303 	 * @param i
304 	 *            Index into the objectArray
305 	 * 
306 	 * @return the object
307 	 */
308 	public Object getFieldAsObject(int i) {
309 		return getFieldAsObject(pointer, i);
310 	}
311 
312 	/***
313 	 * returns the fieldValues Object given by row row and index i
314 	 * 
315 	 * @param row
316 	 *            row in the rsv
317 	 * @param i
318 	 *            Index into the objectArray
319 	 * 
320 	 * @return the object
321 	 */
322 	public Object getFieldAsObject(int row, int i) {
323 		Object res = null;
324 		if (isPointerLegal(row)) {
325 			try {
326 				res = ((Object[]) objectVector.elementAt(row))[i];
327 			} catch (Exception e) {
328 				logCat.error("getFieldAsObject", e);
329 			}
330 		} 
331 		return res;
332 	}
333 
334 	/***
335 	 * sets the fieldValue Object given by row row and index i
336 	 * 
337 	 * @param row
338 	 *            row in the rsv
339 	 * @param i
340 	 *            Index into the objectArray
341 	 * 
342 	 * @return the object
343 	 */
344 	public void setFieldAsObject(int row, int i, Object obj) {
345 		if (isPointerLegal(row)) {
346 			try {
347 				Object[] objRow = (Object[]) objectVector.elementAt(row);
348 				objRow[i] = obj;
349 			} catch (Exception e) {
350 				logCat.error("setFieldAsObject", e);
351 			}
352 		}
353 	}
354 
355 	/***
356 	 * returns the fieldValues Object given by it's name
357 	 * 
358 	 * @param fieldName
359 	 *            name of the field
360 	 * 
361 	 * @return the object
362 	 */
363 	public Object getFieldAsObject(String fieldName) {
364 		return getFieldAsObject(pointer, fieldName);
365 	}
366 
367 	/***
368 	 * returns the fieldValues Object given by row row and fieldName
369 	 * 
370 	 * @param row
371 	 *            row in the rsv
372 	 * 
373 	 * @return the object
374 	 */
375 	public Object getFieldAsObject(int row, String fieldName) {
376 		int fieldIndex = getFieldIndex(fieldName);
377 
378 		if (fieldIndex < 0) {
379 			return null;
380 		}
381 
382 		return getFieldAsObject(row, fieldIndex);
383 	}
384 
385 	/***
386 	 * sets the fieldValue Object given by row row and fieldName
387 	 * 
388 	 * @param row
389 	 *            row in the rsv
390 	 * @param fieldName
391 	 *            name of the field
392 	 * 
393 	 * @return the object
394 	 */
395 	public void setFieldAsObject(int row, String fieldName, Object obj) {
396 		int fieldIndex = getFieldIndex(fieldName);
397 		if (fieldIndex >= 0) {
398 			setFieldAsObject(row, fieldIndex, obj);
399 		}
400 	}
401 
402 	/***
403 	 * gets the Field object to a given fieldName
404 	 * 
405 	 * @param fieldName
406 	 *            name of the field
407 	 * 
408 	 * @return the Field object of the given name null if not found
409 	 */
410 	public Field getFieldDescription(String fieldName) {
411 		return (Field) selectFieldsHashtable.get(fieldName);
412 	}
413 
414 	/***
415 	 * returns the index of a given fieldName
416 	 * 
417 	 * @param fieldName
418 	 *            name of the field
419 	 * 
420 	 * @return the index of the field in the data arrays
421 	 */
422 	public int getFieldIndex(String fieldName) {
423 		int res = -1;
424 
425 		if (!Util.isNull(fieldName)) {
426 			Field f = (Field) selectFieldsHashtable.get(fieldName);
427 
428 			if (f != null) {
429 				res = selectFields.indexOf(f);
430 			}
431 		}
432 
433 		return res;
434 	}
435 
436 	/***
437 	 * Return true if the current record is the first record
438 	 * 
439 	 * @return true if the first record is reached
440 	 */
441 	public boolean isFirst() {
442 		return (pointer == 0);
443 	}
444 
445 	/***
446 	 * DOCUMENT ME!
447 	 * 
448 	 * @param b
449 	 *            value to set
450 	 */
451 	public void setFirstPage(boolean b) {
452 		firstPage = b;
453 	}
454 
455 	/***
456 	 * DOCUMENT ME!
457 	 * 
458 	 * @return DOCUMENT ME!
459 	 */
460 	public boolean isFirstPage() {
461 		return firstPage;
462 	}
463 
464 	/***
465 	 * Return true if the current record is the last record
466 	 * 
467 	 * @return true if the last record is reached
468 	 */
469 	public boolean isLast() {
470 		return (pointer == (size() - 1));
471 	}
472 
473 	/***
474 	 * DOCUMENT ME!
475 	 * 
476 	 * @param b
477 	 *            value to set
478 	 */
479 	public void setLastPage(boolean b) {
480 		lastPage = b;
481 	}
482 
483 	/***
484 	 * DOCUMENT ME!
485 	 * 
486 	 * @return DOCUMENT ME!
487 	 */
488 	public boolean isLastPage() {
489 		return lastPage;
490 	}
491 
492 	/***
493 	 * DOCUMENT ME!
494 	 * 
495 	 * @param interceptorData
496 	 *            DOCUMENT ME!
497 	 * @param rs
498 	 *            DOCUMENT ME!
499 	 * 
500 	 * @throws SQLException
501 	 *             DOCUMENT ME!
502 	 */
503 	public void addResultSet(DbEventInterceptorData interceptorData,
504 			ResultSet rs) throws SQLException {
505 		ResultSetMetaData rsmd = rs.getMetaData();
506 		int columns = rsmd.getColumnCount();
507 		IEscaper escaper = null;
508 
509 		try { // #JP Jun 27, 2001
510 
511 			while (rs.next()) {
512 				Object[] objectRow = new Object[columns];
513 
514 				for (int i = 0; i < columns; i++) {
515 					if ((selectFields != null) && (i < selectFields.size())) {
516 						Field curField = (Field) selectFields.elementAt(i);
517 
518 						if (curField != null) {
519 							escaper = curField.getEscaper();
520 						}
521 					}
522 
523 					if (table != null) {
524 						escaper = (escaper == null) ? escaper : table
525 								.getEscaper();
526 					}
527 
528 					if (escaper == null) {
529 						try {
530 							escaper = DbFormsConfigRegistry.instance().lookup()
531 									.getEscaper();
532 						} catch (Exception e) {
533 							logCat.error(
534 									"cannot create the new default escaper", e);
535 						}
536 					}
537 
538 					objectRow[i] = JDBCDataHelper.getData(rs, escaper, i + 1);
539 				}
540 
541 				addRow(interceptorData, objectRow);
542 			}
543 		} finally {
544 			rs.close();
545 		}
546 	}
547 
548 	/***
549 	 * adds a row to the ResultSetVector
550 	 * 
551 	 * @param interceptorData
552 	 *            DOCUMENT ME!
553 	 * @param objectRow
554 	 *            row to add
555 	 */
556 	public void addRow(DbEventInterceptorData interceptorData,
557 			Object[] objectRow) {
558 		if (objectRow != null) {
559 			boolean doit = true;
560 			int size = (objectRow.length > selectFields.size()) ? objectRow.length
561 					: selectFields.size();
562 
563 			Object[] newRow = new Object[size];
564 
565 			for (int i = 0; i < objectRow.length; i++) {
566 				newRow[i] = objectRow[i];
567 			}
568 
569 			if ((interceptorData != null)
570 					&& (interceptorData.getTable() != null)) {
571 				interceptorData.setAttribute(DbEventInterceptorData.RESULTSET,
572 						this);
573 				interceptorData.setAttribute(DbEventInterceptorData.OBJECTROW,
574 						newRow);
575 
576 				int res = IDbEventInterceptor.GRANT_OPERATION;
577 
578 				try {
579 					res = interceptorData.getTable().processInterceptors(
580 							IDbEventInterceptor.PRE_ADDROW, interceptorData);
581 				} catch (MultipleValidationException e) {
582 					logCat.error("addRow", e);
583 				}
584 
585 				doit = (res == IDbEventInterceptor.GRANT_OPERATION);
586 			}
587 
588 			if (doit) {
589 				objectVector.addElement(newRow);
590 
591 				if ((interceptorData != null)
592 						&& (interceptorData.getTable() != null)) {
593 					try {
594 						interceptorData.getTable()
595 								.processInterceptors(
596 										IDbEventInterceptor.POST_ADDROW,
597 										interceptorData);
598 					} catch (MultipleValidationException e) {
599 						logCat.error("addRow", e);
600 					}
601 				}
602 			}
603 		}
604 	}
605 
606 	/***
607 	 * DOCUMENT ME!
608 	 */
609 	public void flip() {
610 		int vSize = this.size();
611 
612 		if (vSize > 1) {
613 			logCat.info("flipping " + vSize + " elements!");
614 
615 			for (int i = 1; i < vSize; i++) {
616 				Object o = objectVector.elementAt(i);
617 				objectVector.remove(i);
618 				objectVector.insertElementAt(o, 0);
619 			}
620 		}
621 	}
622 
623 	/***
624 	 * moves to the first record
625 	 */
626 	public void moveFirst() {
627 		this.pointer = 0;
628 	}
629 
630 	/***
631 	 * moves to the last record
632 	 */
633 	public void moveLast() {
634 		this.pointer = size() - 1;
635 	}
636 
637 	/***
638 	 * moves to the next record
639 	 * 
640 	 * @return true if end is reached
641 	 */
642 	public boolean moveNext() {
643 		pointer++;
644 
645 		return (pointer >= size());
646 	}
647 
648 	/***
649 	 * moves to the previous record
650 	 * 
651 	 * @return true if beginning is reached
652 	 */
653 	public boolean movePrevious() {
654 		pointer--;
655 
656 		return (pointer < 0);
657 	}
658 
659 	/***
660 	 * implements size()
661 	 * 
662 	 * @return the sizeof the vector
663 	 */
664 	public int size() {
665 		return objectVector.size();
666 	}
667 
668 	private boolean isPointerLegal(int p) {
669 		return ((p >= 0) && (p < size()));
670 	}
671 
672 	private void setupSelectFieldsHashtable(Vector paramSelectFields) {
673 		this.selectFields.addAll(paramSelectFields);
674 		selectFieldsHashtable = new Hashtable();
675 
676 		for (int i = 0; i < selectFields.size(); i++) {
677 			Field f = (Field) selectFields.elementAt(i);
678 			selectFieldsHashtable.put(f.getName(), f);
679 		}
680 	}
681 }