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