001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041: package com.sun.rave.web.ui.faces;
042:
043: import com.sun.data.provider.FieldKey;
044: import com.sun.data.provider.RowKey;
045: import com.sun.data.provider.TableDataProvider;
046: import java.util.AbstractCollection;
047: import java.util.AbstractMap;
048: import java.util.AbstractSet;
049: import java.util.Collection;
050: import java.util.Iterator;
051: import java.util.Map;
052: import java.util.Set;
053: import javax.faces.FacesException;
054: import javax.faces.model.DataModel;
055: import javax.faces.model.DataModelEvent;
056: import javax.faces.model.DataModelListener;
057:
058: /**
059: * <p><code>DataModel</code> implementation that wraps a specified
060: * {@link TableDataProvider} with the standard JavaServer Faces API.
061: * Note that setting the <code>rowIndex</code> property of this
062: * <code>DataModel</code> does <strong>NOT</strong> cause the cursor of
063: * the wrapped {@link TableDataProvider} to be repositioned.</p>
064: */
065: public class TableDataProviderDataModel extends DataModel {
066:
067: // ------------------------------------------------------------ Constructors
068:
069: /**
070: * <p>Construct an unitialized {@link TableDataProviderDataModel}.</p>
071: */
072: public TableDataProviderDataModel() {
073: this (null);
074: }
075:
076: /**
077: * <p>Construct an {@link TableDataProviderDataModel} that wraps the
078: * specified {@link TableDataProvider}.</p>
079: */
080: public TableDataProviderDataModel(TableDataProvider tdp) {
081: setTableDataProvider(tdp);
082: }
083:
084: // ------------------------------------------------------ Instance Variables
085:
086: /**
087: * <p>The set of {@link FieldKey}s for the currently wrapped
088: * {@link TableDataProvider}.</p>
089: */
090: private FieldKey fieldKeys[] = null;
091:
092: /**
093: * <p>The row index to which this <code>DataModel</code>
094: * is positioned.</p>
095: */
096: private int rowIndex = -1;
097:
098: // -------------------------------------------------------------- Properties
099:
100: /**
101: * <p>The {@link TableDataProvider} that we are wrapping.</p>
102: */
103: private TableDataProvider tdp = null;
104:
105: /**
106: * <p>Return the {@link TableDataProvider} we are wrapping.</p>
107: */
108: public TableDataProvider getTableDataProvider() {
109: return this .tdp;
110: }
111:
112: /**
113: * <p>Set the {@link TableDataProvider} we are wrapping.</p>
114: *
115: * @param tdp The {@link TableDataProvider} to be wraapped
116: */
117: public void setTableDataProvider(TableDataProvider tdp) {
118: this .tdp = tdp;
119: if (tdp == null) {
120: this .fieldKeys = null;
121: this .rowIndex = -1;
122: } else {
123: this .fieldKeys = tdp.getFieldKeys();
124: }
125: }
126:
127: // ---------------------------------------------------- DataModel Properties
128:
129: /**
130: * <p>Return <code>true</code> if the wrapped {@link TableDataProvider}
131: * has an available row at the currently specified <code>rowIndex</code>.</p>
132: */
133: public boolean isRowAvailable() {
134: if (getTableDataProvider() == null) {
135: return false;
136: }
137: return getTableDataProvider().isRowAvailable(getRowKey());
138: }
139:
140: /**
141: * <p>Return the number of rows available in the wrapped
142: * {@link TableDataProvider}, or <code>-1</code> if unknown.</p>
143: */
144: public int getRowCount() {
145: if (getTableDataProvider() == null) {
146: return -1;
147: }
148: return getTableDataProvider().getRowCount();
149: }
150:
151: /**
152: * <p>Return a <code>Map</code> representing the data elements in the
153: * current row, keyed by the canonical identifier for each element.
154: * Any call to <code>get()</code> or <code>put()</code> operations on
155: * this <code>Map</code> will be delegated to corresponding
156: * <code>getValue()</code> and <code>setValue()</code> calls on the
157: * wrapped {@link TableDataProvider}. Operations that attempt to add,
158: * delete, or replace keys will be rejected.</p>
159: */
160: public Object getRowData() {
161: if (getTableDataProvider() == null) {
162: return null;
163: }
164: if (!getTableDataProvider().isRowAvailable(getRowKey())) {
165: throw new IllegalArgumentException("" + getRowIndex());
166: }
167: Map map = new TableDataProviderMap();
168: for (int i = 0; i < fieldKeys.length; i++) {
169: map.put(fieldKeys[i].getFieldId(), tdp.getValue(
170: fieldKeys[i], getRowKey()));
171: }
172: return map;
173: }
174:
175: /**
176: * <p>Return the currently selected <code>rowIndex</code>, or -1 for
177: * no current position.</p>
178: */
179: public int getRowIndex() {
180: return this .rowIndex;
181: }
182:
183: public RowKey getRowKey() {
184: int i = getRowIndex();
185: RowKey[] rks = tdp.getRowKeys(i + 1, null);
186: if (rks.length > i) {
187: return rks[i];
188: }
189: return null;
190: }
191:
192: /**
193: * <p>Set the currently selected <code>rowIndex</code>. The cursor
194: * position of the wrapped {@link TableDataProvider} is <strong>NOT</strong>
195: * updated.</p>
196: *
197: * @param rowIndex The new selected row index, or -1 for no selection
198: */
199: public void setRowIndex(int rowIndex) {
200: if (rowIndex < -1) {
201: throw new IllegalArgumentException("" + rowIndex);
202: }
203: int oldIndex = this .rowIndex;
204: this .rowIndex = rowIndex;
205: if (getTableDataProvider() == null) {
206: return;
207: }
208: DataModelListener listeners[] = getDataModelListeners();
209: if ((oldIndex != rowIndex) && (listeners != null)) {
210: Object rowData = null;
211: if (isRowAvailable()) {
212: rowData = getRowData();
213: }
214: DataModelEvent event = new DataModelEvent(this , rowIndex,
215: rowData);
216: for (int i = 0; i < listeners.length; i++) {
217: listeners[i].rowSelected(event);
218: }
219: }
220: }
221:
222: /**
223: * <p>Return the wrapped {@link TableDataProvider} instance, if any.</p>
224: */
225: public Object getWrappedData() {
226: return getTableDataProvider();
227: }
228:
229: /**
230: * <p>Set the wrapped {@link TableDataProvider} instance (if any).</p>
231: *
232: * @param data New {@link TableDataProvider} instance, or <code>null</code>
233: * to disassociate from any instance
234: */
235: public void setWrappedData(Object data) {
236: setTableDataProvider((TableDataProvider) data);
237: }
238:
239: // --------------------------------------------------------- Private Classes
240:
241: /**
242: * <p>Private implementation of <code>Map</code> that delegates
243: * <code>get()</code> and <code>put()</code> operations to
244: * <code>getValue()</code> and <code>setValue()</code> calls on the
245: * underlying {@link TableDataProvider}.</p>
246: */
247: private class TableDataProviderMap extends AbstractMap {
248:
249: public TableDataProviderMap() {
250: this .rowIndex = TableDataProviderDataModel.this
251: .getRowIndex();
252: this .rowKey = TableDataProviderDataModel.this .getRowKey();
253: }
254:
255: private int rowIndex;
256: private RowKey rowKey;
257: private FieldKey fieldKeys[] = TableDataProviderDataModel.this .fieldKeys;
258: private TableDataProvider tdp = TableDataProviderDataModel.this .tdp;
259:
260: public void clear() {
261: throw new UnsupportedOperationException();
262: }
263:
264: public boolean containsValue(Object value) {
265: Iterator keys = keySet().iterator();
266: while (keys.hasNext()) {
267: Object key = keys.next();
268: Object contained = get(key);
269: if (value == null) {
270: if (contained == null) {
271: return true;
272: }
273: } else {
274: if (value.equals(contained)) {
275: return true;
276: }
277: }
278: }
279: return false;
280: }
281:
282: public Set entrySet() {
283: return new TableDataProviderEntries(this );
284: }
285:
286: public Object get(Object key) {
287: int columnIndex = index(key);
288: if (columnIndex < 0) {
289: return null;
290: }
291: return tdp.getValue(fieldKeys[columnIndex], rowKey);
292: }
293:
294: public Set keySet() {
295: return new TableDataProviderKeys(this );
296: }
297:
298: public Object put(Object key, Object value) {
299: int columnIndex = index(key);
300: if (columnIndex < 0) {
301: return null;
302: }
303: Object previous = tdp.getValue(fieldKeys[columnIndex],
304: rowKey);
305: tdp.setValue(fieldKeys[columnIndex], rowKey, value);
306: return previous;
307: }
308:
309: public void putAll(Map map) {
310: Iterator keys = map.keySet().iterator();
311: while (keys.hasNext()) {
312: Object key = keys.next();
313: put(key, map.get(key));
314: }
315: }
316:
317: public Object remove(Object key) {
318: throw new UnsupportedOperationException();
319: }
320:
321: public Collection values() {
322: return new TableDataProviderValues(this );
323: }
324:
325: private int index(Object key) {
326: int index = -1;
327: for (int i = 0; i < fieldKeys.length; i++) {
328: if (key.equals(fieldKeys[i].getFieldId())) {
329: index = i;
330: break;
331: }
332: }
333: return index;
334: }
335:
336: Object realKey(Object key) {
337: return super .get(key);
338: }
339:
340: Iterator realKeys() {
341: return super .keySet().iterator();
342: }
343:
344: }
345:
346: /**
347: * <p>Private implementation of <code>Set</code> for implementing the
348: * <code>entrySet()</code> behavior of <code>TableDataProviderMap</code>.</p>
349: */
350: private class TableDataProviderEntries extends AbstractSet {
351:
352: public TableDataProviderEntries(TableDataProviderMap map) {
353: this .map = map;
354: }
355:
356: private TableDataProviderMap map = null;
357:
358: public boolean add(Object o) {
359: throw new UnsupportedOperationException();
360: }
361:
362: public boolean addAll(Collection c) {
363: throw new UnsupportedOperationException();
364: }
365:
366: public void clear() {
367: throw new UnsupportedOperationException();
368: }
369:
370: public boolean contains(Object o) {
371: if (o == null) {
372: throw new NullPointerException();
373: }
374: if (!(o instanceof Map.Entry)) {
375: return false;
376: }
377: Map.Entry e = (Map.Entry) o;
378: Object k = e.getKey();
379: Object v = e.getValue();
380: if (!map.containsKey(k)) {
381: return false;
382: }
383: if (v == null) {
384: return map.get(k) == null;
385: } else {
386: return v.equals(map.get(k));
387: }
388: }
389:
390: public boolean isEmpty() {
391: return map.isEmpty();
392: }
393:
394: public Iterator iterator() {
395: return new TableDataProviderIterator(map);
396: }
397:
398: public boolean remove(Object o) {
399: throw new UnsupportedOperationException();
400: }
401:
402: public boolean removeAll(Collection c) {
403: throw new UnsupportedOperationException();
404: }
405:
406: public boolean retainAll(Collection c) {
407: throw new UnsupportedOperationException();
408: }
409:
410: public int size() {
411: return map.size();
412: }
413:
414: }
415:
416: /**
417: * <p>Private implementation of <code>Iterator</code> for the
418: * <code>Set</code> returned by <code>entrySet()</code>.</p>
419: */
420: private class TableDataProviderIterator implements Iterator {
421:
422: public TableDataProviderIterator(TableDataProviderMap map) {
423: this .map = map;
424: this .keys = map.keySet().iterator();
425: }
426:
427: private TableDataProviderMap map = null;
428: private Iterator keys = null;
429:
430: public boolean hasNext() {
431: return keys.hasNext();
432: }
433:
434: public Object next() {
435: Object key = keys.next();
436: return (new TableDataProviderEntry(map, key));
437: }
438:
439: public void remove() {
440: throw new UnsupportedOperationException();
441: }
442:
443: }
444:
445: /**
446: * <p>Private implementation of <code>Map.Entry</code> that implements
447: * the behavior for a single entry from the <code>Set</code> that is
448: * returned by <code>entrySet()</code>.</p>
449: */
450: private class TableDataProviderEntry implements Map.Entry {
451:
452: public TableDataProviderEntry(TableDataProviderMap map,
453: Object key) {
454: this .map = map;
455: this .key = key;
456: }
457:
458: private TableDataProviderMap map = null;
459: private Object key = null;
460:
461: public boolean equals(Object o) {
462: if (o == null) {
463: return false;
464: }
465: if (!(o instanceof Map.Entry)) {
466: return false;
467: }
468: Map.Entry e = (Map.Entry) o;
469: if (key == null) {
470: if (e.getKey() != null) {
471: return false;
472: }
473: } else {
474: if (!key.equals(e.getKey())) {
475: return false;
476: }
477: }
478: Object v = map.get(key);
479: if (v == null) {
480: if (e.getValue() != null) {
481: return false;
482: }
483: } else {
484: if (!v.equals(e.getValue())) {
485: return false;
486: }
487: }
488: return true;
489: }
490:
491: public Object getKey() {
492: return this .key;
493: }
494:
495: public Object getValue() {
496: return map.get(key);
497: }
498:
499: public int hashCode() {
500: Object value = map.get(key);
501: return ((key == null) ? 0 : key.hashCode())
502: ^ ((value == null) ? 0 : value.hashCode());
503: }
504:
505: public Object setValue(Object value) {
506: Object previous = map.get(key);
507: map.put(key, value);
508: return previous;
509: }
510:
511: }
512:
513: /**
514: * <p>Private implementation of <code>Set</code> that implements the
515: * <code>keySet()</code> behavior.</p>
516: */
517: private class TableDataProviderKeys extends AbstractSet {
518:
519: public TableDataProviderKeys(TableDataProviderMap map) {
520: this .map = map;
521: }
522:
523: private TableDataProviderMap map = null;
524:
525: public boolean add(Object o) {
526: throw new UnsupportedOperationException();
527: }
528:
529: public boolean addAll(Collection c) {
530: throw new UnsupportedOperationException();
531: }
532:
533: public void clear() {
534: throw new UnsupportedOperationException();
535: }
536:
537: public boolean contains(Object o) {
538: return map.containsKey(o);
539: }
540:
541: public boolean isEmpty() {
542: return map.isEmpty();
543: }
544:
545: public Iterator iterator() {
546: return new TableDataProviderKeysIterator(map);
547: }
548:
549: public boolean remove(Object o) {
550: throw new UnsupportedOperationException();
551: }
552:
553: public boolean removeAll(Collection c) {
554: throw new UnsupportedOperationException();
555: }
556:
557: public boolean retainAll(Collection c) {
558: throw new UnsupportedOperationException();
559: }
560:
561: public int size() {
562: return map.size();
563: }
564:
565: }
566:
567: /**
568: * <p>Private implementation of <code>Iterator</code> that implements the
569: * <code>iterator()</code> method returned by <code>keySet()</code>.</p>
570: */
571: private class TableDataProviderKeysIterator implements Iterator {
572:
573: public TableDataProviderKeysIterator(TableDataProviderMap map) {
574: this .map = map;
575: this .keys = map.realKeys();
576: }
577:
578: private TableDataProviderMap map = null;
579: private Iterator keys = null;
580:
581: public boolean hasNext() {
582: return keys.hasNext();
583: }
584:
585: public Object next() {
586: return keys.next();
587: }
588:
589: public void remove() {
590: throw new UnsupportedOperationException();
591: }
592:
593: }
594:
595: /**
596: * <p>Private implementation of <code>Collection</code> that implements
597: * the <code>values()</code> method.</p>
598: */
599: private class TableDataProviderValues extends AbstractCollection {
600:
601: public TableDataProviderValues(TableDataProviderMap map) {
602: this .map = map;
603: }
604:
605: private TableDataProviderMap map = null;
606:
607: public boolean add(Object o) {
608: throw new UnsupportedOperationException();
609: }
610:
611: public boolean addAll(Collection c) {
612: throw new UnsupportedOperationException();
613: }
614:
615: public void clear() {
616: throw new UnsupportedOperationException();
617: }
618:
619: public boolean contains(Object value) {
620: return map.containsValue(value);
621: }
622:
623: public Iterator iterator() {
624: return new TableDataProviderValuesIterator(map);
625: }
626:
627: public boolean remove(Object o) {
628: throw new UnsupportedOperationException();
629: }
630:
631: public boolean removeAll(Collection c) {
632: throw new UnsupportedOperationException();
633: }
634:
635: public boolean retainAll(Collection c) {
636: throw new UnsupportedOperationException();
637: }
638:
639: public int size() {
640: return map.size();
641: }
642:
643: }
644:
645: /**
646: * <p>Private implementation of <code>Iterator</code> that implements the
647: * <code>behavior for the <code>Iterator</code> returned by
648: * <code>values().iterator()</code>.</p>
649: */
650: private class TableDataProviderValuesIterator implements Iterator {
651:
652: public TableDataProviderValuesIterator(TableDataProviderMap map) {
653: this .map = map;
654: this .keys = map.keySet().iterator();
655: }
656:
657: private TableDataProviderMap map = null;
658: private Iterator keys = null;
659:
660: public boolean hasNext() {
661: return keys.hasNext();
662: }
663:
664: public Object next() {
665: return map.get(keys.next());
666: }
667:
668: public void remove() {
669: throw new UnsupportedOperationException();
670: }
671:
672: }
673:
674: }
|