001: package org.netbeans.modules.visualweb.dataprovider;
002:
003: /*
004: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
005: *
006: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
007: *
008: * The contents of this file are subject to the terms of either the GNU
009: * General Public License Version 2 only ("GPL") or the Common
010: * Development and Distribution License("CDDL") (collectively, the
011: * "License"). You may not use this file except in compliance with the
012: * License. You can obtain a copy of the License at
013: * http://www.netbeans.org/cddl-gplv2.html
014: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
015: * specific language governing permissions and limitations under the
016: * License. When distributing the software, include this License Header
017: * Notice in each file and include the License file at
018: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
019: * particular file as subject to the "Classpath" exception as provided
020: * by Sun in the GPL Version 2 section of the License file that
021: * accompanied this code. If applicable, add the following below the
022: * License Header, with the fields enclosed by brackets [] replaced by
023: * your own identifying information:
024: * "Portions Copyrighted [year] [name of copyright owner]"
025: *
026: * If you wish your version of this file to be governed by only the CDDL
027: * or only the GPL Version 2, indicate your decision by adding
028: * "[Contributor] elects to include this software in this distribution
029: * under the [CDDL or GPL Version 2] license." If you do not indicate a
030: * single choice of license, a recipient has the option to distribute
031: * your version of this file under either the CDDL, the GPL Version 2 or
032: * to extend the choice of license to its licensees as provided above.
033: * However, if you add GPL Version 2 code and therefore, elected the GPL
034: * Version 2 license, then the option applies only if the new code is
035: * made subject to such option by the copyright holder.
036: *
037: * Contributor(s):
038: *
039: * Portions Copyrighted 2007 Sun Microsystems, Inc.
040: */
041: import com.sun.data.provider.DataListener;
042: import com.sun.data.provider.DataProvider;
043: import com.sun.data.provider.FieldKey;
044: import com.sun.data.provider.RowKey;
045: import com.sun.data.provider.TableCursorListener;
046: import com.sun.data.provider.TableCursorVetoException;
047: import com.sun.data.provider.TableDataListener;
048: import com.sun.data.provider.TableDataProvider;
049: import com.sun.data.provider.TransactionalDataListener;
050: import com.sun.data.provider.TransactionalDataProvider;
051: import com.sun.data.provider.impl.IndexRowKey;
052: import com.sun.data.provider.impl.ObjectListDataProvider;
053: import java.io.ByteArrayInputStream;
054: import java.io.ByteArrayOutputStream;
055: import java.io.ObjectInputStream;
056: import java.io.ObjectOutputStream;
057: import java.util.ArrayList;
058: import java.util.List;
059: import java.util.Map;
060: import org.netbeans.junit.NbTestCase;
061:
062: /**
063: *
064: * @author winstonp
065: */
066: public class ObjectListDataProviderTest extends NbTestCase {
067:
068: // ------------------------------------------------------ Instance Variables
069: /**
070: * <p>The beans being wrapped by the {@link DataProvider} under test.
071: */
072: private TestBean beans[] = null;
073: /**
074: * <p>The {@link DataProvider} instance under test.
075: */
076: private ObjectListDataProvider dp = null;
077: /**
078: * <p>List representation of beans being wrapped.</p>
079: */
080: private List list = null;
081: /**
082: * <p>Event listener for event testing.</p>
083: */
084: private Listener listener = null;
085: /**
086: * <p>Event listener for event testing.</p>
087: */
088: private MyCursorListener tdcListener = null;
089: /**
090: * <p>Event listener for event testing.</p>
091: */
092: private MyDataListener tdpListener = null;
093: // -------------------------------------------------------- Static Variables
094: // Dummy variables just to provide access to type information
095: private static int intArray[] = new int[0];
096: private static TestBean nestedArray[] = new TestBean[0];
097: /**
098: * <p>Descriptors for the set of fieldKeys we expect to be known.</p>
099: */
100: private static Descriptor[] fieldKeys = {
101: // Specific fieldKeys of this class
102: new Descriptor("public1", String.class, false,
103: "This is public1"),
104: new Descriptor("public2", Integer.class, false,
105: new Integer(8888)), };
106: /**
107: * <p>Descriptors for the set of properties we expect to be known.</p>
108: */
109: private static Descriptor[] properties = {
110: // Specific properties of this class
111: new Descriptor("booleanProperty", Boolean.class, false,
112: Boolean.TRUE),
113: new Descriptor("byteProperty", Byte.class, false, new Byte(
114: (byte) 123)),
115: new Descriptor("doubleProperty", Double.class, false,
116: new Double(654.321)),
117: new Descriptor("floatProperty", Float.class, false,
118: new Float((float) 123.45)),
119: new Descriptor("id", String.class, false, null),
120: new Descriptor("intArray", intArray.getClass(), false, null),
121: new Descriptor("intList", List.class, false, null),
122: new Descriptor("intProperty", Integer.class, false,
123: new Integer(1234)),
124: new Descriptor("longProperty", Long.class, false, new Long(
125: 54321)),
126: new Descriptor("nestedArray", nestedArray.getClass(),
127: false, null),
128: new Descriptor("nestedList", List.class, false, null),
129: new Descriptor("nestedMap", Map.class, false, null),
130: new Descriptor("nestedProperty", TestBean.class, false,
131: null),
132: new Descriptor("readOnly", String.class, true, null),
133: new Descriptor("shortProperty", Short.class, false,
134: new Short((short) 321)),
135: new Descriptor("stringProperty", String.class, false,
136: "This is a String"),
137: new Descriptor("nullString", String.class, true, null),
138: // Inherited from java.lang.Object
139: new Descriptor("class", Class.class, true, null), };
140: /**
141: * <p>Descriptors for updates that should be applied and tested.</p>
142: */
143: private static Update[] updates = {
144: // Updates to read-write properties
145: new Update("booleanProperty", Boolean.FALSE),
146: new Update("byteProperty", new Byte((byte) 213)),
147: new Update("doubleProperty", new Double(123.456)),
148: new Update("floatProperty", new Float((float) 111.22)),
149: new Update("intProperty", new Integer(23432)),
150: new Update("longProperty", new Long((long) 55555)),
151: new Update("shortProperty", new Short((short) 123)),
152: new Update("stringProperty", "Updated string value"),
153: // Public fieldKeys are read-write as well
154: new Update("public1", "revised String1 value"),
155: new Update("public2", new Integer(55555)), };
156:
157: public ObjectListDataProviderTest(String testName) {
158: super (testName);
159: new ObjectListDataProvider();
160: }
161:
162: @Override
163: protected void setUp() throws Exception {
164: super .setUp();
165: beans = new TestBean[5];
166: list = new ArrayList();
167: for (int i = 0; i < beans.length; i++) {
168: beans[i] = new TestBean("test" + i);
169: list.add(beans[i]);
170: }
171: dp = new ObjectListDataProvider(list, true);
172: }
173:
174: @Override
175: protected void tearDown() throws Exception {
176: super .tearDown();
177: dp = null;
178: beans = null;
179: list = null;
180: listener = null;
181: tdcListener = null;
182: tdpListener = null;
183: }
184:
185: // ------------------------------------------------- Individual Test Methods
186: /**
187: * <p>Check convenience methods on abstract base class that
188: * should still show through the concrete implementation.</p>
189: */
190: public void testBaseClassMethods() {
191:
192: // Operate on FieldKey or field identifier
193: for (int i = 0; i < properties.length; i++) {
194: String fieldId = properties[i].name;
195: FieldKey fieldKey = dp.getFieldKey(fieldId);
196: assertEquals("type(" + fieldId + ")", dp.getType(fieldKey),
197: dp.getType(fieldId));
198: assertEquals("value(" + fieldId + ")", dp
199: .getValue(fieldKey), dp.getValue(fieldId));
200: assertEquals("readOnly(" + fieldId + ")", dp
201: .isReadOnly(fieldKey), dp.isReadOnly(fieldId));
202: }
203:
204: }
205:
206: /**
207: * <p>Check for events related to row appending.</p>
208: */
209: public void testEventsAppend() {
210:
211: // Register listener we will need
212: MyTransactionalListener tListener = new MyTransactionalListener();
213: dp.addTransactionalDataListener(tListener);
214:
215: // Append a row and allow the DP to create an instance
216: assertTrue(dp.canAppendRow());
217: RowKey rk1 = dp.appendRow();
218: assertNull(dp.getValue("id", rk1));
219: dp.setValue("id", rk1, "testA");
220: assertEquals("testA", dp.getValue("id", rk1));
221:
222: // Append a row that is a specific object instance
223: assertTrue(dp.canAppendRow());
224: TestBean beanB = new TestBean("testB");
225: RowKey rk2 = dp.appendRow(beanB);
226:
227: // Commit the results and validate the event history
228: dp.commitChanges();
229: assertEquals("rowAdded/RowKey[5]//"
230: + "FieldKey[id]/RowKey[5]/null/testA//"
231: + "FieldKey[id]/null/testA//" + "rowAdded/RowKey[6]//"
232: + "changesCommitted//", tListener.getLog());
233:
234: // Validate the remaining beans
235: /*
236: assertEquals(beans.length - 2, list.size());
237: assertEquals("test0", ((TestBean) list.get(0)).getId());
238: assertEquals("test2", ((TestBean) list.get(1)).getId());
239: assertEquals("test4", ((TestBean) list.get(2)).getId());
240: */
241:
242: }
243:
244: /**
245: * <p>Check for event propogation for basic DataProvider events.</p>
246: */
247: public void testEventsBasic() {
248:
249: assertNotNull(dp.getFieldKey("intProperty"));
250: assertNotNull(dp.getFieldKey("public1"));
251:
252: // Register a new listener and verify that it worked
253: listener = new Listener();
254: dp.addDataListener(listener);
255: DataListener listeners[] = dp.getDataListeners();
256: assertEquals(1, listeners.length);
257: assertTrue(listener == listeners[0]);
258:
259: // Make sure we log the update events correctly
260: dp.setValue(dp.getFieldKey("intProperty"), new Integer(23432));
261: dp.setValue(dp.getFieldKey("public1"), "new public1");
262: assertEquals(
263: "intProperty/1234/23432//public1/This is public1/new public1//",
264: listener.getLog());
265:
266: // Deregister the old listener and verify that it worked
267: dp.removeDataListener(listener);
268: listeners = dp.getDataListeners();
269: assertEquals(0, listeners.length);
270:
271: }
272:
273: /**
274: * <p>Check for event propogation for cursor changes.</p>
275: */
276: public void testEventsCursor() throws Exception {
277:
278: // Register a new listener and verify that it worked
279: tdcListener = new MyCursorListener();
280: dp.addTableCursorListener(tdcListener);
281: TableCursorListener listeners[] = dp.getTableCursorListeners();
282: assertEquals(1, listeners.length);
283: assertTrue(tdcListener == listeners[0]);
284:
285: // Make sure we log cursor change events correctly
286: assertEquals(new IndexRowKey(0), dp.getCursorRow());
287: dp.setCursorRow(new IndexRowKey(2));
288: assertEquals(new IndexRowKey(2), dp.getCursorRow());
289: dp.setCursorRow(new IndexRowKey(1));
290: assertEquals(new IndexRowKey(1), dp.getCursorRow());
291: assertEquals(
292: "cursorChanging/RowKey[0]/RowKey[2]//cursorChanged/RowKey[0]/RowKey[2]//"
293: + "cursorChanging/RowKey[2]/RowKey[1]//cursorChanged/RowKey[2]/RowKey[1]//",
294: tdcListener.getLog());
295:
296: // Make sure we can deal with vetos as well
297: tdcListener.clear();
298: tdcListener.setVeto(true);
299: try {
300: dp.setCursorRow(new IndexRowKey(3));
301: fail("Should have thrown TableCursorVetoException");
302: } catch (TableCursorVetoException e) {
303: ; // Expected result
304: }
305: assertEquals(new IndexRowKey(1), dp.getCursorRow());
306: assertEquals(
307: "cursorChanging/RowKey[1]/RowKey[3]//cursorVetoed/RowKey[1]/RowKey[3]//",
308: tdcListener.getLog());
309:
310: // Deregister the old listener and verify that it worked
311: dp.removeTableCursorListener(tdcListener);
312: listeners = dp.getTableCursorListeners();
313: assertEquals(0, listeners.length);
314:
315: }
316:
317: /**
318: * <p>Check for event propogation on random data changes.</p>
319: */
320: public void testEventsData() {
321:
322: // Register a new listener and verify that it worked
323: tdpListener = new MyDataListener();
324: dp.addTableDataListener(tdpListener);
325: TableDataListener listeners[] = dp.getTableDataListeners();
326: assertEquals(1, listeners.length);
327: assertTrue(tdpListener == listeners[0]);
328:
329: dp.cursorFirst();
330: // Make sure we log the update events correctly
331: dp.setValue(dp.getFieldKey("intProperty"), new Integer(23432)); // Change, so event expected
332: Object value = dp.getValue(dp.getFieldKey("stringProperty"));
333: dp.setValue(dp.getFieldKey("stringProperty"), value); // No change, so no event expected
334:
335: assertEquals("FieldKey[intProperty]/RowKey[0]/1234/23432//" + // Row-specific event
336: "FieldKey[intProperty]/1234/23432//", // Row-independent event
337: tdpListener.getLog());
338:
339: // We should get a provider change event too
340: tdpListener.clear();
341: dp.setList(dp.getList());
342: assertEquals("providerChanged//", tdpListener.getLog());
343:
344: // Deregister the old listener and verify that it worked
345: dp.removeTableDataListener(tdpListener);
346: listeners = dp.getTableDataListeners();
347: assertEquals(0, listeners.length);
348:
349: }
350:
351: /**
352: * <p>Check for events related to row insertion.</p>
353: */
354: public void testEventsInsert() {
355:
356: // FIXME - inserts are not currently supported. When they are,
357: // the processing in commitChanges() will need to interleave the
358: // deletes and inserts so that references to the pre-commit
359: // row keys are not messed up
360: assertTrue(!dp.canInsertRow(dp.getCursorRow()));
361:
362: }
363:
364: /**
365: * <p>Check for events related to row removal -- ascending ordering.</p>
366: */
367: public void testEventsRemovesAscending() {
368:
369: // Register listener we will need
370: MyTransactionalListener tListener = new MyTransactionalListener();
371: dp.addTransactionalDataListener(tListener);
372:
373: // Remove the rows at indexes 1 and 3, and commit the changes
374: RowKey rk = null;
375: rk = dp.findFirst("id", "test1");
376: assertNotNull(rk);
377: assertTrue(dp.canRemoveRow(rk));
378: dp.removeRow(rk);
379: rk = dp.findFirst("id", "test3");
380: assertNotNull(rk);
381: assertTrue(dp.canRemoveRow(rk));
382: dp.removeRow(rk);
383: dp.commitChanges();
384:
385: // Validate the event history
386: assertEquals("rowRemoved/RowKey[1]//"
387: + "rowRemoved/RowKey[3]//" + "changesCommitted//",
388: tListener.getLog());
389:
390: // Validate the remaining beans
391: assertEquals(beans.length - 2, list.size());
392: assertEquals("test0", ((TestBean) list.get(0)).getId());
393: assertEquals("test2", ((TestBean) list.get(1)).getId());
394: assertEquals("test4", ((TestBean) list.get(2)).getId());
395:
396: }
397:
398: /**
399: * <p>Check for events related to row removal -- descending ordering.</p>
400: */
401: public void testEventsRemovesDescending() {
402:
403: // Register listener we will need
404: MyTransactionalListener tListener = new MyTransactionalListener();
405: dp.addTransactionalDataListener(tListener);
406:
407: // Remove the rows at indexes 3 and 1, and commit the changes
408: RowKey rk = null;
409: rk = dp.findFirst("id", "test3");
410: assertNotNull(rk);
411: assertTrue(dp.canRemoveRow(rk));
412: dp.removeRow(rk);
413: rk = dp.findFirst("id", "test1");
414: assertNotNull(rk);
415: assertTrue(dp.canRemoveRow(rk));
416: dp.removeRow(rk);
417: dp.commitChanges();
418:
419: // Validate the event history
420: assertEquals("rowRemoved/RowKey[3]//"
421: + "rowRemoved/RowKey[1]//" + "changesCommitted//",
422: tListener.getLog());
423:
424: // Validate the remaining beans
425: assertEquals(beans.length - 2, list.size());
426: assertEquals("test0", ((TestBean) list.get(0)).getId());
427: assertEquals("test2", ((TestBean) list.get(1)).getId());
428: assertEquals("test4", ((TestBean) list.get(2)).getId());
429:
430: }
431:
432: /**
433: * <p>Check for transactional updates to existing rows.</p>
434: */
435: public void testEventsUpdates() {
436:
437: // Register listeners we will need for verification
438: TableDataListener aListener = new MyDataListener();
439: MyTransactionalListener tListener = new MyTransactionalListener();
440: dp.addTableDataListener(aListener);
441: TableDataListener aListeners[] = dp.getTableDataListeners();
442: assertEquals(1, aListeners.length);
443: assertTrue(aListener == aListeners[0]);
444: dp.addTransactionalDataListener(tListener);
445: aListeners = dp.getTableDataListeners();
446: assertEquals(2, aListeners.length);
447: assertTrue(aListener == aListeners[0]);
448: assertTrue(tListener == aListeners[1]);
449: TransactionalDataListener tListeners[] = dp
450: .getTransactionalDataListeners();
451: assertEquals(1, tListeners.length);
452: assertTrue(tListener == tListeners[0]);
453:
454: // Perform an update, check for event and new value showing
455: dp.cursorFirst();
456: dp.setValue(dp.getFieldKey("intProperty"), new Integer(23432)); // Change, so event expected
457: assertEquals("FieldKey[intProperty]/RowKey[0]/1234/23432//" + // Row-specific event
458: "FieldKey[intProperty]/1234/23432//", // Row-independent event
459: tListener.getLog());
460: assertEquals(new Integer(23432), (Integer) dp.getValue(dp
461: .getFieldKey("intProperty")));
462:
463: // Fake an update, check for no event and no change in value showing
464: tListener.clear();
465: dp.setValue(dp.getFieldKey("intProperty"), new Integer(23432)); // Change, so event expected
466: assertEquals("", tListener.getLog());
467: assertEquals(new Integer(23432), (Integer) dp.getValue(dp
468: .getFieldKey("intProperty")));
469:
470: // Revert and ensure that old value shows again
471: tListener.clear();
472: dp.revertChanges();
473: assertEquals("changesReverted//", tListener.getLog());
474: assertEquals(new Integer(1234), (Integer) dp.getValue(dp
475: .getFieldKey("intProperty")));
476:
477: // Make a change, commit, and ensure revert does not erase it
478: tListener.clear();
479: dp.setValue(dp.getFieldKey("intProperty"), new Integer(43234)); // Change, so event expected
480: assertEquals("FieldKey[intProperty]/RowKey[0]/1234/43234//" + // Row-specific event
481: "FieldKey[intProperty]/1234/43234//", // Row-independent event
482: tListener.getLog());
483: assertEquals(new Integer(43234), (Integer) dp.getValue(dp
484: .getFieldKey("intProperty")));
485: tListener.clear();
486: dp.commitChanges();
487: assertEquals(new Integer(43234), (Integer) dp.getValue(dp
488: .getFieldKey("intProperty")));
489: dp.revertChanges();
490: assertEquals(new Integer(43234), (Integer) dp.getValue(dp
491: .getFieldKey("intProperty")));
492: assertEquals("changesCommitted//changesReverted//", tListener
493: .getLog());
494:
495: }
496:
497: /**
498: * <p>Check some things that should <strong>not</strong> work.</p>
499: */
500: public void testNegative() {
501:
502: // Access to unknown fieldKey/property
503: try {
504: dp.getFieldKey("unknown id value");
505: fail("Should have thrown IllegalArgumentException");
506: } catch (IllegalArgumentException e) {
507: ; // Expected result
508: }
509:
510: // Attempt to update a read only value
511: try {
512: dp.setValue(dp.getFieldKey("readOnly"), "xyz");
513: fail("Should have thrown IllegalStateException");
514: } catch (IllegalStateException e) {
515: ; // Expected result
516: }
517:
518: // Attempt to set value with an incorrect data type
519: try {
520: dp.setValue(dp.getFieldKey("intProperty"), "string value");
521: fail("Should have thrown IllegalArgumentException");
522: } catch (IllegalArgumentException e) {
523: ; // Expected result
524: }
525:
526: }
527:
528: /**
529: * <p>Ensure that access to public fields can be turned off.</p>
530: */
531: public void testNoFields() {
532:
533: dp = new ObjectListDataProvider(list, false);
534: try {
535: dp.getFieldKey("public1");
536: fail("Should have thrown IllegalArgumentException");
537: } catch (IllegalArgumentException e) {
538: ; // Expected result
539: }
540: try {
541: dp.getFieldKey("public2");
542: fail("Should have thrown IllegalArgumentException");
543: } catch (IllegalArgumentException e) {
544: ; // Expected result
545: }
546:
547: // Check the available properties for expected characteristics
548: checkProperties();
549: checkExtras();
550:
551: }
552:
553: /**
554: * <p>Test a pristine instance.</p>
555: */
556: public void testPristine() throws Exception {
557:
558: assertTrue(dp.isIncludeFields());
559: assertEquals(beans.length, dp.getRowCount());
560:
561: // Check the available fieldKeys and properties for expected characteristics
562: for (int i = 0; i < beans.length; i++) {
563: dp.setCursorRow(dp.getRowKey("" + i));
564: assertEquals("test" + i, dp.getValue(dp.getFieldKey("id")));
565: checkFields();
566: checkProperties();
567: checkExtras();
568: }
569:
570: // Check random access on the id property
571: for (int i = 0; i < beans.length; i++) {
572: assertEquals("test" + i, dp.getValue(dp.getFieldKey("id"),
573: dp.getRowKey("" + i)));
574: }
575:
576: }
577:
578: /**
579: * <p>Test serializability of this data provider.</p>
580: */
581: public void testSerializable() throws Exception {
582:
583: ByteArrayOutputStream baos = new ByteArrayOutputStream();
584: ObjectOutputStream oos = new ObjectOutputStream(baos);
585: oos.writeObject(dp);
586: oos.close();
587: ByteArrayInputStream bais = new ByteArrayInputStream(baos
588: .toByteArray());
589: ObjectInputStream ois = new ObjectInputStream(bais);
590: dp = (ObjectListDataProvider) ois.readObject();
591: ois.close();
592:
593: testPristine();
594:
595: }
596:
597: /**
598: * <p>Test updates to updateable fieldKeys and properties.</p>
599: */
600: public void testUpdates() {
601:
602: // Do the easy cases
603: checkUpdates();
604:
605: }
606:
607: // --------------------------------------------------------- Support Methods
608: /**
609: * <p>Ensure that the array returned by <code>getFieldKeys()</code>
610: * does not include any keys that should not be there.</p>
611: */
612: private void checkExtras() {
613:
614: FieldKey keys[] = dp.getFieldKeys();
615: assertNotNull(keys);
616: for (int i = 0; i < keys.length; i++) {
617: String name = keys[i].getFieldId();
618: boolean found = false;
619: for (int j = 0; j < properties.length; j++) {
620: if (name.equals(properties[j].name)) {
621: found = true;
622: break;
623: }
624: }
625: if (!found && dp.isIncludeFields()) {
626: for (int j = 0; j < fieldKeys.length; j++) {
627: if (name.equals(fieldKeys[j].name)) {
628: found = true;
629: break;
630: }
631: }
632: }
633: assertTrue("Id '" + name + "' is valid", found);
634: }
635:
636: }
637:
638: /**
639: * <p>Ensure that all the expected fieldKeys are present and have
640: * the specified default values (where possible).</p>
641: */
642: private void checkFields() {
643:
644: FieldKey dk = null;
645: String name = null;
646: for (int i = 0; i < fieldKeys.length; i++) {
647: name = fieldKeys[i].name;
648: dk = dp.getFieldKey(name);
649: assertNotNull("FieldKey for '" + name + "'", dk);
650: assertTrue("Type for '" + name + "'", isAssignableFrom(dp
651: .getType(dk), fieldKeys[i].type));
652: assertEquals("ReadOnly for '" + name + "'",
653: fieldKeys[i].canSetValue, dp.isReadOnly(dk));
654: if (fieldKeys[i].defaultValue != null) {
655: assertEquals("Value for '" + name + "'",
656: fieldKeys[i].defaultValue, dp.getValue(dk));
657: }
658: }
659:
660: }
661:
662: /**
663: * <p>Ensure that all the expected properties are present and have
664: * the specified default values (where possible).</p>
665: */
666: private void checkProperties() {
667:
668: FieldKey dk = null;
669: String name = null;
670: for (int i = 0; i < properties.length; i++) {
671: name = properties[i].name;
672: dk = dp.getFieldKey(name);
673: assertNotNull("FieldKey for '" + name + "'", dk);
674: assertTrue("Type for '" + name + "'", isAssignableFrom(dp
675: .getType(dk), properties[i].type));
676: assertEquals("ReadOnly for '" + name + "'",
677: properties[i].canSetValue, dp.isReadOnly(dk));
678: if (properties[i].defaultValue != null) {
679: assertEquals("Value for '" + name + "'",
680: properties[i].defaultValue, dp.getValue(dk));
681: }
682: }
683:
684: }
685:
686: private boolean isAssignableFrom(Class to, Class from) {
687: if (to.isPrimitive()) {
688: if (to == Boolean.TYPE) {
689: to = Boolean.class;
690: } else if (to == Character.TYPE) {
691: to = Character.class;
692: } else if (to == Byte.TYPE) {
693: to = Byte.class;
694: } else if (to == Short.TYPE) {
695: to = Short.class;
696: } else if (to == Integer.TYPE) {
697: to = Integer.class;
698: } else if (to == Long.TYPE) {
699: to = Long.class;
700: } else if (to == Float.TYPE) {
701: to = Float.class;
702: } else if (to == Double.TYPE) {
703: to = Double.class;
704: }
705: }
706: return to.isAssignableFrom(from);
707: }
708:
709: /**
710: * <p>Ensure that we can update all the simple fieldKeys and properties
711: * that should be updatable by default.</p>
712: */
713: private void checkUpdates() {
714:
715: FieldKey dk = null;
716: String name = null;
717: for (int i = 0; i < updates.length; i++) {
718: name = updates[i].name;
719: try {
720: dp.setValue(dp.getFieldKey(name), updates[i].value);
721: } catch (Exception e) {
722: fail("Cannot set value for '" + name + "':" + e);
723: }
724: assertEquals("Updated value for '" + name + "'",
725: updates[i].value, dp.getValue(dp.getFieldKey(name)));
726: }
727:
728: }
729:
730: // Private class to describe the expected properties
731: static class Descriptor {
732:
733: public Descriptor(String name, Class type, boolean canSetValue,
734: Object defaultValue) {
735: this .name = name;
736: this .type = type;
737: this .canSetValue = canSetValue;
738: this .defaultValue = defaultValue;
739: }
740:
741: public String name;
742: public Class type;
743: public boolean canSetValue;
744: public Object defaultValue;
745: }
746:
747: // Private class to represent an event listener
748: static class Listener implements DataListener {
749:
750: String log = "";
751:
752: public String getLog() {
753: return this .log;
754: }
755:
756: public void clear() {
757: this .log = "";
758: }
759:
760: public void valueChanged(DataProvider dp, FieldKey dk,
761: Object oldValue, Object newValue) {
762: log += dk.getFieldId() + "/" + oldValue + "/" + newValue
763: + "//";
764: }
765:
766: public void providerChanged(DataProvider dp) {
767: log += "providerChanged//";
768: }
769: }
770:
771: // Private class to represent a TableDataProvider cursor listener
772: static class MyCursorListener implements TableCursorListener {
773:
774: boolean veto = false;
775: String log = "";
776:
777: public String getLog() {
778: return this .log;
779: }
780:
781: public void clear() {
782: this .log = "";
783: }
784:
785: public void cursorChanged(TableDataProvider dp, RowKey oldRow,
786: RowKey newRow) {
787: log += "cursorChanged/" + oldRow + "/" + newRow + "//";
788: }
789:
790: public void cursorChanging(TableDataProvider dp, RowKey oldRow,
791: RowKey newRow) throws TableCursorVetoException {
792: log += "cursorChanging/" + oldRow + "/" + newRow + "//";
793: if (veto) {
794: log += "cursorVetoed/" + oldRow + "/" + newRow + "//";
795: throw new TableCursorVetoException("No way, Jose");
796: }
797: }
798:
799: public boolean isVeto() {
800: return this .veto;
801: }
802:
803: public void setVeto(boolean veto) {
804: this .veto = veto;
805: }
806: }
807:
808: // Private class to represent a TableDataProvider event listener
809: class MyDataListener implements TableDataListener {
810:
811: String log = "";
812:
813: public String getLog() {
814: return this .log;
815: }
816:
817: public void clear() {
818: this .log = "";
819: }
820:
821: public void valueChanged(DataProvider dp, FieldKey fk,
822: Object oldValue, Object newValue) {
823: log += fk + "/" + oldValue + "/" + newValue + "//";
824: }
825:
826: public void providerChanged(DataProvider dp) {
827: log += "providerChanged//";
828: }
829:
830: public void rowAdded(TableDataProvider dp, RowKey rk) {
831: log += "rowAdded/" + rk + "//";
832: }
833:
834: public void rowRemoved(TableDataProvider dp, RowKey rk) {
835: log += "rowRemoved/" + rk + "//";
836: }
837:
838: public void valueChanged(TableDataProvider dp, FieldKey fk,
839: RowKey rk, Object oldValue, Object newValue) {
840: log += fk + "/" + rk + "/" + oldValue + "/" + newValue
841: + "//";
842: }
843: }
844:
845: // Private class to represent a TransactionalDataProvider event listener
846: class MyTransactionalListener implements TransactionalDataListener,
847: TableDataListener {
848:
849: String log = "";
850:
851: public String getLog() {
852: return this .log;
853: }
854:
855: public void clear() {
856: this .log = "";
857: }
858:
859: public void changesCommitted(TransactionalDataProvider tdp) {
860: log += "changesCommitted//";
861: }
862:
863: public void changesReverted(TransactionalDataProvider tdp) {
864: log += "changesReverted//";
865: }
866:
867: public void providerChanged(DataProvider dp) {
868: log += "providerChanged//";
869: }
870:
871: public void rowAdded(TableDataProvider dp, RowKey rk) {
872: log += "rowAdded/" + rk + "//";
873: }
874:
875: public void rowRemoved(TableDataProvider dp, RowKey rk) {
876: log += "rowRemoved/" + rk + "//";
877: }
878:
879: public void valueChanged(DataProvider dp, FieldKey fk,
880: Object oldValue, Object newValue) {
881: log += fk + "/" + oldValue + "/" + newValue + "//";
882: }
883:
884: public void valueChanged(TableDataProvider dp, FieldKey fk,
885: RowKey rk, Object oldValue, Object newValue) {
886: log += fk + "/" + rk + "/" + oldValue + "/" + newValue
887: + "//";
888: }
889: }
890:
891: // Private class to describe updates to be performed and checked
892: static class Update {
893:
894: public Update(String name, Object value) {
895: this .name = name;
896: this .value = value;
897: }
898:
899: public String name;
900: public Object value;
901: }
902: }
|