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