001: /*
002: * Copyright 2004 The Apache Software Foundation.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package javax.faces.model;
017:
018: import javax.faces.FacesException;
019: import java.sql.ResultSet;
020: import java.sql.SQLException;
021: import java.sql.ResultSetMetaData;
022: import java.util.*;
023:
024: /**
025: * see Javadoc of <a href="http://java.sun.com/javaee/javaserverfaces/1.2/docs/api/index.html">JSF Specification</a>
026: *
027: * @author Thomas Spiegl (latest modification by $Author: mbr $)
028: * @author Martin Marinschek
029: * @version $Revision: 512227 $ $Date: 2007-02-27 13:25:16 +0100 (Di, 27 Feb 2007) $
030: */
031: public class ResultSetDataModel extends DataModel {
032: // FIELDS
033:
034: private int _currentIndex = -1;
035:
036: /**
037: * The ResultSet being wrapped by this DataModel.
038: */
039: private ResultSet _resultSet = null;
040:
041: /**
042: * The MetaData of the ResultSet being wrapped by this DataModel.
043: */
044: private ResultSetMetaData _resultSetMetadata = null;
045:
046: /**
047: * Indicator for an updated row at the current position.
048: */
049: private boolean _currentRowUpdated = false;
050:
051: // CONSTRUCTORS
052: public ResultSetDataModel() {
053: this (null);
054: }
055:
056: public ResultSetDataModel(ResultSet resultSet) {
057:
058: super ();
059: setWrappedData(resultSet);
060:
061: }
062:
063: /** We don't know how many rows the result set has without scrolling
064: * through the whole thing.
065: */
066: public int getRowCount() {
067: return -1;
068: }
069:
070: /** Get the actual data of this row
071: * wrapped into a map.
072: * The specification is very strict about what has to be
073: * returned from here, so check the spec before
074: * modifying anything here.
075: */
076: public Object getRowData() {
077: if (_resultSet == null) {
078: return null;
079: } else if (!isRowAvailable()) {
080: throw new IllegalArgumentException(
081: "the requested row is not available in the ResultSet - you have scrolled beyond the end.");
082: }
083:
084: try {
085: return new WrapResultSetMap(String.CASE_INSENSITIVE_ORDER);
086: } catch (SQLException e) {
087: throw new FacesException(e);
088: }
089: }
090:
091: public int getRowIndex() {
092: return _currentIndex;
093: }
094:
095: public Object getWrappedData() {
096: return _resultSet;
097: }
098:
099: public boolean isRowAvailable() {
100: if (_resultSet == null) {
101: return false;
102: } else if (_currentIndex < 0) {
103: return false;
104: }
105:
106: try {
107: return _resultSet.absolute(_currentIndex + 1);
108: } catch (SQLException e) {
109: throw new FacesException(e);
110: }
111: }
112:
113: public void setRowIndex(int rowIndex) {
114: if (rowIndex < -1) {
115: throw new IllegalArgumentException(
116: "you cannot set the rowIndex to anything less than 0");
117: }
118:
119: // Handle the case of an updated row
120: if (_currentRowUpdated && _resultSet != null) {
121: try {
122: if (!_resultSet.rowDeleted())
123: _resultSet.updateRow();
124:
125: setCurrentRowUpdated(false);
126: } catch (SQLException e) {
127: throw new FacesException(e);
128: }
129: }
130:
131: int old = _currentIndex;
132: _currentIndex = rowIndex;
133:
134: //if no underlying data has been set, the listeners
135: //need not be notified
136: if (_resultSet == null)
137: return;
138:
139: //Notify all listeners of the upated row
140: DataModelListener[] listeners = getDataModelListeners();
141:
142: if ((old != _currentIndex) && (listeners != null)) {
143: Object rowData = null;
144:
145: if (isRowAvailable()) {
146: rowData = getRowData();
147: }
148:
149: DataModelEvent event = new DataModelEvent(this ,
150: _currentIndex, rowData);
151:
152: int n = listeners.length;
153:
154: for (int i = 0; i < n; i++) {
155: if (listeners[i] != null) {
156: listeners[i].rowSelected(event);
157: }
158: }
159: }
160: }
161:
162: public void setWrappedData(Object data) {
163: if (data == null) {
164: _resultSetMetadata = null;
165: _resultSet = null;
166: setRowIndex(-1);
167: } else {
168: _resultSetMetadata = null;
169: _resultSet = (ResultSet) data;
170: _currentIndex = -1;
171: setRowIndex(0);
172: }
173: }
174:
175: private ResultSetMetaData getResultSetMetadata() {
176: if (_resultSetMetadata == null) {
177: try {
178: _resultSetMetadata = _resultSet.getMetaData();
179: } catch (SQLException e) {
180: throw new FacesException(e);
181: }
182: }
183:
184: return _resultSetMetadata;
185: }
186:
187: private void setCurrentRowUpdated(boolean currentRowUpdated) {
188: _currentRowUpdated = currentRowUpdated;
189: }
190:
191: /* A map wrapping the result set and calling
192: * the corresponding operations on the result set,
193: * first setting the correct row index.
194: */
195: private class WrapResultSetMap extends TreeMap {
196: private static final long serialVersionUID = -4321143404567038922L;
197: private int _currentIndex;
198:
199: public WrapResultSetMap(Comparator comparator)
200: throws SQLException {
201: super (comparator);
202:
203: _currentIndex = ResultSetDataModel.this ._currentIndex;
204:
205: _resultSet.absolute(_currentIndex + 1);
206:
207: int columnCount = getResultSetMetadata().getColumnCount();
208:
209: for (int i = 1; i <= columnCount; i++) {
210: super .put(getResultSetMetadata().getColumnName(i),
211: getResultSetMetadata().getColumnName(i));
212: }
213: }
214:
215: public void clear() {
216: throw new UnsupportedOperationException(
217: "It is not allowed to remove from this map");
218: }
219:
220: public boolean containsValue(Object value) {
221: Set<Object> keys = keySet();
222: for (Iterator<Object> iterator = keys.iterator(); iterator
223: .hasNext();) {
224: Object object = get(iterator.next());
225: if (object == null) {
226: return value == null;
227: }
228: if (object.equals(value)) {
229: return true;
230: }
231:
232: }
233: return false;
234: }
235:
236: public Set entrySet() {
237: return new WrapResultSetEntries(this );
238: }
239:
240: public Object get(Object key) {
241: if (!containsKey(key))
242: return null;
243:
244: return basicGet(key);
245: }
246:
247: private Object basicGet(Object key) { //#################################################### remove
248: try {
249: _resultSet.absolute(_currentIndex + 1);
250:
251: return _resultSet
252: .getObject((String) getUnderlyingKey(key));
253:
254: } catch (SQLException e) {
255: throw new FacesException(e);
256: }
257: }
258:
259: public Set<Object> keySet() {
260: return new WrapResultSetKeys(this );
261: }
262:
263: public Object put(Object key, Object value) {
264: if (!containsKey(key))
265: throw new IllegalArgumentException(
266: "underlying result set does not provide this key");
267:
268: if (!(key instanceof String))
269: throw new IllegalArgumentException(
270: "key must be of type 'String', is of type : "
271: + (key == null ? "null" : key
272: .getClass().getName()));
273:
274: try {
275: _resultSet.absolute(_currentIndex + 1);
276:
277: Object oldValue = _resultSet
278: .getObject((String) getUnderlyingKey(key));
279:
280: if (oldValue == null ? value == null : oldValue
281: .equals(value))
282: return oldValue;
283:
284: _resultSet.updateObject((String) getUnderlyingKey(key),
285: value);
286:
287: setCurrentRowUpdated(true);
288:
289: return oldValue;
290: } catch (SQLException e) {
291: throw new FacesException(e);
292: }
293: }
294:
295: public void putAll(Map map) {
296: for (Iterator i = map.entrySet().iterator(); i.hasNext();) {
297: Map.Entry entry = (Map.Entry) i.next();
298: put(entry.getKey(), entry.getValue());
299: }
300: }
301:
302: public Object remove(Object key) {
303: throw new UnsupportedOperationException(
304: "It is not allowed to remove entries from this set.");
305: }
306:
307: public Collection<Object> values() {
308: return new WrapResultSetValues(this );
309: }
310:
311: Object getUnderlyingKey(Object key) {
312: return super .get(key);
313: }
314:
315: Iterator getUnderlyingKeys() {
316: return super .keySet().iterator();
317: }
318:
319: }
320:
321: private static class WrapResultSetEntries extends AbstractSet {
322: private WrapResultSetMap _wrapMap;
323:
324: public WrapResultSetEntries(WrapResultSetMap wrapMap) {
325: _wrapMap = wrapMap;
326: }
327:
328: public boolean add(Object o) {
329: throw new UnsupportedOperationException(
330: "it is not allowed to add to this set");
331: }
332:
333: public boolean addAll(Collection c) {
334: throw new UnsupportedOperationException(
335: "it is not allowed to add to this set");
336: }
337:
338: public void clear() {
339: throw new UnsupportedOperationException(
340: "it is not allowed to remove from this set");
341: }
342:
343: public boolean contains(Object o) {
344: if (o == null)
345: throw new NullPointerException();
346: if (!(o instanceof Map.Entry))
347: return false;
348:
349: Map.Entry e = (Map.Entry) o;
350: Object key = e.getKey();
351:
352: if (!_wrapMap.containsKey(key))
353: return false;
354:
355: Object value = e.getValue();
356: Object cmpValue = _wrapMap.get(key);
357:
358: return value == null ? cmpValue == null : value
359: .equals(cmpValue);
360: }
361:
362: public boolean isEmpty() {
363: return _wrapMap.isEmpty();
364: }
365:
366: public Iterator iterator() {
367: return new WrapResultSetEntriesIterator(_wrapMap);
368: }
369:
370: public boolean remove(Object o) {
371: throw new UnsupportedOperationException(
372: "it is not allowed to remove from this set");
373: }
374:
375: public boolean removeAll(Collection c) {
376: throw new UnsupportedOperationException(
377: "it is not allowed to remove from this set");
378: }
379:
380: public boolean retainAll(Collection c) {
381: throw new UnsupportedOperationException(
382: "it is not allowed to remove from this set");
383: }
384:
385: public int size() {
386: return _wrapMap.size();
387: }
388: }
389:
390: private static class WrapResultSetEntriesIterator implements
391: Iterator {
392:
393: private WrapResultSetMap _wrapMap = null;
394: private Iterator<Object> _keyIterator = null;
395:
396: public WrapResultSetEntriesIterator(WrapResultSetMap wrapMap) {
397: _wrapMap = wrapMap;
398: _keyIterator = _wrapMap.keySet().iterator();
399: }
400:
401: public boolean hasNext() {
402: return _keyIterator.hasNext();
403: }
404:
405: public Object next() {
406: return new WrapResultSetEntry(_wrapMap, _keyIterator.next());
407: }
408:
409: public void remove() {
410: throw new UnsupportedOperationException(
411: "It is not allowed to remove from this iterator");
412: }
413:
414: }
415:
416: private static class WrapResultSetEntry implements Map.Entry {
417:
418: private WrapResultSetMap _wrapMap;
419: private Object _entryKey;
420:
421: public WrapResultSetEntry(WrapResultSetMap wrapMap,
422: Object entryKey) {
423: _wrapMap = wrapMap;
424: _entryKey = entryKey;
425: }
426:
427: public boolean equals(Object o) {
428: if (o == null)
429: return false;
430:
431: if (!(o instanceof Map.Entry))
432: return false;
433:
434: Map.Entry cmpEntry = (Map.Entry) o;
435:
436: if (_entryKey == null ? cmpEntry.getKey() != null
437: : !_entryKey.equals(cmpEntry.getKey()))
438: return false;
439:
440: Object value = _wrapMap.get(_entryKey);
441: Object cmpValue = cmpEntry.getValue();
442:
443: return value == null ? cmpValue != null : value
444: .equals(cmpValue);
445: }
446:
447: public Object getKey() {
448: return _entryKey;
449: }
450:
451: public Object getValue() {
452: return _wrapMap.get(_entryKey);
453: }
454:
455: public int hashCode() {
456: int result;
457: result = (_entryKey != null ? _entryKey.hashCode() : 0);
458: result = 29
459: * result
460: + (_wrapMap.get(_entryKey) != null ? _wrapMap.get(
461: _entryKey).hashCode() : 0);
462: return result;
463: }
464:
465: public Object setValue(Object value) {
466: Object oldValue = _wrapMap.get(_entryKey);
467: _wrapMap.put(_entryKey, value);
468: return oldValue;
469: }
470: }
471:
472: private static class WrapResultSetKeys extends AbstractSet {
473: private WrapResultSetMap _wrapMap;
474:
475: public WrapResultSetKeys(WrapResultSetMap wrapMap) {
476: _wrapMap = wrapMap;
477: }
478:
479: public boolean add(Object o) {
480: throw new UnsupportedOperationException(
481: "It is not allowed to add to this set");
482: }
483:
484: public boolean addAll(Collection c) {
485: throw new UnsupportedOperationException(
486: "It is not allowed to add to this set");
487: }
488:
489: public void clear() {
490: throw new UnsupportedOperationException(
491: "It is not allowed to remove from this set");
492: }
493:
494: public boolean contains(Object obj) {
495: return _wrapMap.containsKey(obj);
496: }
497:
498: public boolean isEmpty() {
499: return _wrapMap.isEmpty();
500: }
501:
502: public Iterator iterator() {
503: return new WrapResultSetKeysIterator(_wrapMap);
504: }
505:
506: public boolean remove(Object o) {
507: throw new UnsupportedOperationException(
508: "It is not allowed to remove from this set");
509: }
510:
511: public boolean removeAll(Collection c) {
512: throw new UnsupportedOperationException(
513: "It is not allowed to remove from this set");
514: }
515:
516: public boolean retainAll(Collection c) {
517: throw new UnsupportedOperationException(
518: "It is not allowed to remove from this set");
519: }
520:
521: public int size() {
522: return _wrapMap.size();
523: }
524: }
525:
526: private static class WrapResultSetKeysIterator implements Iterator {
527: private Iterator _keyIterator = null;
528:
529: public WrapResultSetKeysIterator(WrapResultSetMap map) {
530: _keyIterator = map.getUnderlyingKeys();
531: }
532:
533: public boolean hasNext() {
534: return _keyIterator.hasNext();
535: }
536:
537: public Object next() {
538: return _keyIterator.next();
539: }
540:
541: public void remove() {
542: throw new UnsupportedOperationException(
543: "it is not allowed to remove from this iterator");
544: }
545:
546: }
547:
548: private static class WrapResultSetValues extends AbstractCollection {
549: private WrapResultSetMap _wrapMap;
550:
551: public WrapResultSetValues(WrapResultSetMap wrapMap) {
552: _wrapMap = wrapMap;
553: }
554:
555: public boolean add(Object o) {
556: throw new UnsupportedOperationException(
557: "it is not allowed to add to this collection");
558: }
559:
560: public boolean addAll(Collection c) {
561: throw new UnsupportedOperationException(
562: "it is not allowed to add to this collection");
563: }
564:
565: public void clear() {
566: throw new UnsupportedOperationException(
567: "it is not allowed to remove from this collection");
568: }
569:
570: public boolean contains(Object value) {
571: return _wrapMap.containsValue(value);
572: }
573:
574: public Iterator iterator() {
575: return new WrapResultSetValuesIterator(_wrapMap);
576: }
577:
578: public boolean remove(Object o) {
579: throw new UnsupportedOperationException();
580: }
581:
582: public boolean removeAll(Collection c) {
583: throw new UnsupportedOperationException(
584: "it is not allowed to remove from this collection");
585: }
586:
587: public boolean retainAll(Collection c) {
588: throw new UnsupportedOperationException(
589: "it is not allowed to remove from this collection");
590: }
591:
592: public int size() {
593: return _wrapMap.size();
594: }
595:
596: }
597:
598: private static class WrapResultSetValuesIterator implements
599: Iterator {
600:
601: private WrapResultSetMap _wrapMap;
602: private Iterator<Object> _keyIterator;
603:
604: public WrapResultSetValuesIterator(WrapResultSetMap wrapMap) {
605: _wrapMap = wrapMap;
606: _keyIterator = _wrapMap.keySet().iterator();
607: }
608:
609: public boolean hasNext() {
610: return _keyIterator.hasNext();
611: }
612:
613: public Object next() {
614: return _wrapMap.get(_keyIterator.next());
615: }
616:
617: public void remove() {
618: throw new UnsupportedOperationException(
619: "it is not allowed to remove from this map");
620: }
621:
622: }
623:
624: }
|