1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    * 
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   * 
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */ 
17  package org.apache.commons.betwixt;
18  
19  
20  import java.beans.IntrospectionException;
21  import java.io.IOException;
22  import java.io.StringReader;
23  import java.io.StringWriter;
24  import java.util.ArrayList;
25  import java.util.Iterator;
26  import java.util.List;
27  
28  import org.apache.commons.betwixt.io.BeanReader;
29  import org.apache.commons.betwixt.io.BeanWriter;
30  import org.xml.sax.InputSource;
31  import org.xml.sax.SAXException;
32  
33  /**
34   * Tests the multi-mapping of collections with polymorphic entries.
35   * 
36   * @author Thomas Dudziak (tomdz@apache.org)
37   */
38  public class TestMultipleCollectionMappings extends AbstractTestCase
39  {
40      public static class Container
41      {
42          private List _elements = new ArrayList();
43          private List _nodes    = new ArrayList();
44  
45          public Iterator getElements()
46          {
47              return _elements.iterator();
48          }
49  
50          public void addElement(Element element)
51          {
52              _elements.add(element);
53          }
54  
55          public Iterator getNodes()
56          {
57              return _nodes.iterator();
58          }
59  
60          public void addNode(Node1 node)
61          {
62              _nodes.add(node);
63          }
64      }
65  
66      public static interface Element
67      {}
68  
69      public static class ElementA implements Element
70      {}
71  
72      public static class ElementB implements Element
73      {}
74  
75      public static class ElementC
76      {}
77  
78      public static class Node1
79      {
80          private String name;
81  
82          public String getName()
83          {
84              return name;
85          }
86  
87          public void setName(String name)
88          {
89              this.name = name;
90          }
91      }
92  
93      public static class Node2 extends Node1
94      {
95          private String name;
96  
97          public String getName()
98          {
99              return name;
100         }
101 
102         public void setName(String name)
103         {
104             this.name = name;
105         }
106     }
107 
108     public static class Node3
109     {
110         private List _innerNodes = new ArrayList();
111 
112         public Iterator getInnerNodes()
113         {
114             return _innerNodes.iterator();
115         }
116 
117         public void addInnerNode(InnerNode node)
118         {
119             _innerNodes.add(node);
120         }
121     }
122 
123     public static class InnerNode
124     {}
125 
126     private static final String MAPPING =
127         "<?xml version=\"1.0\"?>\n"+
128         "<betwixt-config>\n"+
129         "  <class name=\""+Container.class.getName()+"\">\n"+
130         "    <element name=\"container\">\n"+
131         "      <element property=\"elements\" updater=\"addElement\"/>\n"+
132         "      <element property=\"nodes\"    updater=\"addNode\"/>\n"+
133         "    </element>\n"+
134         "  </class>\n"+
135         "  <class name=\""+ElementA.class.getName()+"\">\n"+
136         "    <element name=\"elementA\"/>\n"+
137         "  </class>\n"+
138         "  <class name=\""+ElementB.class.getName()+"\">\n"+
139         "    <element name=\"elementB\"/>\n"+
140         "  </class>\n"+
141         "  <class name=\""+ElementC.class.getName()+"\">\n"+
142         "    <element name=\"elementC\"/>\n"+
143         "  </class>\n"+
144         "  <class name=\""+Node1.class.getName()+"\">\n"+
145         "    <element name=\"node1\">\n"+
146         "      <attribute name=\"name\" property=\"name\"/>\n"+
147         "    </element>\n"+
148         "  </class>\n"+
149         "  <class name=\""+Node2.class.getName()+"\">\n"+
150         "    <element name=\"node2\">\n"+
151         "      <attribute name=\"name\" property=\"name\"/>\n"+
152         "    </element>\n"+
153         "  </class>\n"+
154         "  <class name=\""+Node3.class.getName()+"\">\n"+
155         "    <element name=\"node2\">\n"+
156         "      <attribute name=\"name\" property=\"name\"/>\n"+
157         "      <element property=\"innerNodes\" updater=\"addInnerNode\"/>\n"+
158         "    </element>\n"+
159         "  </class>\n"+
160         "  <class name=\""+InnerNode.class.getName()+"\">\n"+
161         "    <element name=\"innerNode\"/>\n"+
162         "  </class>\n"+
163         "</betwixt-config>";
164     private static final String EXPECTED1 =
165         "<?xml version=\"1.0\" ?>\n"+
166         "  <container>\n"+
167         "    <elementB/>\n"+
168         "    <elementA/>\n"+
169         "  </container>\n";
170     private static final String EXPECTED2 =
171         "<?xml version=\"1.0\" ?>\n"+
172         "  <container>\n"+
173         "    <node1/>\n"+
174         "    <node2/>\n"+
175         "    <node2/>\n"+
176         "  </container>\n";
177     private static final String EXPECTED3 =
178         "<?xml version=\"1.0\" ?>\n"+
179         "  <container>\n"+
180         "    <elementA/>\n"+
181         "    <elementB/>\n"+
182         "    <node2/>\n"+
183         "    <node1/>\n"+
184         "    <node2/>\n"+
185         "  </container>\n";
186     private static final String INVALID_XML =
187         "<?xml version=\"1.0\" ?>\n"+
188         "  <container>\n"+
189         "    <elementA/>\n"+
190         "    <elementC/>\n"+
191         "    <node3 name=\"test\"/>\n"+
192         "    <innerNode/>\n"+
193         "  </container>\n";
194     
195     public TestMultipleCollectionMappings(String testName)
196     {
197         super(testName);
198     }
199 
200     public void testOnlyElements() throws IOException, SAXException, IntrospectionException
201     {
202         Container container = new Container();
203 
204         container.addElement(new ElementB());
205         container.addElement(new ElementA());
206 
207         StringWriter outputWriter = new StringWriter();
208 
209         outputWriter.write("<?xml version=\"1.0\" ?>\n");
210 
211         BeanWriter beanWriter = new BeanWriter(outputWriter);
212         beanWriter.setEndOfLine("\n");
213         beanWriter.enablePrettyPrint();
214         beanWriter.setWriteEmptyElements(true);
215         beanWriter.getBindingConfiguration().setMapIDs(false);
216         beanWriter.getXMLIntrospector().register(new InputSource(new StringReader(MAPPING)));
217         beanWriter.setEndOfLine("\n"); //force to \n so expected values match for sure
218         beanWriter.write(container);
219 
220         String output = outputWriter.toString();
221 
222         assertEquals(EXPECTED1, output);
223             
224         BeanReader beanReader = new BeanReader();
225 
226         beanReader.registerMultiMapping(new InputSource(new StringReader(MAPPING)));
227 
228         StringReader xmlReader = new StringReader(output);
229 
230         container = (Container)beanReader.parse(xmlReader);
231 
232         Iterator it = container.getElements();
233 
234         assertTrue(it.next() instanceof ElementB);
235         assertTrue(it.next() instanceof ElementA);
236         assertFalse(it.hasNext());
237 
238         assertFalse(container.getNodes().hasNext());
239     }
240     
241     public void testOnlyNodes() throws IOException, SAXException, IntrospectionException
242     {
243         Container container = new Container();
244 
245         container.addNode(new Node1());
246         container.addNode(new Node2());
247         container.addNode(new Node2());
248 
249         StringWriter outputWriter = new StringWriter();
250 
251         outputWriter.write("<?xml version=\"1.0\" ?>\n");
252 
253         BeanWriter beanWriter = new BeanWriter(outputWriter);
254         beanWriter.setEndOfLine("\n");
255         beanWriter.enablePrettyPrint();
256         beanWriter.setWriteEmptyElements(true);
257         beanWriter.getBindingConfiguration().setMapIDs(false);
258         beanWriter.getXMLIntrospector().register(new InputSource(new StringReader(MAPPING)));
259         beanWriter.setEndOfLine("\n"); //force to \n so expected values match for sure
260         beanWriter.write(container);
261 
262         String output = outputWriter.toString();
263 
264         assertEquals(EXPECTED2, output);
265             
266         BeanReader beanReader = new BeanReader();
267 
268         beanReader.registerMultiMapping(new InputSource(new StringReader(MAPPING)));
269 
270         StringReader xmlReader = new StringReader(output);
271 
272         container = (Container)beanReader.parse(xmlReader);
273 
274         assertFalse(container.getElements().hasNext());
275 
276         Iterator it = container.getNodes();
277 
278         assertTrue(it.next() instanceof Node1);
279         assertTrue(it.next() instanceof Node2);
280         assertTrue(it.next() instanceof Node2);
281         assertFalse(it.hasNext());
282     }
283 
284     public void testMixed() throws IOException, SAXException, IntrospectionException
285     {
286         Container container = new Container();
287 
288         container.addNode(new Node2());
289         container.addNode(new Node1());
290         container.addNode(new Node2());
291         container.addElement(new ElementA());
292         container.addElement(new ElementB());
293 
294         StringWriter outputWriter = new StringWriter();
295 
296         outputWriter.write("<?xml version=\"1.0\" ?>\n");
297 
298         BeanWriter beanWriter = new BeanWriter(outputWriter);
299         beanWriter.setEndOfLine("\n");
300         beanWriter.enablePrettyPrint();
301         beanWriter.setWriteEmptyElements(true);
302         beanWriter.getBindingConfiguration().setMapIDs(false);
303         beanWriter.getXMLIntrospector().register(new InputSource(new StringReader(MAPPING)));
304         beanWriter.setEndOfLine("\n"); //force to \n so expected values match for sure
305         beanWriter.write(container);
306 
307         String output = outputWriter.toString();
308 
309         assertEquals(EXPECTED3, output);
310             
311         BeanReader beanReader = new BeanReader();
312 
313         beanReader.registerMultiMapping(new InputSource(new StringReader(MAPPING)));
314 
315         StringReader xmlReader = new StringReader(output);
316 
317         container = (Container)beanReader.parse(xmlReader);
318 
319         Iterator it = container.getElements();
320 
321         assertTrue(it.next() instanceof ElementA);
322         assertTrue(it.next() instanceof ElementB);
323         assertFalse(it.hasNext());
324 
325         it = container.getNodes();
326 
327         assertTrue(it.next() instanceof Node2);
328         assertTrue(it.next() instanceof Node1);
329         assertTrue(it.next() instanceof Node2);
330         assertFalse(it.hasNext());
331 
332     }
333 
334     public void testInvalidXML() throws IOException, SAXException, IntrospectionException
335     {
336         BeanReader beanReader = new BeanReader();
337 
338         beanReader.registerMultiMapping(new InputSource(new StringReader(MAPPING)));
339 
340         StringReader xmlReader = new StringReader(INVALID_XML);
341         Container    container = (Container)beanReader.parse(xmlReader);
342         Iterator     it        = container.getElements();
343 
344         assertTrue(it.next() instanceof ElementA);
345         assertFalse(it.hasNext());
346 
347         it = container.getNodes();
348 
349         assertFalse(it.hasNext());
350     }
351 }