View Javadoc

1   /* $Id: FromXmlRuleSetTest.java 1127922 2011-05-26 14:03:41Z simonetripodi $
2    *
3    * Licensed to the Apache Software Foundation (ASF) under one or more
4    * contributor license agreements.  See the NOTICE file distributed with
5    * this work for additional information regarding copyright ownership.
6    * The ASF licenses this file to You under the Apache License, Version 2.0
7    * (the "License"); you may not use this file except in compliance with
8    * the License.  You may obtain a copy of the License at
9    *
10   *      http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  
19  package org.apache.commons.digester3.xmlrules;
20  
21  import static org.apache.commons.digester3.binder.DigesterLoader.newLoader;
22  import static org.junit.Assert.assertEquals;
23  import static org.junit.Assert.assertTrue;
24  import static org.junit.Assert.fail;
25  
26  import java.io.InputStream;
27  import java.io.StringReader;
28  import java.net.URL;
29  import java.util.ArrayList;
30  
31  import org.apache.commons.digester3.Address;
32  import org.apache.commons.digester3.Digester;
33  import org.apache.commons.digester3.ObjectCreationFactoryTestImpl;
34  import org.apache.commons.digester3.binder.RulesModule;
35  import org.junit.Test;
36  import org.xml.sax.InputSource;
37  
38  /**
39   * Tests loading Digester rules from an XML file.
40   */
41  
42  public class FromXmlRuleSetTest
43  {
44  
45      private final RulesModule createRules( final URL xmlRules )
46      {
47          return new FromXmlRulesModule()
48          {
49  
50              @Override
51              protected void loadRules()
52              {
53                  loadXMLRules( xmlRules );
54              }
55  
56          };
57      }
58  
59      private final RulesModule createRules( final String xmlText )
60      {
61          return new FromXmlRulesModule()
62          {
63  
64              @Override
65              protected void loadRules()
66              {
67                  loadXMLRulesFromText( xmlText );
68              }
69  
70          };
71      }
72  
73      /**
74       * Tests the DigesterLoader.createDigester(), with multiple
75       * included rule sources: testrules.xml includes another rules xml
76       * file, and also includes programmatically created rules.
77       */
78      @Test
79      public void testCreateDigester()
80          throws Exception
81      {
82          URL rules = getClass().getResource( "testrules.xml" );
83          URL input = getClass().getResource( "test.xml" );
84  
85          Digester digester = newLoader( createRules( rules ) ).newDigester();
86          digester.push( new ArrayList<Object>() );
87          Object root = digester.parse( input.openStream() );
88          assertEquals( "[foo1 baz1 foo2, foo3 foo4]", root.toString() );
89      }
90  
91      /**
92       * Tests the DigesterLoader.load(), with multiple included rule
93       * sources: testrules.xml includes another rules xml file, and
94       * also includes programmatically created rules.
95       */
96      @Test
97      public void testLoad1()
98          throws Exception
99      {
100         ClassLoader classLoader = getClass().getClassLoader();
101         URL rules = getClass().getResource( "testrules.xml" );
102         URL input = getClass().getResource( "test.xml" );
103 
104         Digester digester = newLoader( createRules( rules ) ).setClassLoader( classLoader ).newDigester();
105         digester.push( new ArrayList<Object>() );
106 
107         Object root = digester.parse( input );
108         if ( !( root instanceof ArrayList<?> ) )
109         {
110             fail( "Unexpected object returned from DigesterLoader. Expected ArrayList; got "
111                 + root.getClass().getName() );
112         }
113         assertEquals( "[foo1 baz1 foo2, foo3 foo4]", root.toString() );
114 
115         @SuppressWarnings( "unchecked" )
116         // root is an ArrayList
117         ArrayList<Object> al = (ArrayList<Object>) root;
118         Object obj = al.get( 0 );
119         if ( !( obj instanceof ObjectTestImpl ) )
120         {
121             fail( "Unexpected object returned from DigesterLoader. Expected TestObject; got "
122                 + obj.getClass().getName() );
123         }
124         ObjectTestImpl to = (ObjectTestImpl) obj;
125         assertEquals( new Long( 555 ), to.getLongValue() );
126         assertEquals( "foo", to.getMapValue( "test1" ) );
127         assertEquals( "bar", to.getMapValue( "test2" ) );
128     }
129 
130     /**
131      * The same as testLoad1, exception the input file is passed to
132      * DigesterLoader as an InputStream instead of a URL.
133      */
134     @Test
135     public void testLoad2()
136         throws Exception
137     {
138         URL rules = getClass().getResource( "testrules.xml" );
139         InputStream input = getClass().getResourceAsStream( "test.xml" );
140         Digester digester =
141             newLoader( createRules( rules ) ).setClassLoader( this.getClass().getClassLoader() ).newDigester();
142         digester.push( new ArrayList<Object>() );
143 
144         ArrayList<Object> list = digester.parse( input );
145 
146         assertEquals( list.toString(), "[foo1 baz1 foo2, foo3 foo4]" );
147         assertEquals( "Wrong number of classes created", 2, list.size() );
148         assertEquals( "Pushed first", true, ( (ObjectTestImpl) list.get( 0 ) ).isPushed() );
149         assertEquals( "Didn't push second", false, ( (ObjectTestImpl) list.get( 1 ) ).isPushed() );
150         assertTrue( "Property was set properly",
151                     ( (ObjectTestImpl) list.get( 0 ) ).getProperty().equals( "I am a property!" ) );
152     }
153 
154     /**
155      */
156     @Test
157     public void testSetCustomProperties()
158         throws Exception
159     {
160         URL rules = this.getClass().getResource( "testPropertyAliasRules.xml" );
161         InputStream input =
162             getClass().getClassLoader().getResource( "org/apache/commons/digester3/Test7.xml" ).openStream();
163 
164         Digester digester =
165             newLoader( createRules( rules ) ).setClassLoader( this.getClass().getClassLoader() ).newDigester();
166         digester.push( new ArrayList<Object>() );
167 
168         Object obj = digester.parse( input );
169 
170         if ( !( obj instanceof ArrayList<?> ) )
171         {
172             fail( "Unexpected object returned from DigesterLoader. Expected ArrayList; got " + obj.getClass().getName() );
173         }
174 
175         @SuppressWarnings("unchecked") // root is an ArrayList of Address
176         ArrayList<Address> root = (ArrayList<Address>) obj;
177 
178         assertEquals( "Wrong array size", 4, root.size() );
179 
180         // note that the array is in popped order (rather than pushed)
181 
182         Address add = root.get( 0 );
183         Address addressOne = add;
184         assertEquals( "(1) Street attribute", "New Street", addressOne.getStreet() );
185         assertEquals( "(1) City attribute", "Las Vegas", addressOne.getCity() );
186         assertEquals( "(1) State attribute", "Nevada", addressOne.getState() );
187 
188         add = root.get( 1 );
189         Address addressTwo = add;
190         assertEquals( "(2) Street attribute", "Old Street", addressTwo.getStreet() );
191         assertEquals( "(2) City attribute", "Portland", addressTwo.getCity() );
192         assertEquals( "(2) State attribute", "Oregon", addressTwo.getState() );
193 
194         add = root.get( 2 );
195         Address addressThree = add;
196         assertEquals( "(3) Street attribute", "4th Street", addressThree.getStreet() );
197         assertEquals( "(3) City attribute", "Dayton", addressThree.getCity() );
198         assertEquals( "(3) State attribute", "US", addressThree.getState() );
199 
200         add = root.get( 3 );
201         Address addressFour = add;
202         assertEquals( "(4) Street attribute", "6th Street", addressFour.getStreet() );
203         assertEquals( "(4) City attribute", "Cleveland", addressFour.getCity() );
204         assertEquals( "(4) State attribute", "Ohio", addressFour.getState() );
205     }
206 
207     @Test
208     public void testFactoryCreateRule()
209         throws Exception
210     {
211         URL rules = getClass().getResource( "testfactory.xml" );
212         String xml = "<?xml version='1.0' ?><root one='good' two='bad' three='ugly'><foo/></root>";
213 
214         Digester digester =
215             newLoader( createRules( rules ) ).setClassLoader( this.getClass().getClassLoader() ).newDigester();
216         digester.push( new ArrayList<ObjectCreationFactoryTestImpl>() );
217 
218         Object obj = digester.parse( new StringReader( xml ) );
219         if ( !( obj instanceof ArrayList<?> ) )
220         {
221             fail( "Unexpected object returned from DigesterLoader. Expected ArrayList; got " + obj.getClass().getName() );
222         }
223 
224         @SuppressWarnings("unchecked") // root is an ArrayList of TestObjectCreationFactory
225         ArrayList<ObjectCreationFactoryTestImpl> list = (ArrayList<ObjectCreationFactoryTestImpl>) obj;
226 
227         assertEquals( "List should contain only the factory object", list.size(), 1 );
228         ObjectCreationFactoryTestImpl factory = list.get( 0 );
229         assertEquals( "Object create not called(1)", factory.called, true );
230         assertEquals( "Attribute not passed (1)", factory.attributes.getValue( "one" ), "good" );
231         assertEquals( "Attribute not passed (2)", factory.attributes.getValue( "two" ), "bad" );
232         assertEquals( "Attribute not passed (3)", factory.attributes.getValue( "three" ), "ugly" );
233     }
234 
235     @Test
236     public void testFactoryIgnoreCreateRule()
237         throws Exception
238     {
239         URL rules = getClass().getResource( "testfactoryignore.xml" );
240 
241         String xml = "<?xml version='1.0' ?><root one='good' two='bad' three='ugly'><foo/></root>";
242         try {
243             newLoader(createRules(rules)).newDigester().parse(new StringReader(xml));
244         } catch (Exception e) {
245             fail("This exception should have been ignored: " + e.getClass().getName());
246         }
247     }
248 
249     @Test
250     public void testFactoryNotIgnoreCreateRule()
251         throws Exception
252     {
253         URL rules = getClass().getResource( "testfactorynoignore.xml" );
254 
255         String xml = "<?xml version='1.0' ?><root one='good' two='bad' three='ugly'><foo/></root>";
256         try
257         {
258             newLoader( createRules( rules ) ).newDigester().parse( new StringReader( xml ) );
259             fail( "Exception should have been propagated from create method." );
260         }
261         catch ( Exception e )
262         {
263             /* What we expected */
264             assertEquals( org.xml.sax.SAXParseException.class, e.getClass() );
265         }
266     }
267 
268     @Test
269     public void testCallParamRule()
270         throws Exception
271     {
272         URL rules = getClass().getResource( "test-call-param-rules.xml" );
273 
274          String xml = "<?xml version='1.0' ?>"
275                       + "<root><foo attr='long'><bar>short</bar><foobar><ping>tosh</ping></foobar></foo></root>";
276 
277         CallParamTestObject testObject = new CallParamTestObject();
278 
279         Digester digester =
280             newLoader( createRules( rules ) ).setClassLoader( this.getClass().getClassLoader() ).newDigester();
281         digester.push( testObject );
282         digester.parse( new StringReader( xml ) );
283 
284         assertEquals( "Incorrect left value", "long", testObject.getLeft() );
285         assertEquals( "Incorrect middle value", "short", testObject.getMiddle() );
286         assertEquals( "Incorrect right value", "", testObject.getRight() );
287      }
288 
289     @Test
290     public void testInputSourceLoader() throws Exception {
291         String rulesXml = "<?xml version='1.0'?>"
292                 + "<digester-rules>"
293                 + " <pattern value='root'>"
294                 + "   <pattern value='foo'>"
295                 + "     <call-method-rule methodname='triple' paramcount='3'"
296                 + "            paramtypes='java.lang.String,java.lang.String,java.lang.String'/>"
297                 + "     <call-param-rule paramnumber='0' attrname='attr'/>"
298                 + "        <pattern value='bar'>"
299                 + "            <call-param-rule paramnumber='1' from-stack='false'/>"
300                 + "        </pattern>"
301                 + "        <pattern value='foobar'>"
302                 + "            <object-create-rule classname='java.lang.String'/>"
303                 + "            <pattern value='ping'>"
304                 + "                <call-param-rule paramnumber='2' from-stack='true'/>"
305                 + "            </pattern>"
306                 + "         </pattern>"
307                 + "   </pattern>"
308                 + " </pattern>"
309                 + "</digester-rules>";
310                 
311         String xml = "<?xml version='1.0' ?>"
312                      + "<root><foo attr='long'><bar>short</bar><foobar><ping>tosh</ping></foobar></foo></root>";
313 
314         CallParamTestObject testObject = new CallParamTestObject();
315 
316         Digester digester = newLoader( createRules( rulesXml ) ).newDigester();
317         digester.push( testObject );
318         digester.parse( new StringReader( xml ) );
319 
320         assertEquals( "Incorrect left value", "long", testObject.getLeft() );
321         assertEquals( "Incorrect middle value", "short", testObject.getMiddle() );
322         assertEquals( "Incorrect right value", "", testObject.getRight() );
323     }
324 
325     /** 
326      * Test the FromXmlRules.addRuleInstances(digester, path) method, ie
327      * test loading rules at a base position other than the root.
328      */
329     @Test
330     public void testBasePath()
331         throws Exception
332     {
333         String xmlRules =
334             "<?xml version='1.0'?>"
335             + "<digester-rules>"
336             + "   <pattern value='root/foo'>"
337             + "      <call-method-rule methodname='setProperty' usingElementBodyAsArgument='true' />"
338             + "   </pattern>"
339             + "</digester-rules>";
340 
341         String xml =
342             "<?xml version='1.0'?>"
343             + "<root>"
344             + "  <foo>success</foo>"
345             + "</root>";
346 
347         ObjectTestImpl testObject = new ObjectTestImpl();
348         Digester digester = newLoader( createRules( xmlRules ) ).newDigester();
349 
350         digester.push( testObject );
351         digester.parse( new InputSource( new StringReader( xml ) ) );
352 
353         assertEquals( "success", testObject.getProperty() );
354     }
355 }