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