1   /*
2    * Copyright 2001-2004 The Apache Software Foundation.
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * 
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    * 
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */ 
16   
17  package org.apache.commons.betwixt;
18  
19  import java.io.FileInputStream;
20  import java.io.IOException;
21  import java.io.InputStream;
22  import java.io.StringReader;
23  import java.io.StringWriter;
24  import java.math.BigDecimal;
25  import java.math.BigInteger;
26  import java.sql.Date;
27  import java.sql.Time;
28  import java.sql.Timestamp;
29  import java.text.ParseException;
30  import java.text.SimpleDateFormat;
31  import java.util.ArrayList;
32  import java.util.Calendar;
33  import java.util.List;
34  import java.util.Iterator;
35  
36  import junit.framework.Test;
37  import junit.framework.TestSuite;
38  import junit.textui.TestRunner;
39  
40  import org.apache.commons.beanutils.ConversionException;
41  import org.apache.commons.beanutils.ConvertUtils;
42  import org.apache.commons.beanutils.Converter;
43  import org.apache.commons.betwixt.io.BeanReader;
44  import org.apache.commons.betwixt.io.BeanWriter;
45  import org.apache.commons.betwixt.strategy.ConvertUtilsObjectStringConverter;
46  import org.apache.commons.betwixt.strategy.HyphenatedNameMapper;
47  import org.apache.commons.digester.ExtendedBaseRules;
48  import org.apache.commons.digester.Rule;
49  import org.xml.sax.Attributes;
50  
51  
52  /*** Test harness for the BeanReader
53    *
54    * @author <a href="mailto:jstrachan@apache.org">James Strachan</a>
55    * @version $Revision: 155402 $
56    */
57  public class TestBeanReader extends AbstractTestCase {
58      
59      public static void main( String[] args ) {
60          TestRunner.run( suite() );
61      }
62      
63      public static Test suite() {
64          return new TestSuite(TestBeanReader.class);
65      }
66      
67      public TestBeanReader(String testName) {
68          super(testName);
69      }
70      
71      public void testBeanWriter() throws Exception {
72          BeanReader reader = new BeanReader();
73          reader.registerBeanClass( getBeanClass() );
74  
75          InputStream in = getXMLInput();
76          try {
77              Object bean = reader.parse( in );
78  
79              testCustomer(bean);
80              
81              String out = writeBean( bean );
82              String xml = "<?xml version='1.0'?><CustomerBean><name>James</name><time>20:30:40</time>"
83                  + "<date>2002-03-17</date><projectMap/><bigDecimal>1234567890.12345</bigDecimal>"
84                  + "<bigInteger>1234567890</bigInteger><projectNames/><emails>"
85                  + "<email>jstrachan@apache.org</email><email>james_strachan@yahoo.co.uk</email>"
86                  + "</emails><timestamp>2002-03-17 20:30:40.0</timestamp><locations>"
87                  + "<location>London</location><location>Bath</location></locations>"
88                  + "<ID/><projectURLs/><nickName/><address><code/><country/>"
89                  + "<city/><street/></address><numbers><number>3</number><number>4</number>"
90                  + "<number>5</number></numbers></CustomerBean>";
91                  
92              xmlAssertIsomorphic(parseString(xml), parseString(out) , true);
93          }
94          finally {
95              in.close();
96          }
97      }
98      
99      public void testWriteThenRead() throws Exception {
100         // test defaults
101         PersonBean bean = new PersonBean(21, "Samual Smith");
102         StringWriter stringWriter = new StringWriter();
103         BeanWriter beanWriter = new BeanWriter(stringWriter);
104         beanWriter.write(bean);
105         stringWriter.flush();
106         String xml = "<?xml version='1.0'?>" + stringWriter.toString();
107         
108         BeanReader reader = new BeanReader();
109         reader.registerBeanClass( PersonBean.class );
110         bean = (PersonBean) reader.parse(new StringReader(xml));
111         
112         assertEquals("Person age wrong", 21 , bean.getAge());
113         assertEquals("Person name wrong", "Samual Smith" , bean.getName());
114         
115         // test now with attributes for primitives
116         bean = new PersonBean(19, "John Smith");
117         stringWriter = new StringWriter();
118         beanWriter = new BeanWriter(stringWriter);
119         beanWriter.getXMLIntrospector().getConfiguration().setAttributesForPrimitives(true);
120         beanWriter.write(bean);
121         stringWriter.flush();
122         xml = "<?xml version='1.0'?>" + stringWriter.toString();
123         
124         reader = new BeanReader();
125         reader.getXMLIntrospector().getConfiguration().setAttributesForPrimitives(true);
126         reader.registerBeanClass( PersonBean.class );
127         bean = (PersonBean) reader.parse(new StringReader(xml));
128         
129         assertEquals("[Attribute] Person age wrong", 19 , bean.getAge());
130         assertEquals("[Attribute] Person name wrong", "John Smith" , bean.getName());
131     }
132 
133     public String writeBean(Object bean) throws Exception {
134         StringWriter out = new StringWriter();
135         out.write("<?xml version='1.0'?>");
136         BeanWriter writer = new BeanWriter(out);
137 		writer.getBindingConfiguration().setMapIDs(false);
138         writer.enablePrettyPrint();
139         writer.write( bean );
140         return out.getBuffer().toString();
141     }
142     
143     /*** @return the bean class to use as the root */
144     public Class getBeanClass() {
145         return CustomerBean.class;
146     }
147     
148     /*** 
149      * Asserts that the parsed CustomerBean looks fine
150      */
151     protected void testCustomer(Object bean) throws Exception {
152         assertTrue( "Is a CustomerBean", bean instanceof CustomerBean );
153         CustomerBean customer = (CustomerBean) bean;
154      
155         assertEquals( "name", "James", customer.getName() );
156         
157         String[] emails = customer.getEmails();
158         assertTrue( "contains some emails", emails != null );
159         assertEquals( "emails.length", 2, emails.length );
160         assertEquals( "emails[0]", "jstrachan@apache.org", emails[0] );
161         assertEquals( "emails[1]", "james_strachan@yahoo.co.uk", emails[1] );
162         
163         int[] numbers = customer.getNumbers();
164         assertTrue( "contains some numbers", numbers != null );
165         assertEquals( "numbers.length", 3, numbers.length );
166         assertEquals( "numbers[0]", 3, numbers[0] );
167         assertEquals( "numbers[1]", 4, numbers[1] );
168         assertEquals( "numbers[2]", 5, numbers[2] );
169         
170         List locations = customer.getLocations();
171         assertTrue( "contains some locations", locations != null );
172         assertEquals( "locations.size()", 2, locations.size() );
173         assertEquals( "locations[0]", "London", locations.get(0) );
174         assertEquals( "locations[1]", "Bath", locations.get(1) );
175         
176         assertEquals( ConvertUtils.convert("2002-03-17", Date.class), customer.getDate());
177         assertEquals( ConvertUtils.convert("20:30:40", Time.class), customer.getTime());
178         assertEquals( ConvertUtils.convert("2002-03-17 20:30:40.0", Timestamp.class), customer.getTimestamp());
179 
180         assertEquals( new BigDecimal("1234567890.12345"), customer.getBigDecimal() );
181         assertEquals( new BigInteger("1234567890"), customer.getBigInteger() );
182     }
183     
184     protected InputStream getXMLInput() throws IOException {
185         return new FileInputStream( getTestFile("src/test/org/apache/commons/betwixt/customer.xml") );
186     }
187  
188     /*** 
189      * This tests that you can read a bean which has an adder but not a property
190      */ 
191     public void testAdderButNoProperty() throws Exception {
192         /*
193         // 
194         // This is a test for an unfixed issue that might - or might not - be a bug
195         // a developer submitted a patch but this broke the other unit test
196         // a proper fix would require quite a lot of work including some refactoring
197         // of various interfaces
198         //
199         
200         // check bean's still working
201         AdderButNoPropertyBean bean = new AdderButNoPropertyBean();
202         bean.addString("one");
203         bean.addString("two");
204         bean.addString("three");
205         checkBean(bean);
206         
207         BeanReader reader = new BeanReader();
208         reader.registerBeanClass( AdderButNoPropertyBean.class );
209         
210         InputStream in =  
211             new FileInputStream( getTestFile("src/test/org/apache/commons/betwixt/adder-np.xml") );
212         try {
213         
214             checkBean((AdderButNoPropertyBean) reader.parse( in ));
215             
216         }
217         finally {
218             in.close();
219         }        
220         */
221     }
222     
223     private void checkBean(AdderButNoPropertyBean bean) throws Exception {
224         assertEquals("Bad addString call count", 3, bean.stringCallCount());
225     }
226     
227     private void checkBean(PersonListBean bean) throws Exception {
228         assertEquals("PersonList size", 4, bean.getPersonList().size());
229         assertEquals("PersonList value (1)", "Athos", ((PersonBean) bean.getPersonList().get(0)).getName());
230         assertEquals("PersonList value (2)", "Porthos", ((PersonBean) bean.getPersonList().get(1)).getName());
231         assertEquals("PersonList value (3)", "Aramis", ((PersonBean) bean.getPersonList().get(2)).getName());
232         assertEquals("PersonList value (4)", "D'Artagnan", ((PersonBean) bean.getPersonList().get(3)).getName());
233     }
234     
235     public void testPersonList() throws Exception {
236 
237         PersonListBean people = new PersonListBean();
238         people.addPerson(new PersonBean(22, "Athos"));
239         people.addPerson(new PersonBean(25, "Porthos"));
240         people.addPerson(new PersonBean(23, "Aramis"));
241         people.addPerson(new PersonBean(18, "D'Artagnan"));
242         
243         checkBean(people);
244 //
245 // Logging and debugging code for this method commented out
246 //
247 //        writeBean(people);
248 
249 //        SimpleLog log = new SimpleLog("[TestPersonList:XMLIntrospectorHelper]");
250 //        log.setLevel(SimpleLog.LOG_LEVEL_TRACE);
251 //        XMLIntrospectorHelper.setLog(log);
252         
253         
254 //        log = new SimpleLog("[TestPersonList:BeanCreateRule]");
255 //        log.setLevel(SimpleLog.LOG_LEVEL_TRACE);
256 //        BeanCreateRule.setLog(log);
257         
258 //        log = new SimpleLog("[TestPersonList:XMLIntrospector]");
259 //        log.setLevel(SimpleLog.LOG_LEVEL_TRACE);
260         
261         BeanReader reader = new BeanReader();
262 //        reader.getXMLIntrospector().setLog(log);
263               
264 //        log = new SimpleLog("[TestPersonList:BeanReader]");
265 //        log.setLevel(SimpleLog.LOG_LEVEL_TRACE);
266         
267 //        reader.setLog(log);
268         reader.registerBeanClass( PersonListBean.class );
269         
270         InputStream in =  
271             new FileInputStream( getTestFile("src/test/org/apache/commons/betwixt/person-list.xml") );
272         try {
273         
274             checkBean((PersonListBean) reader.parse( in ));
275             
276         }
277         finally {
278             in.close();
279         }   
280     }
281     
282     /*** Another test for reading wrapped collections */
283     public void testWrapElements() throws Exception {
284         ListOfNames listOfNames = new ListOfNames();
285         listOfNames.addName( new NameBean("Martin") );
286         
287         String xml = "<ListOfNames><names><name name='Martin'/></names></ListOfNames>";
288         
289         BeanReader reader = new BeanReader();
290         reader.getXMLIntrospector().getConfiguration().setAttributesForPrimitives(true);
291         reader.getXMLIntrospector().getConfiguration().setWrapCollectionsInElement(true);
292         
293         reader.registerBeanClass(ListOfNames.class);
294         ListOfNames newListOfNames = (ListOfNames) reader.parse(new StringReader(xml));
295         
296         assertEquals("Wrapped collection read fails", listOfNames, newListOfNames);
297     }
298     
299     public void testSetDigesterRules() throws Exception {
300         NameBean martinBean = new NameBean("Martin");
301         ListOfNames listOfNames = new ListOfNames();
302         listOfNames.addName( martinBean );
303         
304         String xml = "<ListOfNames><names><name name='Martin'/></names></ListOfNames>";
305         
306         BeanReader reader = new BeanReader();
307         reader.setRules( new ExtendedBaseRules() );
308         reader.getXMLIntrospector().getConfiguration().setAttributesForPrimitives(true);
309         reader.getXMLIntrospector().getConfiguration().setWrapCollectionsInElement(true);
310         
311         TestRule ruleOne = new TestRule();
312         TestRule ruleTwo = new TestRule();
313         
314         // add a test rule before the bean rules
315         reader.addRule("!*/ListOfNames/names/name", ruleOne);
316         reader.registerBeanClass(ListOfNames.class);
317         // add a test rule after the bean rules
318         reader.addRule("!*/ListOfNames/names/name", ruleTwo);
319         
320         ListOfNames newListOfNames = (ListOfNames) reader.parse(new StringReader(xml));
321         
322         reader.parse(new StringReader(xml));
323         
324         // test that the rules were called
325         assertEquals("Rule one called", true , ruleOne.isCalled());
326         assertEquals("Rule two called", true , ruleTwo.isCalled());
327         
328         // test that the top objects are correct
329         assertEquals("Rule one digester top object", listOfNames , ruleOne.getTop());
330         assertEquals("Rule two digester top object", martinBean , ruleTwo.getTop());
331     }
332     
333     public void testDateReadConversion() throws Exception {
334         Calendar calendar = Calendar.getInstance();
335         calendar.set(2003, 7, 2, 19, 30, 00);
336         java.util.Date date = calendar.getTime();
337         
338         String dateToString = date.toString();
339         
340         PartyBean bean = new PartyBean(
341                 "Wedding",
342                 date,
343                 1930,
344                 new AddressBean("Old White Lion Hotel", "Howarth", "Merry Old England", "BD22 8EP"));
345 
346         StringWriter out = new StringWriter();
347         out.write("<?xml version='1.0'?>");
348         
349         BeanWriter writer = new BeanWriter(out);
350 		writer.getBindingConfiguration().setMapIDs(false);
351         XMLIntrospector introspector = writer.getXMLIntrospector();
352         introspector.getConfiguration().setElementNameMapper(new HyphenatedNameMapper());
353         introspector.getConfiguration().setAttributesForPrimitives(false);
354         
355         writer.write("party", bean);
356 
357         String xml = "<?xml version='1.0'?><party>"
358             + "<venue><street>Old White Lion Hotel</street><city>Howarth</city>"
359             + "<code>BD22 8EP</code><country>Merry Old England</country></venue>"
360             + "<date-of-party>" + dateToString 
361             + "</date-of-party><from-hour>1930</from-hour>"
362             + "<excuse>Wedding</excuse>"
363             + "</party>";
364         
365         xmlAssertIsomorphic(parseString(xml), parseString(out) , true);
366         
367         BeanReader reader = new BeanReader();
368         reader.setXMLIntrospector(introspector);
369         reader.registerBeanClass("party", PartyBean.class);
370         PartyBean readBean = (PartyBean) reader.parse(new StringReader(xml)); 
371         
372         assertEquals("FromHours incorrect property value", readBean.getFromHour(), bean.getFromHour());
373         assertEquals("Excuse incorrect property value", readBean.getExcuse(), bean.getExcuse());
374         
375         // check address
376         AddressBean readAddress = readBean.getVenue();
377         AddressBean address = bean.getVenue();
378         assertEquals("address.street incorrect property value", readAddress.getStreet(), address.getStreet());
379         assertEquals("address.city incorrect property value", readAddress.getCity(), address.getCity());
380         assertEquals("address.code incorrect property value", readAddress.getCode(), address.getCode());
381         assertEquals("address.country incorrect property value", readAddress.getCountry(), address.getCountry());
382         
383         // check dates
384         assertEquals("Incorrect date property", date.toGMTString(), readBean.getDateOfParty().toGMTString());  
385     }
386  
387     public void testHyphenatedNameMapping() throws Exception {
388         Calendar calendar = Calendar.getInstance();
389         calendar.set(2003, 7, 2, 19, 30, 00);
390         java.util.Date date = calendar.getTime();
391         
392         String dateToString = date.toString();
393         
394         PartyBean bean = new PartyBean(
395                 "Wedding",
396                 date,
397                 1930,
398                 new AddressBean("Old White Lion Hotel", "Howarth", "Merry Old England", "BD22 8EP"));
399 
400         StringWriter out = new StringWriter();
401         out.write("<?xml version='1.0'?>");
402         
403         BeanWriter writer = new BeanWriter(out);
404 		writer.getBindingConfiguration().setMapIDs(false);
405         XMLIntrospector introspector = writer.getXMLIntrospector();
406         introspector.getConfiguration().setElementNameMapper(new HyphenatedNameMapper());
407         introspector.getConfiguration().setAttributesForPrimitives(false);
408         
409         writer.write(bean);
410         
411         String xml = "<?xml version='1.0'?><party-bean>"
412             + "<venue><street>Old White Lion Hotel</street><city>Howarth</city>"
413             + "<code>BD22 8EP</code><country>Merry Old England</country></venue>"
414             + "<date-of-party>" + dateToString 
415             + "</date-of-party><from-hour>1930</from-hour>"
416             + "<excuse>Wedding</excuse>"
417             + "</party-bean>";
418         
419         xmlAssertIsomorphic(parseString(xml), parseString(out) , true);
420         
421         BeanReader reader = new BeanReader();
422         reader.setXMLIntrospector(introspector);
423         reader.registerBeanClass(PartyBean.class);
424         PartyBean readBean = (PartyBean) reader.parse(new StringReader(xml)); 
425         
426         assertEquals("FromHours incorrect property value", readBean.getFromHour(), bean.getFromHour());
427         assertEquals("Excuse incorrect property value", readBean.getExcuse(), bean.getExcuse());
428         
429         // check address
430         AddressBean readAddress = readBean.getVenue();
431         AddressBean address = bean.getVenue();
432         assertEquals("address.street incorrect property value", readAddress.getStreet(), address.getStreet());
433         assertEquals("address.city incorrect property value", readAddress.getCity(), address.getCity());
434         assertEquals("address.code incorrect property value", readAddress.getCode(), address.getCode());
435         assertEquals("address.country incorrect property value", readAddress.getCountry(), address.getCountry());
436         
437         // check dates
438         assertEquals("Incorrect date property", date.toGMTString(), readBean.getDateOfParty().toGMTString());  
439         
440     }
441  
442     public void testCustomDateReadConversion() throws Exception {
443     
444         BindingConfiguration configuration = new BindingConfiguration(
445                                             new ConvertUtilsObjectStringConverter(),false);
446     
447         //SimpleLog log = new SimpleLog("testDateReadConversion:MethodUpdater");
448         //log.setLevel(SimpleLog.LOG_LEVEL_TRACE);
449         //MethodUpdater.setLog(log);
450    
451         class ISOToStringConverter implements Converter {
452             final SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMdd");
453             public Object convert(Class type, Object value) {
454                 if (value == null) {
455                     return null;
456                 }
457                 if (value instanceof java.util.Date) {
458                     return formatter.format((java.util.Date)value);
459                 }
460                 return value.toString();
461             }
462         }
463      
464         class ISODateConverter implements Converter {
465             final SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMdd");
466             public Object convert(Class type, Object value) {
467 
468                 if (value == null) {
469                     return null;
470                 }
471                 
472                 if (value instanceof java.util.Date) {
473 
474                     return formatter.format((java.util.Date)value);
475                 }
476                 
477                 try {
478                     return formatter.parse(value.toString());
479                 } catch (ParseException ex) {
480                     throw new ConversionException(ex);
481                 }
482             }
483         }
484         
485         ISODateConverter converter = new ISODateConverter();
486         ConvertUtils.register(converter, java.util.Date.class);
487         ISOToStringConverter tsConverter = new ISOToStringConverter();
488         ConvertUtils.register(tsConverter, String.class);
489         
490         Converter dateConverter = ConvertUtils.lookup(java.util.Date.class);
491         assertEquals("Date converter successfully registered", dateConverter, converter);
492         Converter stringConverter = ConvertUtils.lookup(String.class);
493         assertEquals("Date converter successfully registered", tsConverter, stringConverter);
494         
495         java.util.Date conversionResult = (java.util.Date)
496                                 ConvertUtils.convert("20030101", java.util.Date.class);
497         
498         Calendar calendar = Calendar.getInstance();
499         calendar.setTime(conversionResult);
500         int dayOfYear = calendar.get(Calendar.DAY_OF_YEAR);
501         assertEquals("Correct conversion result", dayOfYear, 1);
502         
503         calendar.set(2003, 7, 2);
504         java.util.Date date = calendar.getTime();
505         
506         PartyBean bean = new PartyBean(
507                 "Wedding",
508                 date,
509                 1900,
510                 new AddressBean("Old White Lion Hotel", "Howarth", "Merry Old England", "BD22 8EP"));
511 
512         StringWriter out = new StringWriter();
513         out.write("<?xml version='1.0'?>");
514         
515         BeanWriter writer = new BeanWriter(out);
516         writer.setBindingConfiguration(configuration);
517         XMLIntrospector introspector = writer.getXMLIntrospector();
518         introspector.getConfiguration().setElementNameMapper(new HyphenatedNameMapper());
519         introspector.getConfiguration().setAttributesForPrimitives(false);
520         
521         writer.write("party", bean);
522 
523         String xml = "<?xml version='1.0'?><party>"
524             + "<venue><street>Old White Lion Hotel</street><city>Howarth</city>"
525             + "<code>BD22 8EP</code><country>Merry Old England</country></venue>"
526             + "<date-of-party>20030802</date-of-party><from-hour>1900</from-hour>"
527             + "<excuse>Wedding</excuse>"
528             + "</party>";
529         
530         xmlAssertIsomorphic(parseString(xml), parseString(out) , true);
531         
532         BeanReader reader = new BeanReader();
533         reader.setBindingConfiguration(configuration);
534         reader.setXMLIntrospector(introspector);
535         reader.registerBeanClass("party", PartyBean.class);
536         PartyBean readBean = (PartyBean) reader.parse(new StringReader(xml)); 
537         
538         assertEquals("FromHours incorrect property value", readBean.getFromHour(), bean.getFromHour());
539         assertEquals("Excuse incorrect property value", readBean.getExcuse(), bean.getExcuse());
540         
541         // check address
542         AddressBean readAddress = readBean.getVenue();
543         AddressBean address = bean.getVenue();
544         assertEquals("address.street incorrect property value", readAddress.getStreet(), address.getStreet());
545         assertEquals("address.city incorrect property value", readAddress.getCity(), address.getCity());
546         assertEquals("address.code incorrect property value", readAddress.getCode(), address.getCode());
547         assertEquals("address.country incorrect property value", readAddress.getCountry(), address.getCountry());
548         
549         // check dates
550         calendar.setTime(bean.getDateOfParty());
551         calendar.set(Calendar.HOUR_OF_DAY, 0);
552         dayOfYear = calendar.get(Calendar.DAY_OF_YEAR);
553         int year = calendar.get(Calendar.YEAR);
554         calendar.setTime(readBean.getDateOfParty());
555         calendar.set(Calendar.HOUR_OF_DAY, 0);
556         int readDayOfYear = calendar.get(Calendar.DAY_OF_YEAR);    
557         int readYear = calendar.get(Calendar.YEAR); 
558         assertEquals("date incorrect property value (year)", year, readYear); 
559         assertEquals("date incorrect property value (day)", dayOfYear, readDayOfYear);   
560         
561         ConvertUtils.deregister();
562     }
563 
564     
565     public void testReadMap() throws Exception {
566         // we might as well start by writing out 
567         MapBean bean = new MapBean("drinkers");
568         bean.addAddress(
569                 "Russell McManus", 
570                 new AddressBean("6, Westgate","Shipley", "United Kingdom", "BD17 5EJ"));
571         bean.addAddress(
572                 "Alex Compbell", 
573                 new AddressBean("5, Kirkgate","Shipley", "United Kingdom", "BD18 3QW"));
574         bean.addAddress(
575                 "Sid Gardner", 
576                 new AddressBean("Old House At Home, Otley Road","Shipley", "United Kingdom", "BD18 2BJ"));
577                 
578         StringWriter out = new StringWriter();
579         out.write("<?xml version='1.0'?>");
580         BeanWriter writer = new BeanWriter(out);
581         writer.getBindingConfiguration().setMapIDs(false);
582         writer.write("address-book", bean);
583         
584         String xml = "<?xml version='1.0'?><address-book><title>drinkers</title>"
585             + "<addresses>"
586             + "<entry><key>Alex Compbell</key><value><country>United Kingdom</country>"
587             + "<code>BD18 3QW</code><city>Shipley</city><street>5, Kirkgate</street></value></entry>"
588             + "<entry><key>Russell McManus</key><value><country>United Kingdom</country><code>BD17 5EJ</code>"
589             + "<city>Shipley</city><street>6, Westgate</street></value></entry>"
590             + "<entry><key>Sid Gardner</key><value><country>United Kingdom</country>"
591             + "<code>BD18 2BJ</code><city>Shipley</city><street>Old House At Home, Otley Road</street>"
592             + "</value></entry>"
593             + "</addresses></address-book>";
594         
595         xmlAssertIsomorphic(parseString(out.toString()), parseString(xml), true);
596         
597 //        SimpleLog log = new SimpleLog("[testReadMap:BeanRuleSet]");
598 //        log.setLevel(SimpleLog.LOG_LEVEL_TRACE);
599 //        BeanRuleSet.setLog(log);
600 //        log = new SimpleLog("[testReadMap:XMLIntrospectorHelper]");
601 //        log.setLevel(SimpleLog.LOG_LEVEL_TRACE);
602 //        XMLIntrospectorHelper.setLog(log);
603 //        log = new SimpleLog("[testReadMap:MapEntryAdder]");
604 //        log.setLevel(SimpleLog.LOG_LEVEL_TRACE);
605 //        MapEntryAdder.setLog(log);
606 
607         BeanReader reader = new BeanReader();
608 
609 //        log = new SimpleLog("[testReadMap:BeanReader]");
610 //        log.setLevel(SimpleLog.LOG_LEVEL_TRACE);
611 //        reader.setLog(log);
612 //        log = new SimpleLog("[testReadMap:XMLIntrospector]");
613 //        log.setLevel(SimpleLog.LOG_LEVEL_TRACE);
614 //        reader.getXMLIntrospector().setLog(log);
615 
616         reader.getBindingConfiguration().setMapIDs(false);
617         reader.registerBeanClass("address-book", MapBean.class);
618         bean = (MapBean) reader.parse(new StringReader(xml));
619         
620         assertEquals("Title property is incorrect", "drinkers", bean.getTitle());
621         assertEquals("Map entries", 3, bean.getAddresses().size());
622         
623         AddressBean address = (AddressBean) bean.getAddresses().get("Russell McManus");
624         assertNotNull("Missing entry for 'Russell McManus'", address);
625         assertEquals("Bad address (1)", "6, Westgate", address.getStreet());
626         assertEquals("Bad address (2)", "Shipley", address.getCity());
627         assertEquals("Bad address (3)",  "United Kingdom", address.getCountry());
628         assertEquals("Bad address (4)", "BD17 5EJ", address.getCode());
629                     
630         address = (AddressBean) bean.getAddresses().get("Alex Compbell");
631         assertNotNull("Missing entry for 'Alex Compbell'", address);
632         assertEquals("Bad address (5)", "5, Kirkgate", address.getStreet());
633         assertEquals("Bad address (6)", "Shipley", address.getCity());
634         assertEquals("Bad address (7)",  "United Kingdom", address.getCountry());
635         assertEquals("Bad address (8)", "BD18 3QW", address.getCode());
636          
637         address = (AddressBean) bean.getAddresses().get("Sid Gardner");
638         assertNotNull("Missing entry for 'Sid Gardner'", address);
639         assertEquals("Bad address (9)", "Old House At Home, Otley Road", address.getStreet());
640         assertEquals("Bad address (10)", "Shipley", address.getCity());
641         assertEquals("Bad address (11)",  "United Kingdom", address.getCountry());
642         assertEquals("Bad address (12)", "BD18 2BJ", address.getCode());
643     }
644 
645   public void testReadMap2() throws Exception{
646     IdMap idMap = new IdMap();
647     String id ="3920";
648     idMap.addId(id, new Integer(1));
649     StringWriter outputWriter = new StringWriter();
650     outputWriter.write("<?xml version='1.0' ?>\n");
651     BeanWriter beanWriter = new BeanWriter(outputWriter);
652     beanWriter.write(idMap);
653     String xml = outputWriter.toString();
654     System.out.println("Map test: " + xml);
655 
656     BeanReader beanReader = new BeanReader();
657     beanReader.registerBeanClass(IdMap.class);
658     IdMap result = (IdMap)beanReader.parse(new StringReader(xml));
659     assertNotNull("didn't get an object back!", result);
660     assertNotNull("didn't get a Map out of the IdMap!", result.getIds());
661     assertEquals("Got the Map, but doesn't have an entry!", 1, result.getIds().size());
662     assertNotNull("Got the Map, but doesn't have correct values!", result.getIds().get(id));
663   }
664 
665     public void testIndirectReference() throws Exception
666     {	
667         Tweedledum dum = new Tweedledum();
668         Tweedledee dee = new Tweedledee(dum);
669         StringWriter out = new StringWriter();
670         out.write("<?xml version='1.0'?>");
671         BeanWriter writer = new BeanWriter(out);
672         writer.getBindingConfiguration().setMapIDs(false);
673         writer.write(dee);
674         String xml =  "<?xml version='1.0'?><Tweedledee><name>Tweedledee</name>"
675                     + "<brother><name>Tweedledum</name></brother></Tweedledee>";
676         xmlAssertIsomorphic(parseString(xml), parseString(out) , true);
677 
678         BeanReader reader = new BeanReader();
679         
680         reader.getBindingConfiguration().setMapIDs(false);
681         reader.registerBeanClass(Tweedledee.class);
682         Tweedledee bean = (Tweedledee) reader.parse(new StringReader(xml));
683         assertNotNull(bean.getBrother());
684     }
685     
686     public void _testDoubleLinkedCollectionRead() throws Exception
687     {
688         String xml =  "<?xml version='1.0'?><DOUBLE_LINKED_PARENT_BEAN>"
689                     + "<NAME>Cronus</NAME>"
690                     + "<CHILDREN>"
691                     + "<CHILD><NAME>Hades</NAME></CHILD>"
692                     + "<CHILD><NAME>Hera</NAME></CHILD>"
693                     + "<CHILD><NAME>Hestia</NAME></CHILD>"
694                     + "<CHILD><NAME>Demeter</NAME></CHILD>"
695                     + "<CHILD><NAME>Poseidon</NAME></CHILD>"
696                     + "<CHILD><NAME>Zeus</NAME></CHILD>"
697                     + "</CHILDREN></DOUBLE_LINKED_PARENT_BEAN>";
698                     
699         BeanReader reader = new BeanReader();
700         reader.getXMLIntrospector().getConfiguration().setElementNameMapper(new HyphenatedNameMapper(true, "_"));
701         reader.registerBeanClass(DoubleLinkedParentBean.class);
702         DoubleLinkedParentBean bean = (DoubleLinkedParentBean) reader.parse(new StringReader(xml));
703         
704         assertNotNull("Bean read", bean);
705         assertEquals("Cronus", "Parent name", bean.getName());
706         assertEquals("Number of children", 6, bean.getSize());
707         
708         ArrayList list = new ArrayList();
709         for (Iterator it=bean.getChildren();it.hasNext();) {
710             list.add(it.next());
711         }
712         
713         DoubleLinkedChildBean childZero = (DoubleLinkedChildBean) list.get(0);
714         DoubleLinkedChildBean childOne = (DoubleLinkedChildBean) list.get(1);
715         DoubleLinkedChildBean childTwo = (DoubleLinkedChildBean) list.get(2);
716         DoubleLinkedChildBean childThree = (DoubleLinkedChildBean) list.get(3);
717         DoubleLinkedChildBean childFour = (DoubleLinkedChildBean) list.get(4);
718         DoubleLinkedChildBean childFive = (DoubleLinkedChildBean) list.get(5);
719  
720         assertEquals("Child name zero", "Hades", childZero.getName());
721         assertEquals("Child name one", "Hera", childZero.getName());
722         assertEquals("Child name two", "Hestia", childZero.getName());
723         assertEquals("Child name three", "Demeter", childZero.getName());
724         assertEquals("Child name four", "Poseidon", childZero.getName());
725         assertEquals("Child name five", "Zeus", childZero.getName());
726         
727     }
728     
729     /*** 
730       * This is a member class since all classes starting with test 
731       * will be run as test cases.
732       */
733     private class TestRule extends Rule {
734         
735         private String name;
736         private boolean called = false;
737         private Object top;
738         
739         public Object getTop() {
740             return top;
741         }
742         
743         public String getName() {
744             return name;
745         }
746         
747         public void setName(String name) {
748             this.name = name;
749         }	
750         
751         public boolean isCalled() {
752             return called;
753         }
754         
755         public void begin(String name, String namespace, Attributes attributes) {
756             top = getDigester().peek();
757             called = true;
758         }
759     }
760 }
761