View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package javax.faces.model;
20  
21  import javax.faces.FacesException;
22  import java.sql.ResultSet;
23  import java.sql.SQLException;
24  import java.sql.ResultSetMetaData;
25  import java.util.*;
26  
27  /**
28   * see Javadoc of <a href="http://java.sun.com/javaee/javaserverfaces/1.2/docs/api/index.html">JSF Specification</a>
29   * 
30   * @author Thomas Spiegl (latest modification by $Author: bommel $)
31   * @author Martin Marinschek
32   * @version $Revision: 1187700 $ $Date: 2011-10-22 12:19:37 +0000 (Sat, 22 Oct 2011) $
33   */
34  public class ResultSetDataModel extends DataModel<Map<String,Object>>
35  {
36      // FIELDS
37  
38      private int _currentIndex = -1;
39  
40      /**
41       * The ResultSet being wrapped by this DataModel.
42       */
43      private ResultSet _resultSet = null;
44  
45      /**
46       * The MetaData of the ResultSet being wrapped by this DataModel.
47       */
48      private ResultSetMetaData _resultSetMetadata = null;
49  
50      /**
51       * Indicator for an updated row at the current position.
52       */
53      private boolean _currentRowUpdated = false;
54  
55      // CONSTRUCTORS
56      public ResultSetDataModel()
57      {
58          this(null);
59      }
60  
61      public ResultSetDataModel(ResultSet resultSet)
62      {
63  
64          super();
65          setWrappedData(resultSet);
66  
67      }
68  
69      /**
70       * We don't know how many rows the result set has without scrolling through the whole thing.
71       */
72      @Override
73      public int getRowCount()
74      {
75          return -1;
76      }
77  
78      /**
79       * Get the actual data of this row wrapped into a map. The specification is very strict about what has to be
80       * returned from here, so check the spec before modifying anything here.
81       */
82      @Override
83      public Map<String,Object> getRowData()
84      {
85          if (_resultSet == null)
86          {
87              return null;
88          }
89          else if (!isRowAvailable())
90          {
91              throw new IllegalArgumentException(
92                  "the requested row is not available in the ResultSet - you have scrolled beyond the end.");
93          }
94  
95          try
96          {
97              return new WrapResultSetMap(String.CASE_INSENSITIVE_ORDER);
98          }
99          catch (SQLException e)
100         {
101             throw new FacesException(e);
102         }
103     }
104 
105     @Override
106     public int getRowIndex()
107     {
108         return _currentIndex;
109     }
110 
111     @Override
112     public Object getWrappedData()
113     {
114         return _resultSet;
115     }
116 
117     @Override
118     public boolean isRowAvailable()
119     {
120         if (_resultSet == null)
121         {
122             return false;
123         }
124         else if (_currentIndex < 0)
125         {
126             return false;
127         }
128 
129         try
130         {
131             return _resultSet.absolute(_currentIndex + 1);
132         }
133         catch (SQLException e)
134         {
135             throw new FacesException(e);
136         }
137     }
138 
139     @Override
140     public void setRowIndex(int rowIndex)
141     {
142         if (rowIndex < -1)
143         {
144             throw new IllegalArgumentException("you cannot set the rowIndex to anything less than 0");
145         }
146 
147         // Handle the case of an updated row
148         if (_currentRowUpdated && _resultSet != null)
149         {
150             try
151             {
152                 if (!_resultSet.rowDeleted())
153                     _resultSet.updateRow();
154 
155                 setCurrentRowUpdated(false);
156             }
157             catch (SQLException e)
158             {
159                 throw new FacesException(e);
160             }
161         }
162 
163         int old = _currentIndex;
164         _currentIndex = rowIndex;
165 
166         // if no underlying data has been set, the listeners
167         // need not be notified
168         if (_resultSet == null)
169             return;
170 
171         // Notify all listeners of the upated row
172         DataModelListener[] listeners = getDataModelListeners();
173 
174         if ((old != _currentIndex) && (listeners != null))
175         {
176             Object rowData = null;
177 
178             if (isRowAvailable())
179             {
180                 rowData = getRowData();
181             }
182 
183             DataModelEvent event = new DataModelEvent(this, _currentIndex, rowData);
184 
185             int n = listeners.length;
186 
187             for (int i = 0; i < n; i++)
188             {
189                 if (listeners[i] != null)
190                 {
191                     listeners[i].rowSelected(event);
192                 }
193             }
194         }
195     }
196 
197     @Override
198     public void setWrappedData(Object data)
199     {
200         if (data == null)
201         {
202             _resultSetMetadata = null;
203             _resultSet = null;
204             setRowIndex(-1);
205         }
206         else
207         {
208             _resultSetMetadata = null;
209             _resultSet = (ResultSet) data;
210             _currentIndex = -1;
211             setRowIndex(0);
212         }
213     }
214 
215     private ResultSetMetaData getResultSetMetadata()
216     {
217         if (_resultSetMetadata == null)
218         {
219             try
220             {
221                 _resultSetMetadata = _resultSet.getMetaData();
222             }
223             catch (SQLException e)
224             {
225                 throw new FacesException(e);
226             }
227         }
228 
229         return _resultSetMetadata;
230     }
231 
232     private void setCurrentRowUpdated(boolean currentRowUpdated)
233     {
234         _currentRowUpdated = currentRowUpdated;
235     }
236 
237     /*
238      * A map wrapping the result set and calling the corresponding operations on the result set, first setting the
239      * correct row index.
240      * TODO: Implement Map, use internal TreeMap for keys instead, it's cleaner
241      */
242     private class WrapResultSetMap extends TreeMap<String, Object>
243     {
244         private static final long serialVersionUID = -4321143404567038922L;
245         private int _currentIndex;
246 
247         public WrapResultSetMap(Comparator<String> comparator) throws SQLException
248         {
249             super(comparator);
250 
251             _currentIndex = ResultSetDataModel.this._currentIndex;
252 
253             _resultSet.absolute(_currentIndex + 1);
254 
255             int columnCount = getResultSetMetadata().getColumnCount();
256 
257             for (int i = 1; i <= columnCount; i++)
258             {
259                 super.put(getResultSetMetadata().getColumnName(i), getResultSetMetadata().getColumnName(i));
260             }
261         }
262 
263         @Override
264         public void clear()
265         {
266             throw new UnsupportedOperationException("It is not allowed to remove from this map");
267         }
268 
269         @Override
270         public boolean containsValue(Object value)
271         {
272             //Iterate over entry set is better, because an entry
273             //key could have null value.
274             for (Map.Entry<String, Object> entry : entrySet())
275             {
276                 if (value != null && value.equals(entry.getValue()))
277                 {
278                     return true;
279                 }
280                 else if (value == null && entry.getValue() == null)
281                 {
282                     return true;
283                 }
284             }
285             
286             return false;
287         }
288 
289         @Override
290         public Set<Map.Entry<String, Object>> entrySet()
291         {
292             return new WrapResultSetEntries(this);
293         }
294 
295         @Override
296         public Object get(Object key)
297         {
298             if (!containsKey(key))
299             {
300                 return null;
301             }
302 
303             return basicGet(key);
304         }
305 
306         private Object basicGet(Object key)
307         { // #################################################### remove
308             try
309             {
310                 _resultSet.absolute(_currentIndex + 1);
311 
312                 return _resultSet.getObject((String) getUnderlyingKey(key));
313 
314             }
315             catch (SQLException e)
316             {
317                 throw new FacesException(e);
318             }
319         }
320 
321         @Override
322         public Set<String> keySet()
323         {
324             return new WrapResultSetKeys(this);
325         }
326 
327         @Override
328         public Object put(String key, Object value)
329         {
330             if (!containsKey(key))
331             {
332                 throw new IllegalArgumentException("underlying result set does not provide this key");
333             }
334             
335             try
336             {
337                 _resultSet.absolute(_currentIndex + 1);
338 
339                 Object oldValue = _resultSet.getObject((String) getUnderlyingKey(key));
340 
341                 if (oldValue == null ? value == null : oldValue.equals(value))
342                     return oldValue;
343 
344                 _resultSet.updateObject((String) getUnderlyingKey(key), value);
345 
346                 setCurrentRowUpdated(true);
347 
348                 return oldValue;
349             }
350             catch (SQLException e)
351             {
352                 throw new FacesException(e);
353             }
354         }
355 
356         @Override
357         public void putAll(Map<? extends String, ?> map)
358         {
359             for (Map.Entry<? extends String, ?> entry : map.entrySet())
360             {
361                 put(entry.getKey(), entry.getValue());
362             }
363         }
364 
365         @Override
366         public Object remove(Object key)
367         {
368             throw new UnsupportedOperationException("It is not allowed to remove entries from this set.");
369         }
370 
371         @Override
372         public Collection<Object> values()
373         {
374             return new WrapResultSetValues(this);
375         }
376 
377         Object getUnderlyingKey(Object key)
378         {
379             return super.get(key);
380         }
381 
382         Iterator<String> getUnderlyingKeys()
383         {
384             return super.keySet().iterator();
385         }
386 
387     }
388 
389     private static class WrapResultSetEntries extends AbstractSet<Map.Entry<String, Object>>
390     {
391         private WrapResultSetMap _wrapMap;
392 
393         public WrapResultSetEntries(WrapResultSetMap wrapMap)
394         {
395             _wrapMap = wrapMap;
396         }
397 
398         @Override
399         public boolean add(Map.Entry<String, Object> o)
400         {
401             throw new UnsupportedOperationException("it is not allowed to add to this set");
402         }
403 
404         @Override
405         public boolean addAll(Collection<? extends Map.Entry<String, Object>> c)
406         {
407             throw new UnsupportedOperationException("it is not allowed to add to this set");
408         }
409 
410         @Override
411         public void clear()
412         {
413             throw new UnsupportedOperationException("it is not allowed to remove from this set");
414         }
415 
416         @Override
417         public boolean contains(Object o)
418         {
419             if (o == null)
420                 throw new NullPointerException();
421             if (!(o instanceof Map.Entry))
422                 return false;
423 
424             Map.Entry<?, ?> e = (Map.Entry<?, ?>) o;
425             Object key = e.getKey();
426 
427             if (!_wrapMap.containsKey(key))
428                 return false;
429 
430             Object value = e.getValue();
431             Object cmpValue = _wrapMap.get(key);
432 
433             return value == null ? cmpValue == null : value.equals(cmpValue);
434         }
435 
436         @Override
437         public boolean isEmpty()
438         {
439             return _wrapMap.isEmpty();
440         }
441 
442         @Override
443         public Iterator<Map.Entry<String, Object>> iterator()
444         {
445             return new WrapResultSetEntriesIterator(_wrapMap);
446         }
447 
448         @Override
449         public boolean remove(Object o)
450         {
451             throw new UnsupportedOperationException("it is not allowed to remove from this set");
452         }
453 
454         @Override
455         public boolean removeAll(Collection<?> c)
456         {
457             throw new UnsupportedOperationException("it is not allowed to remove from this set");
458         }
459 
460         @Override
461         public boolean retainAll(Collection<?> c)
462         {
463             throw new UnsupportedOperationException("it is not allowed to remove from this set");
464         }
465 
466         @Override
467         public int size()
468         {
469             return _wrapMap.size();
470         }
471     }
472 
473     private static class WrapResultSetEntriesIterator implements Iterator<Map.Entry<String, Object>>
474     {
475 
476         private WrapResultSetMap _wrapMap = null;
477         private Iterator<String> _keyIterator = null;
478 
479         public WrapResultSetEntriesIterator(WrapResultSetMap wrapMap)
480         {
481             _wrapMap = wrapMap;
482             _keyIterator = _wrapMap.keySet().iterator();
483         }
484 
485         public boolean hasNext()
486         {
487             return _keyIterator.hasNext();
488         }
489 
490         public Map.Entry<String, Object> next()
491         {
492             return new WrapResultSetEntry(_wrapMap, _keyIterator.next());
493         }
494 
495         public void remove()
496         {
497             throw new UnsupportedOperationException("It is not allowed to remove from this iterator");
498         }
499 
500     }
501 
502     private static class WrapResultSetEntry implements Map.Entry<String, Object>
503     {
504 
505         private WrapResultSetMap _wrapMap;
506         private String _entryKey;
507 
508         public WrapResultSetEntry(WrapResultSetMap wrapMap, String entryKey)
509         {
510             _wrapMap = wrapMap;
511             _entryKey = entryKey;
512         }
513 
514         @Override
515         public boolean equals(Object o)
516         {
517             if (o == null)
518                 return false;
519 
520             if (!(o instanceof Map.Entry))
521                 return false;
522 
523             Map.Entry<?, ?> cmpEntry = (Map.Entry<?, ?>) o;
524 
525             if (_entryKey == null ? cmpEntry.getKey() != null : !_entryKey.equals(cmpEntry.getKey()))
526                 return false;
527 
528             Object value = _wrapMap.get(_entryKey);
529             Object cmpValue = cmpEntry.getValue();
530 
531             return value == null ? cmpValue != null : value.equals(cmpValue);
532         }
533 
534         public String getKey()
535         {
536             return _entryKey;
537         }
538 
539         public Object getValue()
540         {
541             return _wrapMap.get(_entryKey);
542         }
543 
544         @Override
545         public int hashCode()
546         {
547             int result;
548             result = (_entryKey != null ? _entryKey.hashCode() : 0);
549             result = 29 * result + (_wrapMap.get(_entryKey) != null ? _wrapMap.get(_entryKey).hashCode() : 0);
550             return result;
551         }
552 
553         public Object setValue(Object value)
554         {
555             Object oldValue = _wrapMap.get(_entryKey);
556             _wrapMap.put(_entryKey, value);
557             return oldValue;
558         }
559     }
560 
561     private static class WrapResultSetKeys extends AbstractSet<String>
562     {
563         private WrapResultSetMap _wrapMap;
564 
565         public WrapResultSetKeys(WrapResultSetMap wrapMap)
566         {
567             _wrapMap = wrapMap;
568         }
569 
570         @Override
571         public boolean add(String o)
572         {
573             throw new UnsupportedOperationException("It is not allowed to add to this set");
574         }
575 
576         @Override
577         public boolean addAll(Collection<? extends String> c)
578         {
579             throw new UnsupportedOperationException("It is not allowed to add to this set");
580         }
581 
582         @Override
583         public void clear()
584         {
585             throw new UnsupportedOperationException("It is not allowed to remove from this set");
586         }
587 
588         @Override
589         public boolean contains(Object obj)
590         {
591             return _wrapMap.containsKey(obj);
592         }
593 
594         @Override
595         public boolean isEmpty()
596         {
597             return _wrapMap.isEmpty();
598         }
599 
600         @Override
601         public Iterator<String> iterator()
602         {
603             return new WrapResultSetKeysIterator(_wrapMap);
604         }
605 
606         @Override
607         public boolean remove(Object o)
608         {
609             throw new UnsupportedOperationException("It is not allowed to remove from this set");
610         }
611 
612         @Override
613         public boolean removeAll(Collection<?> c)
614         {
615             throw new UnsupportedOperationException("It is not allowed to remove from this set");
616         }
617 
618         @Override
619         public boolean retainAll(Collection<?> c)
620         {
621             throw new UnsupportedOperationException("It is not allowed to remove from this set");
622         }
623 
624         @Override
625         public int size()
626         {
627             return _wrapMap.size();
628         }
629     }
630 
631     private static class WrapResultSetKeysIterator implements Iterator<String>
632     {
633         private Iterator<String> _keyIterator = null;
634 
635         public WrapResultSetKeysIterator(WrapResultSetMap map)
636         {
637             _keyIterator = map.getUnderlyingKeys();
638         }
639 
640         public boolean hasNext()
641         {
642             return _keyIterator.hasNext();
643         }
644 
645         public String next()
646         {
647             return _keyIterator.next();
648         }
649 
650         public void remove()
651         {
652             throw new UnsupportedOperationException("it is not allowed to remove from this iterator");
653         }
654 
655     }
656 
657     private static class WrapResultSetValues extends AbstractCollection<Object>
658     {
659         private WrapResultSetMap _wrapMap;
660 
661         public WrapResultSetValues(WrapResultSetMap wrapMap)
662         {
663             _wrapMap = wrapMap;
664         }
665 
666         @Override
667         public boolean add(Object o)
668         {
669             throw new UnsupportedOperationException("it is not allowed to add to this collection");
670         }
671 
672         @Override
673         public boolean addAll(Collection<?> c)
674         {
675             throw new UnsupportedOperationException("it is not allowed to add to this collection");
676         }
677 
678         @Override
679         public void clear()
680         {
681             throw new UnsupportedOperationException("it is not allowed to remove from this collection");
682         }
683 
684         @Override
685         public boolean contains(Object value)
686         {
687             return _wrapMap.containsValue(value);
688         }
689 
690         @Override
691         public Iterator<Object> iterator()
692         {
693             return new WrapResultSetValuesIterator(_wrapMap);
694         }
695 
696         @Override
697         public boolean remove(Object o)
698         {
699             throw new UnsupportedOperationException();
700         }
701 
702         @Override
703         public boolean removeAll(Collection<?> c)
704         {
705             throw new UnsupportedOperationException("it is not allowed to remove from this collection");
706         }
707 
708         @Override
709         public boolean retainAll(Collection<?> c)
710         {
711             throw new UnsupportedOperationException("it is not allowed to remove from this collection");
712         }
713 
714         @Override
715         public int size()
716         {
717             return _wrapMap.size();
718         }
719 
720     }
721 
722     private static class WrapResultSetValuesIterator implements Iterator<Object>
723     {
724 
725         private WrapResultSetMap _wrapMap;
726         private Iterator<String> _keyIterator;
727 
728         public WrapResultSetValuesIterator(WrapResultSetMap wrapMap)
729         {
730             _wrapMap = wrapMap;
731             _keyIterator = _wrapMap.keySet().iterator();
732         }
733 
734         public boolean hasNext()
735         {
736             return _keyIterator.hasNext();
737         }
738 
739         public Object next()
740         {
741             return _wrapMap.get(_keyIterator.next());
742         }
743 
744         public void remove()
745         {
746             throw new UnsupportedOperationException("it is not allowed to remove from this map");
747         }
748 
749     }
750 
751 }