Author: hlship
Date: Mon Oct 20 18:26:55 2008
New Revision: 706488

URL: http://svn.apache.org/viewvc?rev=706488&view=rev
Log:
TAP5-290: Namespace error when partial-updating a zone with a block

Added:
    
tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry5/dom/namespace_element_without_a_prefix.txt
Modified:
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/mixins/Autocomplete.java
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/dom/Document.java
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/dom/Element.java
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/AjaxPartialResponseRendererImpl.java
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/MarkupWriterFactoryImpl.java
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/test/TestableMarkupWriterFactoryImpl.java
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/MarkupWriterFactory.java
    
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/dom/DOMTest.java

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/mixins/Autocomplete.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/mixins/Autocomplete.java?rev=706488&r1=706487&r2=706488&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/mixins/Autocomplete.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/mixins/Autocomplete.java
 Mon Oct 20 18:26:55 2008
@@ -191,7 +191,7 @@
 
         ContentType contentType = responseRenderer.findContentType(this);
 
-        MarkupWriter writer = factory.newMarkupWriter(contentType);
+        MarkupWriter writer = factory.newPartialMarkupWriter(contentType);
 
         generateResponseMarkup(writer, matchesHolder.get());
 

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/dom/Document.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/dom/Document.java?rev=706488&r1=706487&r2=706488&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/dom/Document.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/dom/Document.java
 Mon Oct 20 18:26:55 2008
@@ -44,6 +44,7 @@
         this.encoding = encoding;
     }
 
