[DIGESTER-90] xmlrules does not support setNamespaceURI

git-svn-id: https://svn.apache.org/repos/asf/commons/proper/digester/trunk@1139948 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt
index d0c154e..cb9c75b 100644
--- a/RELEASE-NOTES.txt
+++ b/RELEASE-NOTES.txt
@@ -87,6 +87,8 @@
 IMPROVEMENTS OVER PREVIOUS RELEASE
 ===================================
 
+ * [DIGESTER-90] xmlrules does not support setNamespaceURI
+
  * [DIGESTER-127] Allow DigesterLoader to accept an instance of a preconfigured Digester
 
  * [DIGESTER-131] Allow recursive match in ExtendedBaseRules
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index aabe5dc..09fe15a 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -26,6 +26,9 @@
     <action dev="simonetripodi" type="fix" issue="DIGESTER-28">
       Default ClassLoader policy unusable in EAR archive
     </action>
+    <action dev="simonetripodi" type="add" issue="DIGESTER-90">
+      xmlrules does not support setNamespaceURI
+    </action>
     <action dev="simonetripodi" type="fix" issue="DIGESTER-103">
       xmlrules does not support NodeCreateRule
     </action>
diff --git a/src/main/java/org/apache/commons/digester3/xmlrules/FromXmlRulesModule.java b/src/main/java/org/apache/commons/digester3/xmlrules/FromXmlRulesModule.java
index 8f7b4f3..de18ad5 100644
--- a/src/main/java/org/apache/commons/digester3/xmlrules/FromXmlRulesModule.java
+++ b/src/main/java/org/apache/commons/digester3/xmlrules/FromXmlRulesModule.java
@@ -75,7 +75,8 @@
         {
             loadRules();
 
-            XmlRulesModule xmlRulesModule = new XmlRulesModule( rulesBinder(), getSystemIds(), rootPath );
+            XmlRulesModule xmlRulesModule = new XmlRulesModule( new NameSpaceURIRulesBinder( rulesBinder() ),
+                                                                getSystemIds(), rootPath );
             Digester digester = newLoader( xmlRulesModule )
                     .register( DIGESTER_PUBLIC_ID, xmlRulesDtdUrl.toString() )
                     .setXIncludeAware( true )
diff --git a/src/main/java/org/apache/commons/digester3/xmlrules/NameSpaceURIRulesBinder.java b/src/main/java/org/apache/commons/digester3/xmlrules/NameSpaceURIRulesBinder.java
new file mode 100644
index 0000000..52085d0
--- /dev/null
+++ b/src/main/java/org/apache/commons/digester3/xmlrules/NameSpaceURIRulesBinder.java
@@ -0,0 +1,102 @@
+package org.apache.commons.digester3.xmlrules;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.util.Stack;
+
+import org.apache.commons.digester3.binder.LinkedRuleBuilder;
+import org.apache.commons.digester3.binder.RulesBinder;
+import org.apache.commons.digester3.binder.RulesModule;
+
+/**
+ * @since 3.0
+ */
+final class NameSpaceURIRulesBinder
+    implements RulesBinder
+{
+
+    // a stack is needed because of includes!!!
+    private final Stack<String> namespaceURIs = new Stack<String>();
+
+    private final RulesBinder wrappedBinder;
+
+    public NameSpaceURIRulesBinder( RulesBinder wrappedBinder )
+    {
+        this.wrappedBinder = wrappedBinder;
+    }
+
+    /**
+     * 
+     * @param namespaceURI
+     */
+    public void addNamespaceURI( String namespaceURI )
+    {
+        namespaceURIs.push( namespaceURI );
+    }
+
+    /**
+     * 
+     */
+    public void removeNamespaceURI()
+    {
+        namespaceURIs.pop();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public ClassLoader getContextClassLoader()
+    {
+        return wrappedBinder.getContextClassLoader();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void addError( String messagePattern, Object... arguments )
+    {
+        wrappedBinder.addError( messagePattern, arguments );
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void addError( Throwable t )
+    {
+        wrappedBinder.addError( t );
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void install( RulesModule rulesModule )
+    {
+        wrappedBinder.install( rulesModule );
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public LinkedRuleBuilder forPattern( String pattern )
+    {
+        return wrappedBinder.forPattern( pattern ).withNamespaceURI( namespaceURIs.peek() );
+    }
+
+}
diff --git a/src/main/java/org/apache/commons/digester3/xmlrules/SetNamespaceURIRule.java b/src/main/java/org/apache/commons/digester3/xmlrules/SetNamespaceURIRule.java
new file mode 100644
index 0000000..459f1e0
--- /dev/null
+++ b/src/main/java/org/apache/commons/digester3/xmlrules/SetNamespaceURIRule.java
@@ -0,0 +1,59 @@
+package org.apache.commons.digester3.xmlrules;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.apache.commons.digester3.Rule;
+import org.xml.sax.Attributes;
+
+/**
+ * @since 3.0
+ */
+final class SetNamespaceURIRule
+    extends Rule
+{
+
+    private final NameSpaceURIRulesBinder rulesBinder;
+
+    public SetNamespaceURIRule( NameSpaceURIRulesBinder rulesBinder )
+    {
+        this.rulesBinder = rulesBinder;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void begin( String namespace, String name, Attributes attributes )
+        throws Exception
+    {
+        rulesBinder.addNamespaceURI( attributes.getValue( "namespaceURI" ) );
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void end( String namespace, String name )
+        throws Exception
+    {
+        rulesBinder.removeNamespaceURI();
+    }
+
+}
diff --git a/src/main/java/org/apache/commons/digester3/xmlrules/XmlRulesModule.java b/src/main/java/org/apache/commons/digester3/xmlrules/XmlRulesModule.java
index 0f0229b..f4e2be2 100644
--- a/src/main/java/org/apache/commons/digester3/xmlrules/XmlRulesModule.java
+++ b/src/main/java/org/apache/commons/digester3/xmlrules/XmlRulesModule.java
@@ -32,7 +32,7 @@
     implements RulesModule
 {
 
-    private final RulesBinder targetRulesBinder;
+    private final NameSpaceURIRulesBinder targetRulesBinder;
 
     private final Set<String> rootSystemIds;
 
@@ -40,7 +40,7 @@
 
     private WithMemoryRulesBinder memoryRulesBinder;
 
-    public XmlRulesModule( final RulesBinder targetRulesBinder, Set<String> rootSystemIds,
+    public XmlRulesModule( final NameSpaceURIRulesBinder targetRulesBinder, Set<String> rootSystemIds,
     /* @Nullable */String rootPath )
     {
         this.targetRulesBinder = targetRulesBinder;
@@ -75,6 +75,8 @@
 
         try
         {
+            forPattern( "digester-rules" ).addRule( new SetNamespaceURIRule( targetRulesBinder ) );
+
             forPattern( "*/pattern" ).addRule( new PatternRule( patternStack ) );
             forPattern( "*/include" ).addRule( new IncludeRule( memoryRulesBinder, targetRulesBinder ) );
 
diff --git a/src/main/resources/org/apache/commons/digester3/xmlrules/digester-rules.dtd b/src/main/resources/org/apache/commons/digester3/xmlrules/digester-rules.dtd
index b38cab5..e83f607 100644
--- a/src/main/resources/org/apache/commons/digester3/xmlrules/digester-rules.dtd
+++ b/src/main/resources/org/apache/commons/digester3/xmlrules/digester-rules.dtd
@@ -45,7 +45,8 @@
 
 <!-- digester-rules is the root element. -->
 <!ELEMENT digester-rules (pattern | include | %rule-elements; )*>
-
+<!ATTLIST digester-rules
+    namespaceURI   CDATA #IMPLIED>
 
 <!-- <pattern> defines a matching pattern, or part of a matching pattern. Any
      rule nested in a pattern element prepends its parent's to its pattern.
diff --git a/src/site/resources/dtds/digester-rules-3.0.dtd b/src/site/resources/dtds/digester-rules-3.0.dtd
index b38cab5..e83f607 100644
--- a/src/site/resources/dtds/digester-rules-3.0.dtd
+++ b/src/site/resources/dtds/digester-rules-3.0.dtd
@@ -45,7 +45,8 @@
 
 <!-- digester-rules is the root element. -->
 <!ELEMENT digester-rules (pattern | include | %rule-elements; )*>
-
+<!ATTLIST digester-rules
+    namespaceURI   CDATA #IMPLIED>
 
 <!-- <pattern> defines a matching pattern, or part of a matching pattern. Any
      rule nested in a pattern element prepends its parent's to its pattern.
diff --git a/src/test/java/org/apache/commons/digester3/xmlrules/Entry.java b/src/test/java/org/apache/commons/digester3/xmlrules/Entry.java
new file mode 100644
index 0000000..6c1ffdb
--- /dev/null
+++ b/src/test/java/org/apache/commons/digester3/xmlrules/Entry.java
@@ -0,0 +1,95 @@
+package org.apache.commons.digester3.xmlrules;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.net.URL;
+import java.util.Date;
+
+public final class Entry
+{
+
+    private String title;
+
+    private URL link;
+
+    private Date updated;
+
+    private String id;
+
+    private String content;
+
+    public String getTitle()
+    {
+        return title;
+    }
+
+    public void setTitle( String title )
+    {
+        this.title = title;
+    }
+
+    public URL getLink()
+    {
+        return link;
+    }
+
+    public void setLink( URL link )
+    {
+        this.link = link;
+    }
+
+    public Date getUpdated()
+    {
+        return updated;
+    }
+
+    public void setUpdated( Date updated )
+    {
+        this.updated = updated;
+    }
+
+    public String getId()
+    {
+        return id;
+    }
+
+    public void setId( String id )
+    {
+        this.id = id;
+    }
+
+    public String getContent()
+    {
+        return content;
+    }
+
+    public void setContent( String content )
+    {
+        this.content = content;
+    }
+
+    @Override
+    public String toString()
+    {
+        return "\n    Entry [title=" + title + ", link=" + link + ", updated=" + updated + ", id=" + id + ", content="
+            + content + "]\n";
+    }
+
+}
diff --git a/src/test/java/org/apache/commons/digester3/xmlrules/Feed.java b/src/test/java/org/apache/commons/digester3/xmlrules/Feed.java
new file mode 100644
index 0000000..c63a1cf
--- /dev/null
+++ b/src/test/java/org/apache/commons/digester3/xmlrules/Feed.java
@@ -0,0 +1,109 @@
+package org.apache.commons.digester3.xmlrules;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+public final class Feed
+{
+
+    private String title;
+
+    private URL link;
+
+    private Date updated;
+
+    private final List<String> authors = new ArrayList<String>();
+
+    private String id;
+
+    private final List<Entry> entries = new ArrayList<Entry>();
+
+    public String getTitle()
+    {
+        return title;
+    }
+
+    public void setTitle( String title )
+    {
+        this.title = title;
+    }
+
+    public URL getLink()
+    {
+        return link;
+    }
+
+    public void setLink( URL link )
+    {
+        this.link = link;
+    }
+
+    public Date getUpdated()
+    {
+        return updated;
+    }
+
+    public void setUpdated( Date updated )
+    {
+        this.updated = updated;
+    }
+
+    public String getId()
+    {
+        return id;
+    }
+
+    public void setId( String id )
+    {
+        this.id = id;
+    }
+
+    public List<String> getAuthors()
+    {
+        return authors;
+    }
+
+    public void addAuthor( String author )
+    {
+        authors.add( author );
+    }
+
+    public List<Entry> getEntries()
+    {
+        return entries;
+    }
+
+    public void addEntry( Entry entry )
+    {
+        entries.add( entry );
+    }
+
+    @Override
+    public String toString()
+    {
+        return "Feed [title=" + title + ", link=" + link + ", updated=" + updated + ", authors=" + authors + ", id="
+            + id + ", entries=" + entries + "]";
+    }
+
+}
diff --git a/src/test/java/org/apache/commons/digester3/xmlrules/SetNamespaceURITestCase.java b/src/test/java/org/apache/commons/digester3/xmlrules/SetNamespaceURITestCase.java
new file mode 100644
index 0000000..e9020ff
--- /dev/null
+++ b/src/test/java/org/apache/commons/digester3/xmlrules/SetNamespaceURITestCase.java
@@ -0,0 +1,64 @@
+package org.apache.commons.digester3.xmlrules;
+
+import static org.apache.commons.digester3.binder.DigesterLoader.newLoader;
+import static org.junit.Assert.*;
+
+import java.net.URL;
+import java.util.Date;
+
+import org.apache.commons.beanutils.ConvertUtils;
+import org.apache.commons.beanutils.converters.DateConverter;
+import org.apache.commons.digester3.Digester;
+import org.junit.Test;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+public final class SetNamespaceURITestCase
+{
+
+    @Test
+    public void atomWithNamespaceParse()
+        throws Exception
+    {
+        // Drive commons-beanutils how to convert dates
+        DateConverter dateConverter = new DateConverter();
+        dateConverter.setPatterns( new String[] { "yyyy-MM-dd'T'HH:mm" } );
+        ConvertUtils.register( dateConverter, Date.class );
+
+        final URL rules = getClass().getResource( "atom-rules.xml" );
+        final URL input = getClass().getResource( "atom-content.xml" );
+
+        Digester digester = newLoader( new FromXmlRulesModule()
+        {
+
+            @Override
+            protected void loadRules()
+            {
+                loadXMLRules( rules );
+            }
+
+        } )
+        .setNamespaceAware( true )
+        .newDigester();
+        Feed feed = digester.parse( input.openStream() );
+        assertNotNull( feed );
+    }
+
+}
diff --git a/src/test/resources/org/apache/commons/digester3/xmlrules/atom-content.xml b/src/test/resources/org/apache/commons/digester3/xmlrules/atom-content.xml
new file mode 100644
index 0000000..226b28c
--- /dev/null
+++ b/src/test/resources/org/apache/commons/digester3/xmlrules/atom-content.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<!--
+    ATOM feed kindly borrowed from Apache Abdera
+    (see http://svn.apache.org/repos/asf/abdera/java/trunk/parser/src/test/resources/xmlcontent.xml)
+-->
+<atom:feed xmlns:atom="http://www.w3.org/2005/Atom">
+
+  <atom:title>Example Feed</atom:title>
+  <atom:link href="http://example.org/" />
+  <atom:updated>2003-12-13T18:30</atom:updated>
+  <atom:author>
+    <atom:name>John Doe</atom:name>
+  </atom:author>
+  <atom:id>urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6</atom:id>
+
+  <atom:entry>
+    <atom:title>Atom-Powered Robots Run Amok</atom:title>
+    <atom:link href="http://example.org/2003/12/13/atom03" />
+    <atom:id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</atom:id>
+    <atom:updated>2003-12-13T18:30</atom:updated>
+    <atom:content type="text/plain">this is just a simple test!</atom:content>
+  </atom:entry>
+
+</atom:feed>
diff --git a/src/test/resources/org/apache/commons/digester3/xmlrules/atom-rules.xml b/src/test/resources/org/apache/commons/digester3/xmlrules/atom-rules.xml
new file mode 100644
index 0000000..8a91276
--- /dev/null
+++ b/src/test/resources/org/apache/commons/digester3/xmlrules/atom-rules.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE digester-rules PUBLIC "-//Apache Commons //DTD digester-rules XML V1.0//EN" "http://commons.apache.org/digester/dtds/digester-rules-3.0.dtd">
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements.  See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License.  You may obtain a copy of the License at
+  
+      http://www.apache.org/licenses/LICENSE-2.0
+  
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<digester-rules namespaceURI="http://www.w3.org/2005/Atom">
+  <pattern value="feed">
+    <object-create-rule classname="org.apache.commons.digester3.xmlrules.Feed" />
+    <bean-property-setter-rule pattern="title" />
+    <bean-property-setter-rule pattern="updated" />
+    <bean-property-setter-rule pattern="id" />
+    <set-properties-rule pattern="link">
+      <alias attr-name="href" prop-name="link" />
+    </set-properties-rule>
+    <call-method-rule pattern="author/name" methodname="addAuthor" usingElementBodyAsArgument="true" />
+
+    <pattern value="entry">
+      <object-create-rule classname="org.apache.commons.digester3.xmlrules.Entry" />
+      <bean-property-setter-rule pattern="title" />
+      <bean-property-setter-rule pattern="updated" />
+      <bean-property-setter-rule pattern="id" />
+      <set-properties-rule pattern="link">
+        <alias attr-name="href" prop-name="link" />
+      </set-properties-rule>
+      <set-next-rule methodname="addEntry" />
+    </pattern>
+  </pattern>
+</digester-rules>