0001: /*
0002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
0003: *
0004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
0005: *
0006: * The contents of this file are subject to the terms of either the GNU
0007: * General Public License Version 2 only ("GPL") or the Common
0008: * Development and Distribution License("CDDL") (collectively, the
0009: * "License"). You may not use this file except in compliance with the
0010: * License. You can obtain a copy of the License at
0011: * http://www.netbeans.org/cddl-gplv2.html
0012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
0013: * specific language governing permissions and limitations under the
0014: * License. When distributing the software, include this License Header
0015: * Notice in each file and include the License file at
0016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
0017: * particular file as subject to the "Classpath" exception as provided
0018: * by Sun in the GPL Version 2 section of the License file that
0019: * accompanied this code. If applicable, add the following below the
0020: * License Header, with the fields enclosed by brackets [] replaced by
0021: * your own identifying information:
0022: * "Portions Copyrighted [year] [name of copyright owner]"
0023: *
0024: * Contributor(s):
0025: *
0026: * The Original Software is NetBeans. The Initial Developer of the Original
0027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
0028: * Microsystems, Inc. All Rights Reserved.
0029: *
0030: * If you wish your version of this file to be governed by only the CDDL
0031: * or only the GPL Version 2, indicate your decision by adding
0032: * "[Contributor] elects to include this software in this distribution
0033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
0034: * single choice of license, a recipient has the option to distribute
0035: * your version of this file under either the CDDL, the GPL Version 2 or
0036: * to extend the choice of license to its licensees as provided above.
0037: * However, if you add GPL Version 2 code and therefore, elected the GPL
0038: * Version 2 license, then the option applies only if the new code is
0039: * made subject to such option by the copyright holder.
0040: */
0041:
0042: /*
0043: * $Id$
0044: */
0045:
0046: package com.sun.rave.faces.data;
0047:
0048: import java.beans.Beans;
0049: import java.sql.ResultSet;
0050: import javax.sql.rowset.CachedRowSet;
0051: import java.sql.ResultSetMetaData;
0052: import java.sql.SQLException;
0053: import java.sql.Types;
0054: import java.util.AbstractCollection;
0055: import java.util.AbstractSet;
0056: import java.util.Collection;
0057: import java.util.Comparator;
0058: import java.util.Iterator;
0059: import java.util.Map;
0060: import java.util.Set;
0061: import java.util.TreeMap;
0062: import javax.faces.FacesException;
0063: import javax.faces.el.PropertyNotFoundException;
0064: import com.sun.rave.faces.util.ComponentBundle;
0065:
0066: import javax.faces.model.DataModel;
0067: import javax.faces.model.DataModelEvent;
0068: import javax.faces.model.DataModelListener;
0069:
0070: /**
0071: * <p><strong>CachedRowSetDataModel</strong> is a convenience implementation of
0072: * {@link DataModel} that wraps a <code>CachedRowSet</code> of Java objects.
0073: * Note that the specified <code>CachedRowSet</code> <strong>MUST</strong>
0074: * be scrollable. In addition, if input components (that will be updating
0075: * model values) reference this object in value binding expressions, the
0076: * specified <code>CachedRowSet</code> <strong>MUST</strong> be updatable.</p>
0077: */
0078:
0079: public class CachedRowSetDataModel extends DataModel {
0080:
0081: // ------------------------------------------------------------ Constructors
0082:
0083: /**
0084: * <p>Construct a new {@link CachedRowSetDataModel} with no specified
0085: * wrapped data.</p>
0086: */
0087: public CachedRowSetDataModel() {
0088:
0089: this (null);
0090:
0091: }
0092:
0093: /**
0094: * <p>Construct a new {@link CachedRowSetDataModel} wrapping the specified
0095: * <code>CachedRowSet</code>.</p>
0096: *
0097: * @param cachedRowSet <code>CachedRowSet</code> to be wrapped (if any)
0098: */
0099: public CachedRowSetDataModel(CachedRowSet cachedRowSet) {
0100:
0101: super ();
0102: setWrappedData(cachedRowSet);
0103:
0104: }
0105:
0106: // ------------------------------------------------------ Instance Variables
0107:
0108: /**
0109: * <p>Localization resources for this package.</p>
0110: */
0111: private static final ComponentBundle bundle = ComponentBundle
0112: .getBundle(CachedRowSetDataModel.class);
0113:
0114: /**
0115: * <p>The number of fake data rows we will compose at
0116: * design time.</p>
0117: */
0118: private static final int DESIGN_TIME_ROWS = 5;
0119:
0120: // The row index for the row whose column values may be read or written
0121: //private int current = -1;
0122:
0123: // The current row index (zero relative)
0124: private int index = -1;
0125:
0126: // The metadata for the CachedRowSet we are wrapping (lazily instantiated)
0127: private ResultSetMetaData metadata = null;
0128:
0129: // The CachedRowSet we are wrapping
0130: private CachedRowSet cachedRowSet = null;
0131:
0132: // Has the row at the current index been updated?
0133: private boolean updated = false;
0134:
0135: // -------------------------------------------------------------- Properties
0136:
0137: /**
0138: * <p>Return <code>true</code> if there is <code>wrappedData</code>
0139: * available, and the result of calling <code>absolute()</code> on the
0140: * underlying <code>CachedRowSet</code>, passing the current value of
0141: * <code>rowIndex</code> plus one (to account for the fact that
0142: * <code>CachedRowSet</code> uses one-relative indexing), returns
0143: * <code>true</code>. Otherwise, return <code>false</code>.</p>
0144: *
0145: * @exception FacesException if an error occurs getting the row availability
0146: */
0147: public boolean isRowAvailable() {
0148:
0149: if (Beans.isDesignTime()) {
0150: return (index >= 0) && (index < DESIGN_TIME_ROWS);
0151: }
0152:
0153: executeIfNecessary();
0154:
0155: if (cachedRowSet == null) {
0156: return (false);
0157: } else if (index < 0) {
0158: return (false);
0159: }
0160: try {
0161: if (cachedRowSet.absolute(index + 1)) {
0162: return (true);
0163: } else {
0164: return (false);
0165: }
0166: } catch (SQLException e) {
0167: throw new FacesException(e);
0168: }
0169:
0170: }
0171:
0172: /**
0173: * <p>Return -1, since <code>CachedRowSet</code> does not provide a
0174: * standard way to determine the number of available rows without
0175: * scrolling through the entire <code>CachedRowSet</code>, and this can
0176: * be very expensive if the number of rows is large.</p>
0177: *
0178: * @exception FacesException if an error occurs getting the row count
0179: */
0180: public int getRowCount() {
0181:
0182: if (Beans.isDesignTime()) {
0183: return DESIGN_TIME_ROWS;
0184: }
0185:
0186: return (-1);
0187:
0188: }
0189:
0190: /**
0191: * <p>If row data is available, return a <code>Map</code> representing
0192: * the values of the columns for the row specified by <code>rowIndex</code>,
0193: * keyed by the corresponding column names. If no wrapped data is
0194: * available, return <code>null</code>.</p>
0195: *
0196: * <p>If a non-<code>null</code> <code>Map</code> is returned, its behavior
0197: * must correspond to the contract for a mutable <code>Map</code> as
0198: * described in the JavaDocs for <code>AbstractMap</code>, with the
0199: * following exceptions and specialized behavior:</p>
0200: * <ul>
0201:
0202: * <li>The <code>Map</code>, and any supporting objects it returns,
0203: * must perform all column name comparisons in a
0204: * case-insensitive manner. This case-insensitivity must be
0205: * implemented using a case-insensitive <code>Comparator</code>,
0206: * such as
0207: * <code>String.CASE_INSENSITIVE_ORDER</code>.</li>
0208:
0209: * <li>The following methods must throw
0210: * <code>UnsupportedOperationException</code>: <code>clear()</code>,
0211: * <code>remove()</code>.</li>
0212: * <li>The <code>entrySet()</code> method must return a <code>Set</code>
0213: * that has the following behavior:
0214: * <ul>
0215: * <li>Throw <code>UnsupportedOperationException</code> for any attempt
0216: * to add or remove entries from the <code>Set</code>, either
0217: * directly or indirectly through an <code>Iterator</code>
0218: * returned by the <code>Set</code>.</li>
0219: * <li>Updates to the <code>value</code> of an entry in this
0220: * <code>set</code> must write through to the corresponding
0221: * column value in the underlying <code>CachedRowSet</code>.</li>
0222: * </ul></li>
0223: * <li>The <code>keySet()</code> method must return a <code>Set</code>
0224: * that throws <code>UnsupportedOperationException</code> on any
0225: * attempt to add or remove keys, either directly or through an
0226: * <code>Iterator</code> returned by the <code>Set</code>.</li>
0227: * <li>The <code>put()</code> method must throw
0228: * <code>IllegalArgumentException</code> if a key value for which
0229: * <code>containsKey()</code> returns <code>false</code> is
0230: * specified. However, if a key already present in the <code>Map</code>
0231: * is specified, the specified value must write through to the
0232: * corresponding column value in the underlying <code>CachedRowSet</code>.
0233: * </li>
0234: * <li>The <code>values()</code> method must return a
0235: * <code>Collection</code> that throws
0236: * <code>UnsupportedOperationException</code> on any attempt to add
0237: * or remove values, either directly or through an <code>Iterator</code>
0238: * returned by the <code>Collection</code>.</li>
0239: * </ul>
0240: *
0241: * @exception FacesException if an error occurs getting the row data
0242: * @exception IllegalArgumentException if now row data is available
0243: * at the currently specified row index
0244: */
0245: public Object getRowData() {
0246:
0247: if (cachedRowSet == null) {
0248: return (null);
0249: } else if (!isRowAvailable()) {
0250: throw new IllegalArgumentException();
0251: }
0252: try {
0253: getMetaData();
0254: return (new CachedRowSetMap(String.CASE_INSENSITIVE_ORDER));
0255: } catch (SQLException e) {
0256: throw new FacesException(e);
0257: }
0258:
0259: }
0260:
0261: /**
0262: * @exception FacesException
0263: */
0264: public int getRowIndex() {
0265:
0266: return (index);
0267:
0268: }
0269:
0270: /**
0271: * @exception FacesException
0272: * @exception IllegalArgumentException
0273: */
0274: public void setRowIndex(int rowIndex) {
0275:
0276: if (rowIndex < -1) {
0277: throw new IllegalArgumentException();
0278: }
0279:
0280: // Tell the CachedRowSet that the previous row was updated if necessary
0281: if (!Beans.isDesignTime()) {
0282: if (updated && (cachedRowSet != null)) {
0283: try {
0284: if (!cachedRowSet.rowDeleted()) {
0285: cachedRowSet.updateRow();
0286: }
0287: updated = false;
0288: } catch (SQLException e) {
0289: throw new FacesException(e);
0290: }
0291: }
0292: }
0293:
0294: int old = index;
0295: index = rowIndex;
0296: if (cachedRowSet == null) {
0297: return;
0298: }
0299: DataModelListener[] listeners = getDataModelListeners();
0300: if ((old != index) && (listeners != null)) {
0301: Object rowData = null;
0302: if (isRowAvailable()) {
0303: rowData = getRowData();
0304: }
0305: DataModelEvent event = new DataModelEvent(this , index,
0306: rowData);
0307: int n = listeners.length;
0308: for (int i = 0; i < n; i++) {
0309: if (null != listeners[i]) {
0310: listeners[i].rowSelected(event);
0311: }
0312: }
0313: }
0314:
0315: }
0316:
0317: public Object getWrappedData() {
0318:
0319: return (this .cachedRowSet);
0320:
0321: }
0322:
0323: /**
0324: * @exception ClassCastException
0325: */
0326: public void setWrappedData(Object data) {
0327:
0328: if (data == null) {
0329: metadata = null;
0330: cachedRowSet = null;
0331: setRowIndex(-1);
0332: } else {
0333: metadata = null;
0334: cachedRowSet = (CachedRowSet) data;
0335: index = -1;
0336: setRowIndex(0);
0337: }
0338: }
0339:
0340: /**
0341: * <p>Return the <code>CachedRowSet</code> we are connected with,
0342: * if any; otherwise, return <code>null</code>. This is a
0343: * type=safe alias for <code>getWrappedData()</code>.</p>
0344: */
0345: public CachedRowSet getCachedRowSet() {
0346:
0347: return ((CachedRowSet) getWrappedData());
0348:
0349: }
0350:
0351: /**
0352: * <p>Set the <code>CachedRowSet</code> we are connected with,
0353: * or pass <code>null</code> to disconnect. This is a
0354: * type-safe alias for <code>setWrappedData()</code>.</p>
0355: *
0356: * @param rowSet The <code>CachedRowSet</code> we are connected to,
0357: * or <code>null</code> to disconnect
0358: */
0359: public void setCachedRowSet(CachedRowSet rowSet) {
0360:
0361: setWrappedData(rowSet);
0362:
0363: }
0364:
0365: // --------------------------------------------------------- Private Methods
0366:
0367: /**
0368: * <p>If not designtime, execute the rowset if necessary.
0369: */
0370: private void executeIfNecessary() {
0371:
0372: if (Beans.isDesignTime()) {
0373: return;
0374: }
0375:
0376: if (getCachedRowSet() == null) {
0377: throw new FacesException(bundle
0378: .getMessage("cachedRowSetIsNull")); // NOI18N
0379: }
0380:
0381: try {
0382: getCachedRowSet().isBeforeFirst();
0383: } catch (SQLException e) {
0384: try {
0385: getCachedRowSet().execute();
0386: } catch (SQLException e2) {
0387: throw new FacesException(e2);
0388: }
0389: }
0390: }
0391:
0392: /**
0393: * <p>Return the <code>ResultSetMetaData</code> for the
0394: * <code>CachedRowSet</code> we are wrapping, caching it the first time
0395: * it is returned.</p>
0396: *
0397: * @exception FacesException if the <code>ResultSetMetaData</code>
0398: * cannot be acquired
0399: */
0400: private ResultSetMetaData getMetaData() {
0401:
0402: if (metadata == null) {
0403: try {
0404: metadata = cachedRowSet.getMetaData();
0405: } catch (SQLException e) {
0406: throw new FacesException(e);
0407: }
0408: }
0409: return (metadata);
0410:
0411: }
0412:
0413: /**
0414: * <p>Mark the current row as having been updated, so that we will call
0415: * <code>updateRow()</code> before moving elsewhere.</p>
0416: */
0417: private void updated() {
0418:
0419: this .updated = true;
0420:
0421: }
0422:
0423: // --------------------------------------------------------- Private Classes
0424:
0425: // Private implementation of Map that delegates column get and put
0426: // operations to the underlying CachedRowSet, after setting the required
0427: // row index
0428: private class CachedRowSetMap extends TreeMap {
0429:
0430: public CachedRowSetMap(Comparator comparator)
0431: throws SQLException {
0432: super (comparator);
0433: index = CachedRowSetDataModel.this .index;
0434: if (!Beans.isDesignTime()) {
0435: cachedRowSet.absolute(index + 1);
0436: }
0437: int n = metadata.getColumnCount();
0438: for (int i = 1; i <= n; i++) {
0439: super .put(metadata.getColumnName(i), metadata
0440: .getColumnName(i));
0441: }
0442: }
0443:
0444: // The zero-relative row index of our row
0445: private int index;
0446:
0447: // Removing entries is not allowed
0448: public void clear() {
0449: throw new UnsupportedOperationException();
0450: }
0451:
0452: public boolean containsValue(Object value) {
0453: Iterator keys = keySet().iterator();
0454: while (keys.hasNext()) {
0455: Object key = keys.next();
0456: Object contained = get(key);
0457: if (value == null) {
0458: if (contained == null) {
0459: return (true);
0460: }
0461: } else {
0462: if (value.equals(contained)) {
0463: return (true);
0464: }
0465: }
0466: }
0467: return (false);
0468: }
0469:
0470: public Set entrySet() {
0471: return (new CachedRowSetEntries(this ));
0472: }
0473:
0474: public Object get(Object key) {
0475: if (!containsKey(key)) {
0476: return (null);
0477: }
0478: try {
0479: if (Beans.isDesignTime()) {
0480: return getFakeData(metadata, (String) realKey(key));
0481: } else {
0482: cachedRowSet.absolute(index + 1);
0483: return (cachedRowSet
0484: .getObject((String) realKey(key)));
0485: }
0486: } catch (SQLException e) {
0487: throw new FacesException(e);
0488: }
0489: }
0490:
0491: public Set keySet() {
0492: return (new CachedRowSetKeys(this ));
0493: }
0494:
0495: public Object put(Object key, Object value) {
0496: if (Beans.isDesignTime()) {
0497: return get(key);
0498: }
0499: if (!containsKey(key)) {
0500: throw new IllegalArgumentException();
0501: }
0502: if (!(key instanceof String)) {
0503: throw new IllegalArgumentException();
0504: }
0505: try {
0506: cachedRowSet.absolute(index + 1);
0507: Object previous = cachedRowSet
0508: .getObject((String) realKey(key));
0509: if ((previous == null) && (value == null)) {
0510: return (previous);
0511: } else if ((previous != null) && (value != null)
0512: && previous.equals(value)) {
0513: return (previous);
0514: }
0515: cachedRowSet.updateObject((String) realKey(key), value);
0516: CachedRowSetDataModel.this .updated();
0517: return (previous);
0518: } catch (SQLException e) {
0519: throw new FacesException(e);
0520: }
0521: }
0522:
0523: public void putAll(Map map) {
0524: if (Beans.isDesignTime()) {
0525: return;
0526: }
0527: Iterator keys = map.keySet().iterator();
0528: while (keys.hasNext()) {
0529: Object key = keys.next();
0530: put(key, map.get(key));
0531: }
0532: }
0533:
0534: // Removing entries is not allowed
0535: public Object remove(Object key) {
0536: throw new UnsupportedOperationException();
0537: }
0538:
0539: public Collection values() {
0540: return (new CachedRowSetValues(this ));
0541: }
0542:
0543: Object realKey(Object key) {
0544: return (super .get(key));
0545: }
0546:
0547: Iterator realKeys() {
0548: return (super .keySet().iterator());
0549: }
0550:
0551: }
0552:
0553: // Private implementation of Set that implements the entrySet() behavior
0554: // for CachedRowSetMap
0555: private class CachedRowSetEntries extends AbstractSet {
0556:
0557: public CachedRowSetEntries(CachedRowSetMap map) {
0558: this .map = map;
0559: }
0560:
0561: private CachedRowSetMap map;
0562:
0563: // Adding entries is not allowed
0564: public boolean add(Object o) {
0565: throw new UnsupportedOperationException();
0566: }
0567:
0568: // Adding entries is not allowed
0569: public boolean addAll(Collection c) {
0570: throw new UnsupportedOperationException();
0571: }
0572:
0573: // Removing entries is not allowed
0574: public void clear() {
0575: throw new UnsupportedOperationException();
0576: }
0577:
0578: public boolean contains(Object o) {
0579: if (o == null) {
0580: throw new NullPointerException();
0581: }
0582: if (!(o instanceof Map.Entry)) {
0583: return (false);
0584: }
0585: Map.Entry e = (Map.Entry) o;
0586: Object k = e.getKey();
0587: Object v = e.getValue();
0588: if (!map.containsKey(k)) {
0589: return (false);
0590: }
0591: if (v == null) {
0592: return (map.get(k) == null);
0593: } else {
0594: return (v.equals(map.get(k)));
0595: }
0596: }
0597:
0598: public boolean isEmpty() {
0599: return (map.isEmpty());
0600: }
0601:
0602: public Iterator iterator() {
0603: return (new CachedRowSetEntriesIterator(map));
0604: }
0605:
0606: // Removing entries is not allowed
0607: public boolean remove(Object o) {
0608: throw new UnsupportedOperationException();
0609: }
0610:
0611: // Removing entries is not allowed
0612: public boolean removeAll(Collection c) {
0613: throw new UnsupportedOperationException();
0614: }
0615:
0616: // Removing entries is not allowed
0617: public boolean retainAll(Collection c) {
0618: throw new UnsupportedOperationException();
0619: }
0620:
0621: public int size() {
0622: return (map.size());
0623: }
0624:
0625: }
0626:
0627: // Private implementation of Iterator that implements the iterator()
0628: // behavior for the Set returned by entrySet() from CachedRowSetMap
0629: private class CachedRowSetEntriesIterator implements Iterator {
0630:
0631: public CachedRowSetEntriesIterator(CachedRowSetMap map) {
0632: this .map = map;
0633: this .keys = map.keySet().iterator();
0634: }
0635:
0636: private CachedRowSetMap map = null;
0637: private Iterator keys = null;
0638:
0639: public boolean hasNext() {
0640: return (keys.hasNext());
0641: }
0642:
0643: public Object next() {
0644: Object key = keys.next();
0645: return (new CachedRowSetEntry(map, key));
0646: }
0647:
0648: // Removing entries is not allowed
0649: public void remove() {
0650: throw new UnsupportedOperationException();
0651: }
0652:
0653: }
0654:
0655: // Private implementation of Map.Entry that implements the behavior for
0656: // a single entry from the Set returned by entrySet() from CachedRowSetMap
0657: private class CachedRowSetEntry implements Map.Entry {
0658:
0659: public CachedRowSetEntry(CachedRowSetMap map, Object key) {
0660: this .map = map;
0661: this .key = key;
0662: }
0663:
0664: private CachedRowSetMap map;
0665: private Object key;
0666:
0667: public boolean equals(Object o) {
0668: if (o == null) {
0669: return (false);
0670: }
0671: if (!(o instanceof Map.Entry)) {
0672: return (false);
0673: }
0674: Map.Entry e = (Map.Entry) o;
0675: if (key == null) {
0676: if (e.getKey() != null) {
0677: return (false);
0678: }
0679: } else {
0680: if (!key.equals(e.getKey())) {
0681: return (false);
0682: }
0683: }
0684: Object v = map.get(key);
0685: if (v == null) {
0686: if (e.getValue() != null) {
0687: return (false);
0688: }
0689: } else {
0690: if (!v.equals(e.getValue())) {
0691: return (false);
0692: }
0693: }
0694: return (true);
0695: }
0696:
0697: public Object getKey() {
0698: return (key);
0699: }
0700:
0701: public Object getValue() {
0702: return (map.get(key));
0703: }
0704:
0705: public int hashCode() {
0706: Object value = map.get(key);
0707: return (((key == null) ? 0 : key.hashCode()) ^ ((value == null) ? 0
0708: : value.hashCode()));
0709: }
0710:
0711: public Object setValue(Object value) {
0712: Object previous = map.get(key);
0713: map.put(key, value);
0714: return (previous);
0715: }
0716:
0717: }
0718:
0719: // Private implementation of Set that implements the keySet() behavior
0720: // for CachedRowSetMap
0721: private class CachedRowSetKeys extends AbstractSet {
0722:
0723: public CachedRowSetKeys(CachedRowSetMap map) {
0724: this .map = map;
0725: }
0726:
0727: private CachedRowSetMap map;
0728:
0729: // Adding keys is not allowed
0730: public boolean add(Object o) {
0731: throw new UnsupportedOperationException();
0732: }
0733:
0734: // Adding keys is not allowed
0735: public boolean addAll(Collection c) {
0736: throw new UnsupportedOperationException();
0737: }
0738:
0739: // Removing keys is not allowed
0740: public void clear() {
0741: throw new UnsupportedOperationException();
0742: }
0743:
0744: public boolean contains(Object o) {
0745: return (map.containsKey(o));
0746: }
0747:
0748: public boolean isEmpty() {
0749: return (map.isEmpty());
0750: }
0751:
0752: public Iterator iterator() {
0753: return (new CachedRowSetKeysIterator(map));
0754: }
0755:
0756: // Removing keys is not allowed
0757: public boolean remove(Object o) {
0758: throw new UnsupportedOperationException();
0759: }
0760:
0761: // Removing keys is not allowed
0762: public boolean removeAll(Collection c) {
0763: throw new UnsupportedOperationException();
0764: }
0765:
0766: // Removing keys is not allowed
0767: public boolean retainAll(Collection c) {
0768: throw new UnsupportedOperationException();
0769: }
0770:
0771: public int size() {
0772: return (map.size());
0773: }
0774:
0775: }
0776:
0777: // Private implementation of Iterator that implements the iterator()
0778: // behavior for the Set returned by keySet() from CachedRowSetMap
0779: private class CachedRowSetKeysIterator implements Iterator {
0780:
0781: public CachedRowSetKeysIterator(CachedRowSetMap map) {
0782: this .map = map;
0783: this .keys = map.realKeys();
0784: }
0785:
0786: private CachedRowSetMap map = null;
0787: private Iterator keys = null;
0788:
0789: public boolean hasNext() {
0790: return (keys.hasNext());
0791: }
0792:
0793: public Object next() {
0794: return (keys.next());
0795: }
0796:
0797: // Removing keys is not allowed
0798: public void remove() {
0799: throw new UnsupportedOperationException();
0800: }
0801:
0802: }
0803:
0804: // Private implementation of Collection that implements the behavior
0805: // for the Collection returned by values() from CachedRowSetMap
0806: private class CachedRowSetValues extends AbstractCollection {
0807:
0808: public CachedRowSetValues(CachedRowSetMap map) {
0809: this .map = map;
0810: }
0811:
0812: private CachedRowSetMap map;
0813:
0814: public boolean add(Object o) {
0815: throw new UnsupportedOperationException();
0816: }
0817:
0818: public boolean addAll(Collection c) {
0819: throw new UnsupportedOperationException();
0820: }
0821:
0822: public void clear() {
0823: throw new UnsupportedOperationException();
0824: }
0825:
0826: public boolean contains(Object value) {
0827: return (map.containsValue(value));
0828: }
0829:
0830: public Iterator iterator() {
0831: return (new CachedRowSetValuesIterator(map));
0832: }
0833:
0834: public boolean remove(Object o) {
0835: throw new UnsupportedOperationException();
0836: }
0837:
0838: public boolean removeAll(Collection c) {
0839: throw new UnsupportedOperationException();
0840: }
0841:
0842: public boolean retainAll(Collection c) {
0843: throw new UnsupportedOperationException();
0844: }
0845:
0846: public int size() {
0847: return (map.size());
0848: }
0849:
0850: }
0851:
0852: // Private implementation of Iterator that implements the behavior
0853: // for the Iterator returned by values().iterator() from CachedRowSetMap
0854: private class CachedRowSetValuesIterator implements Iterator {
0855:
0856: public CachedRowSetValuesIterator(CachedRowSetMap map) {
0857: this .map = map;
0858: this .keys = map.keySet().iterator();
0859: }
0860:
0861: private CachedRowSetMap map;
0862: private Iterator keys;
0863:
0864: public boolean hasNext() {
0865: return (keys.hasNext());
0866: }
0867:
0868: public Object next() {
0869: return (map.get(keys.next()));
0870: }
0871:
0872: public void remove() {
0873: throw new UnsupportedOperationException();
0874: }
0875:
0876: }
0877:
0878: /**
0879: * <p>Return fake data of the appropriate type for use at design time.
0880: * (Snarfed from <code>ResultSetPropertyResolver</code>).</p>
0881: */
0882: private static Object getFakeData(ResultSetMetaData rsmd,
0883: String colName) throws SQLException {
0884:
0885: int colIndex = -1;
0886: for (int i = 1; i <= rsmd.getColumnCount(); i++) {
0887: if (rsmd.getColumnName(i).equals(colName)) {
0888: colIndex = i;
0889: break;
0890: }
0891: }
0892: switch (rsmd.getColumnType(colIndex)) {
0893: case Types.ARRAY:
0894: return new java.sql.Array() {
0895: public Object getArray() {
0896: return null;
0897: }
0898:
0899: public Object getArray(long index, int count) {
0900: return null;
0901: }
0902:
0903: public Object getArray(long index, int count, Map map) {
0904: return null;
0905: }
0906:
0907: public Object getArray(Map map) {
0908: return null;
0909: }
0910:
0911: public int getBaseType() {
0912: return Types.CHAR;
0913: }
0914:
0915: public String getBaseTypeName() {
0916: return "CHAR"; //NOI18N
0917: }
0918:
0919: public ResultSet getResultSet() {
0920: return null;
0921: }
0922:
0923: public ResultSet getResultSet(long index, int count) {
0924: return null;
0925: }
0926:
0927: public ResultSet getResultSet(long index, int count,
0928: Map map) {
0929: return null;
0930: }
0931:
0932: public ResultSet getResultSet(Map map) {
0933: return null;
0934: }
0935:
0936: public void free() {
0937: }
0938: };
0939: case Types.BIGINT:
0940:
0941: //return new Long(rowIndex);
0942: return new Long(123);
0943: case Types.BINARY:
0944: return new byte[] { 1, 2, 3, 4, 5 };
0945: case Types.BIT:
0946: return new Boolean(true);
0947: case Types.BLOB:
0948: return new javax.sql.rowset.serial.SerialBlob(new byte[] {
0949: 1, 2, 3, 4, 5 });
0950: case Types.BOOLEAN:
0951: return new Boolean(true);
0952: case Types.CHAR:
0953:
0954: //return new String(colName + rowIndex);
0955: return new String(bundle.getMessage("arbitraryCharData")); //NOI18N
0956: case Types.CLOB:
0957: return new javax.sql.rowset.serial.SerialClob(bundle
0958: .getMessage("arbitraryClobData").toCharArray());
0959: case Types.DATALINK:
0960: try {
0961: return new java.net.URL("http://www.sun.com"); //NOI18N
0962: } catch (java.net.MalformedURLException e) {
0963: return null;
0964: }
0965: case Types.DATE:
0966: return new java.sql.Date(new java.util.Date().getTime());
0967: case Types.DECIMAL:
0968: return new java.math.BigDecimal(java.math.BigInteger.ONE);
0969: case Types.DISTINCT:
0970: return null;
0971: case Types.DOUBLE:
0972:
0973: //return new Double(rowIndex);
0974: return new Double(123);
0975: case Types.FLOAT:
0976:
0977: //return new Double(rowIndex);
0978: return new Double(123);
0979: case Types.INTEGER:
0980:
0981: //return new Integer(rowIndex);
0982: return new Integer(123);
0983: case Types.JAVA_OBJECT:
0984:
0985: //return new String(colName + "_" + rowIndex); //NOI18N
0986: return new String(bundle.getMessage("arbitraryCharData")); //NOI18N
0987: case Types.LONGVARBINARY:
0988: return new byte[] { 1, 2, 3, 4, 5 };
0989: case Types.LONGVARCHAR:
0990:
0991: //return new String(colName + "_" + rowIndex); //NOI18N
0992: return new String(bundle.getMessage("arbitraryCharData")); //NOI18N
0993: case Types.NULL:
0994: return null;
0995: case Types.NUMERIC:
0996: return new java.math.BigDecimal(java.math.BigInteger.ONE);
0997: case Types.OTHER:
0998: return null;
0999: case Types.REAL:
1000:
1001: //return new Float(rowIndex);
1002: return new Float(123);
1003: case Types.REF:
1004: return new java.sql.Ref() {
1005: private Object data = new String(bundle
1006: .getMessage("arbitraryCharData")); //NOI18N
1007:
1008: public String getBaseTypeName() {
1009: return "CHAR"; //NOI18N
1010: }
1011:
1012: public Object getObject() {
1013: return data;
1014: }
1015:
1016: public Object getObject(Map map) {
1017: return data;
1018: }
1019:
1020: public void setObject(Object value) {
1021: data = value;
1022: }
1023: };
1024: case Types.SMALLINT:
1025:
1026: //return new Short((short)rowIndex);
1027: return new Short((short) 123);
1028: case Types.STRUCT:
1029: return new java.sql.Struct() {
1030: private String[] data = {
1031: bundle.getMessage("arbitraryCharData"),
1032: bundle.getMessage("arbitraryCharData2"),
1033: bundle.getMessage("arbitraryCharData3") }; //NOI18N
1034:
1035: public Object[] getAttributes() {
1036: return data;
1037: }
1038:
1039: public Object[] getAttributes(Map map) {
1040: return data;
1041: }
1042:
1043: public String getSQLTypeName() {
1044: return "CHAR"; //NOI18N
1045: }
1046: };
1047: case Types.TIME:
1048: return new java.sql.Time(new java.util.Date().getTime());
1049: case Types.TIMESTAMP:
1050: return new java.sql.Timestamp(new java.util.Date()
1051: .getTime());
1052: case Types.TINYINT:
1053:
1054: //return new Byte((byte)rowIndex);
1055: return new Byte((byte) 123);
1056: case Types.VARBINARY:
1057: return new byte[] { 1, 2, 3, 4, 5 };
1058: case Types.VARCHAR:
1059:
1060: //return new String(colName + "_" + rowIndex); //NOI18N
1061: return new String(bundle.getMessage("arbitraryCharData")); //NOI18N
1062: }
1063: return null;
1064: }
1065:
1066: }
|