+    @Override
     public Document getDocument()
     {
         return this;

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/dom/Element.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/dom/Element.java?rev=706488&r1=706487&r2=706488&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/dom/Element.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/dom/Element.java
 Mon Oct 20 18:26:55 2008
@@ -23,9 +23,7 @@
 import org.apache.tapestry5.ioc.internal.util.InternalUtils;
 
 import java.io.PrintWriter;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
 
 /**
  * An element that will render with a begin tag and attributes, a body, and an 
end tag. Also acts as a factory for
@@ -49,10 +47,10 @@
         }
 
 
-        void render(MarkupModel model, StringBuilder builder)
+        void render(MarkupModel model, StringBuilder builder, Map<String, 
String> namespaceURIToPrefix)
         {
             builder.append(" ");
-            builder.append(toPrefixedName(namespace, name));
+            builder.append(toPrefixedName(namespaceURIToPrefix, namespace, 
name));
             builder.append("=\"");
             model.encodeQuoted(value, builder);
             builder.append('"');
@@ -104,6 +102,7 @@
         document = null;
     }
 
+    @Override
     public Document getDocument()
     {
         return document != null ? document : super.getDocument();
@@ -293,15 +292,16 @@
     @Override
     void toMarkup(Document document, PrintWriter writer)
     {
+        Map<String, String> namespaceToPrefixMap = 
createNamespaceURIToNamespaceMap();
+
         MarkupModel markupModel = document.getMarkupModel();
 
         StringBuilder builder = new StringBuilder();
 
-        String prefixedElementName = toPrefixedName(namespace, name);
+        String prefixedElementName = toPrefixedName(namespaceToPrefixMap, 
namespace, name);
 
         builder.append("<").append(prefixedElementName);
 
-
         if (attributes != null)
         {
             List<String> keys = InternalUtils.sortedKeys(attributes);
@@ -310,7 +310,7 @@
             {
                 Attribute attribute = attributes.get(key);
 
-                attribute.render(markupModel, builder);
+                attribute.render(markupModel, builder, namespaceToPrefixMap);
             }
         }
 
@@ -359,11 +359,17 @@
         if (hasChildren || style == EndTagStyle.REQUIRE) 
writer.printf("</%s>", prefixedElementName);
     }
 
-    private String toPrefixedName(String namespace, String name)
+    private String toPrefixedName(Map<String, String> namespaceURIToPrefix, 
String namespace, String name)
     {
         if (namespace == null || namespace.equals("")) return name;
 
-        String prefix = toNamespacePrefix(namespace);
+        String prefix = namespaceURIToPrefix.get(namespace);
+
+        // This should never happen, because namespaces are automatically 
defined as needed.
+
+        if (prefix == null)
+            throw new IllegalArgumentException(
+                    String.format("No prefix has been defined for namespace 
'%s'.", namespace));
 
         // The empty string indicates the default namespace which doesn't use 
a prefix.
 
@@ -408,6 +414,7 @@
         return null;
     }
 
+
     /**
      * Searchs for a child element with a particular name below this element. 
The path parameter is a slash separated
      * series of element names.
@@ -493,17 +500,6 @@
         return this;
     }
 
-    String toNamespacePrefix(String namespaceURI)
-    {
-        String prefix = InternalUtils.get(namespaceToPrefix, namespaceURI);
-
-        if (prefix != null) return prefix;
-
-        if (parent == null) throw new 
RuntimeException(DomMessages.namespaceURINotMappedToPrefix(namespaceURI));
-
-        return parent.toNamespacePrefix(namespaceURI);
-    }
-
     /**
      * Defines a namespace for this element, mapping a URI to a prefix.   This 
will affect how namespaced elements and
      * attributes nested within the element are rendered, and will also cause 
<code>xmlns:</code> attributes (to define
@@ -562,4 +558,97 @@
 
         return this;
     }
+
+    /**
+     * Creates the URI to namespace map for this element, which reflects 
namespace mappings from containing elements. In
+     * addition, automatic namespaces are defined for any URIs that are not 
explicitly mapped (this occurs sometimes in
+     * Ajax partial render scenarios).
+     *
+     * @return a mapping from namespace URI to namespace prefix
+     */
+    private Map<String, String> createNamespaceURIToNamespaceMap()
+    {
+        Map<String, String> result = CollectionFactory.newMap();
+
+        List<Element> elements = gatherParentElements();
+
+        elements.add(this);
+
+        for (Element e : elements)
+        {
+            // Put each namespace map, when present, overwriting child 
element's mappings
+            // over parent elements (by virtue of order in the list).
+
+            if (e.namespaceToPrefix != null)
+                result.putAll(e.namespaceToPrefix);
+        }
+
+        // result now contains all the mappings, including this element's.
+
+        // Add a mapping for the element's namespace.
+
+        addMappingIfNeeded(result, namespace);
+
+        // And for any attributes that have a namespace.
+
+        if (attributes != null)
+        {
+            for (Attribute a : attributes.values())
+                addMappingIfNeeded(result, a.namespace);
+        }
+
+        return result;
+    }
+
+    private void addMappingIfNeeded(Map<String, String> masterURItoPrefixMap, 
String namespace)
+    {
+        if (namespace == null) return;
+
+        if (masterURItoPrefixMap.containsKey(namespace)) return;
+
+        // A missing namespace.
+
+        Set<String> prefixes = 
CollectionFactory.newSet(masterURItoPrefixMap.values());
+
+        // A clumsy way to find a unique id for the new namespace.
+
+        int i = 0;
+        while (true)
+        {
+            String prefix = "ns" + i;
+
+            if (!prefixes.contains(prefix))
+            {
+
+                defineNamespace(namespace, prefix);
+                masterURItoPrefixMap.put(namespace, prefix);
+                return;
+            }
+
+            i++;
+        }
+    }
+
+    /**
+     * Returns the parent elements containing this element, ordered by depth 
(the root element is first, the current
+     * element's parent is last).
+     *
+     * @return list of elements
+     */
+    private List<Element> gatherParentElements()
+    {
+        List<Element> result = CollectionFactory.newList();
+
+        Element cursor = parent;
+
+        while (cursor != null)
+        {
+            result.add(cursor);
+            cursor = cursor.parent;
+        }
+
+        Collections.reverse(result);
+
+        return result;
+    }
 }

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/AjaxPartialResponseRendererImpl.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/AjaxPartialResponseRendererImpl.java?rev=706488&r1=706487&r2=706488&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/AjaxPartialResponseRendererImpl.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/AjaxPartialResponseRendererImpl.java
 Mon Oct 20 18:26:55 2008
@@ -70,7 +70,7 @@
 
         ContentType contentType = new 
ContentType(InternalConstants.JSON_MIME_TYPE, outputEncoding);
 
-        MarkupWriter writer = factory.newMarkupWriter(pageContentType);
+        MarkupWriter writer = factory.newPartialMarkupWriter(pageContentType);
 
         JSONObject reply = new JSONObject();
 

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/MarkupWriterFactoryImpl.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/MarkupWriterFactoryImpl.java?rev=706488&r1=706487&r2=706488&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/MarkupWriterFactoryImpl.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/MarkupWriterFactoryImpl.java
 Mon Oct 20 18:26:55 2008
@@ -40,6 +40,16 @@
 
     public MarkupWriter newMarkupWriter(ContentType contentType)
     {
+        return newMarkupWriter(contentType, false);
+    }
+
+    public MarkupWriter newPartialMarkupWriter(ContentType contentType)
+    {
+        return newMarkupWriter(contentType, true);
+    }
+
+    private MarkupWriter newMarkupWriter(ContentType contentType, boolean 
partial)
+    {
         boolean isHTML = 
contentType.getMimeType().equalsIgnoreCase("text/html");
 
         MarkupModel model = isHTML ? htmlModel : xmlModel;

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/test/TestableMarkupWriterFactoryImpl.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/test/TestableMarkupWriterFactoryImpl.java?rev=706488&r1=706487&r2=706488&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/test/TestableMarkupWriterFactoryImpl.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/test/TestableMarkupWriterFactoryImpl.java
 Mon Oct 20 18:26:55 2008
@@ -46,6 +46,11 @@
         return save(delegate.newMarkupWriter(contentType));
     }
 
+    public MarkupWriter newPartialMarkupWriter(ContentType contentType)
+    {
+        return save(delegate.newPartialMarkupWriter(contentType));
+    }
+
     public MarkupWriter newMarkupWriter(String pageName)
     {
         return save(delegate.newMarkupWriter(pageName));
@@ -57,6 +62,4 @@
 
         return writer;
     }
-
-
 }

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/MarkupWriterFactory.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/MarkupWriterFactory.java?rev=706488&r1=706487&r2=706488&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/MarkupWriterFactory.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/MarkupWriterFactory.java
 Mon Oct 20 18:26:55 2008
@@ -32,6 +32,16 @@
     MarkupWriter newMarkupWriter(ContentType contentType);
 
     /**
+     * Creates a markup writer for a particular content type, configured for 
<em>partial page rendering</em> (i.e., for
+     * a response to an Ajax request).
+     *
+     * @param contentType type of content generated by the markup write; used 
to control the type of [EMAIL PROTECTED]
+     *                    org.apache.tapestry5.dom.MarkupModel} used with the 
[EMAIL PROTECTED] org.apache.tapestry5.dom.Document}
+     *                    the backs the markup writer.
+     */
+    MarkupWriter newPartialMarkupWriter(ContentType contentType);
+
+    /**
      * Obtains a markup writer that will render the content for the provided 
logical page name.
      *
      * @param pageName logical page name

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/dom/DOMTest.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/dom/DOMTest.java?rev=706488&r1=706487&r2=706488&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/dom/DOMTest.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/dom/DOMTest.java
 Mon Oct 20 18:26:55 2008
@@ -61,22 +61,23 @@
     }
 
     @Test
-    public void namespace_element_without_a_prefix()
+    public void namespace_element_without_a_prefix() throws Exception
     {
 
         Document d = new Document(new XMLMarkupModel());
 
         Element root = d.newRootElement("fredns", "root");
 
-        try
-        {
-            d.toString();
-            unreachable();
-        }
-        catch (RuntimeException ex)
-        {
-            assertEquals(ex.getMessage(), "Namespace prefix for URI 'fredns' 
is not defined.");
-        }
+        Element child = root.element("child");
+
+        Element barney = child.elementNS("barneyns", "barney");
+
+        barney.attribute("simple", "a");
+        barney.defineNamespace("bettyns", "betty");
+        barney.attribute("bettyns", "betty", "b");
+        barney.attribute("wilmans", "wilma", "c");
+
+        assertEquals(d.toString(), 
readFile("namespace_element_without_a_prefix.txt"));
     }
 
     @Test

Added: 
tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry5/dom/namespace_element_without_a_prefix.txt
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry5/dom/namespace_element_without_a_prefix.txt?rev=706488&view=auto
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry5/dom/namespace_element_without_a_prefix.txt
 (added)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry5/dom/namespace_element_without_a_prefix.txt
 Mon Oct 20 18:26:55 2008
@@ -0,0 +1,2 @@
+<?xml version="1.0"?>
+<ns0:root xmlns:ns0="fredns"><child><ns1:barney betty:betty="b" simple="a" 
ns2:wilma="c" xmlns:ns1="barneyns" xmlns:betty="bettyns" 
xmlns:ns2="wilmans"/></child></ns0:root>
\ No newline at end of file


Reply via email to