You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tapestry.apache.org by hl...@apache.org on 2009/12/10 23:38:40 UTC

svn commit: r889446 [1/2] - in /tapestry/tapestry5/trunk: ./ quickstart/ src/site/apt/ tapestry-core/ tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ tapestry-core/src/main/resources/org/apache/tapestry5/internal/services/ tapestry-...

Author: hlship
Date: Thu Dec 10 22:38:39 2009
New Revision: 889446

URL: http://svn.apache.org/viewvc?rev=889446&view=rev
Log:
TAP5-713: Change template parser to not use StAX, as it is not (yet) compatible with Google App Engine

Added:
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/AttributeInfo.java   (with props)
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/DTDData.java   (with props)
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/NamespaceMapping.java   (with props)
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/SaxTemplateParser.java
      - copied, changed from r888990, tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/StaxTemplateParser.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/XMLToken.java   (with props)
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/XMLTokenStream.java   (with props)
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/XMLTokenType.java   (with props)
Removed:
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/StaxTemplateParser.java
Modified:
    tapestry/tapestry5/trunk/   (props changed)
    tapestry/tapestry5/trunk/quickstart/   (props changed)
    tapestry/tapestry5/trunk/src/site/apt/index.apt
    tapestry/tapestry5/trunk/src/site/apt/upgrade.apt
    tapestry/tapestry5/trunk/tapestry-core/pom.xml
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ServicesMessages.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/TemplateParserImpl.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/TemplateParserState.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/services/ServicesStrings.properties
    tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/IntegrationTests.java

Propchange: tapestry/tapestry5/trunk/
------------------------------------------------------------------------------
--- svn:ignore (original)
+++ svn:ignore Thu Dec 10 22:38:39 2009
@@ -2,4 +2,10 @@
 target
 bin-test
 temp-testng-customsuite.xml
-*.iml
*.ipr
*.iws
.classpath
.project
.settings
+*.iml
+*.ipr
+*.iws
+.classpath
+.project
+.settings
+.externalToolBuilders

Propchange: tapestry/tapestry5/trunk/quickstart/
------------------------------------------------------------------------------
--- svn:ignore (original)
+++ svn:ignore Thu Dec 10 22:38:39 2009
@@ -1,3 +1,4 @@
 target
 .settings
 .project
+.classpath

Modified: tapestry/tapestry5/trunk/src/site/apt/index.apt
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/src/site/apt/index.apt?rev=889446&r1=889445&r2=889446&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/src/site/apt/index.apt (original)
+++ tapestry/tapestry5/trunk/src/site/apt/index.apt Thu Dec 10 22:38:39 2009
@@ -34,39 +34,6 @@
 
 New And Of Note
 
-  * Tapestry now uses the {{{http://www.gscottolson.com/blackbirdjs/}Blackbird}} JavaScript console.
-
-  * Tapestry now automatically combines multiple JavaScript libraries into a single request.
-
-  * An Ajax event request may now return a
-    {{{apidocs/org/apache/tapestry5/ajax/MultiZoneUpdate.html}MultiZoneUpdate}} instance
-    to update multiple zones in the client web browser.
-
-  * Client-side numeric validation is now locale-sensitive.
-
-  * Some significant performance improvements over Tapestry 5.0.18: the time to initially load a page,
-    and the time to render a page have decreased.
-
-  * Tapestry IoC services can now be easily <{{{tapestry-ioc/advice.html}advised}}> as well as
-   <{{{tapestry-ioc/decorator.html}decorated}}> (both of these refer to Aspect Oriented Techniques applied to
-    Tapestry IoC services).
-
-  * Tapestry Services can now be injected into Spring Beans, when using the Tapestry/Spring integration library.
-
-  * Tapestry now {{{guide/compress.html}compresses}} responses for clients that support GZIP compression.
-    Context and classpath assets
-    are now handled uniformly: versioned URLs, far-future expiration headers, and GZIP compression where applicable.
-
-  * Ordered and mapped configurations can now have overrides.
-
-  * Property expressions have been improved: You can now invoke methods with parameters, or create a list (very useful for link contexts).
-
-  * IoC Service contributions may now be made in terms of classes (that are automatically instantiated) as well as
-    instances.
-
-  * A simpler method of {{{apidocs/org/apache/tapestry5/ioc/services/ServiceOverride}overriding built-in services}}
-    has been added.
-
   []
   
 Roadmap

Modified: tapestry/tapestry5/trunk/src/site/apt/upgrade.apt
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/src/site/apt/upgrade.apt?rev=889446&r1=889445&r2=889446&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/src/site/apt/upgrade.apt (original)
+++ tapestry/tapestry5/trunk/src/site/apt/upgrade.apt Thu Dec 10 22:38:39 2009
@@ -4,15 +4,20 @@
 
 Upgrade Notes
 
-  This is a quick guide to changes <since> Tapestry 5.0.18.  This is meant to provide information
-  on any additions or changes that developers will face after upgrading from Tapestry 5.0 to Tapestry 5.1, or from one
-  5.1 snapshot release to another.
-
+  This is a quick guide to changes <since> Tapestry 5.1.0.5.  This is meant to provide information
+  on any additions or changes that developers will face after upgrading to Tapestry 5.2.
+  
   It is always advised to perform a full and complete build after upgrading.
 
   You should also check the {{{release-notes.html}project-wide release notes}} for information
   about bugs fixes and other improvements.
 
+Release 5.2.0
+
+  Tapestry no longer uses a StAX parser (it uses a normal SAX parser) to parse template. This change
+  reduces the number of dependencies for Tapestry, and is a stepping stone to compatibility with
+  Google App Engine.
+
 Release 5.1.0.4
 
   Tapestry's alpha URL rewriting support (available from 5.1.0.1) has undergone some API changes:

Modified: tapestry/tapestry5/trunk/tapestry-core/pom.xml
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/pom.xml?rev=889446&r1=889445&r2=889446&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/pom.xml (original)
+++ tapestry/tapestry5/trunk/tapestry-core/pom.xml Thu Dec 10 22:38:39 2009
@@ -53,12 +53,6 @@
             </exclusions>
         </dependency>
 
-        <dependency>
-            <groupId>org.codehaus.woodstox</groupId>
-            <artifactId>woodstox-core-asl</artifactId>
-            <version>4.0.3</version>
-        </dependency>
-
     </dependencies>
 
     <build>

Added: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/AttributeInfo.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/AttributeInfo.java?rev=889446&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/AttributeInfo.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/AttributeInfo.java Thu Dec 10 22:38:39 2009
@@ -0,0 +1,36 @@
+// Copyright 2009 The Apache Software Foundation
+//
+// Licensed 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.
+
+package org.apache.tapestry5.internal.services;
+
+import javax.xml.namespace.QName;
+
+/**
+ * Tracks the qualified name and value of an attribute within a start element
+ * XMLToken.
+ * 
+ * @since 5.2.0
+ */
+public class AttributeInfo
+{
+    final QName attributeName;
+
+    final String value;
+
+    public AttributeInfo(QName attributeName, String value)
+    {
+        this.attributeName = attributeName;
+        this.value = value;
+    }
+}

Propchange: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/AttributeInfo.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/DTDData.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/DTDData.java?rev=889446&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/DTDData.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/DTDData.java Thu Dec 10 22:38:39 2009
@@ -0,0 +1,32 @@
+// Copyright 2009 The Apache Software Foundation
+//
+// Licensed 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.
+
+package org.apache.tapestry5.internal.services;
+
+import org.xml.sax.ext.LexicalHandler;
+
+/**
+ * A capturing of the data from
+ * {@link LexicalHandler#startDTD(String, String, String)}.
+ * 
+ * @since 5.2.0
+ */
+public interface DTDData
+{
+    String getRootName();
+
+    String getPublicId();
+
+    String getSystemId();
+}

Propchange: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/DTDData.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/NamespaceMapping.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/NamespaceMapping.java?rev=889446&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/NamespaceMapping.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/NamespaceMapping.java Thu Dec 10 22:38:39 2009
@@ -0,0 +1,33 @@
+// Copyright 2009 The Apache Software Foundation
+//
+// Licensed 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.
+
+package org.apache.tapestry5.internal.services;
+
+/**
+ * Used within a {@link XMLToken} to identify namespaces defined with a start
+ * element token.
+ * 
+ * @since 5.2.0
+ */
+class NamespaceMapping
+{
+    final String prefix, uri;
+
+    public NamespaceMapping(String prefix, String uri)
+    {
+        this.prefix = prefix;
+        this.uri = uri;
+    }
+
+}

Propchange: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/NamespaceMapping.java
------------------------------------------------------------------------------
    svn:eol-style = native

Copied: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/SaxTemplateParser.java (from r888990, tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/StaxTemplateParser.java)
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/SaxTemplateParser.java?p2=tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/SaxTemplateParser.java&p1=tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/StaxTemplateParser.java&r1=888990&r2=889446&rev=889446&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/StaxTemplateParser.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/SaxTemplateParser.java Thu Dec 10 22:38:39 2009
@@ -14,34 +14,53 @@
 
 package org.apache.tapestry5.internal.services;
 
-import org.apache.tapestry5.internal.parser.*;
-import org.apache.tapestry5.ioc.Location;
-import org.apache.tapestry5.ioc.Resource;
-import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
-import org.apache.tapestry5.ioc.internal.util.InternalUtils;
-import org.apache.tapestry5.ioc.internal.util.LocationImpl;
-import org.apache.tapestry5.ioc.internal.util.TapestryException;
-import org.codehaus.stax2.DTDInfo;
-import org.codehaus.stax2.XMLInputFactory2;
-import org.codehaus.stax2.XMLStreamReader2;
-
-import javax.xml.namespace.QName;
-import static javax.xml.stream.XMLStreamConstants.*;
-import javax.xml.stream.XMLStreamException;
-import java.io.IOException;
+import java.net.URL;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
+import javax.xml.namespace.QName;
+
+import org.apache.tapestry5.internal.parser.AttributeToken;
+import org.apache.tapestry5.internal.parser.BlockToken;
+import org.apache.tapestry5.internal.parser.BodyToken;
+import org.apache.tapestry5.internal.parser.CDATAToken;
+import org.apache.tapestry5.internal.parser.CommentToken;
+import org.apache.tapestry5.internal.parser.ComponentTemplate;
+import org.apache.tapestry5.internal.parser.ComponentTemplateImpl;
+import org.apache.tapestry5.internal.parser.DTDToken;
+import org.apache.tapestry5.internal.parser.DefineNamespacePrefixToken;
+import org.apache.tapestry5.internal.parser.EndElementToken;
+import org.apache.tapestry5.internal.parser.ExpansionToken;
+import org.apache.tapestry5.internal.parser.ExtensionPointToken;
+import org.apache.tapestry5.internal.parser.ParameterToken;
+import org.apache.tapestry5.internal.parser.StartComponentToken;
+import org.apache.tapestry5.internal.parser.StartElementToken;
+import org.apache.tapestry5.internal.parser.TemplateToken;
+import org.apache.tapestry5.internal.parser.TextToken;
+import org.apache.tapestry5.ioc.Location;
+import org.apache.tapestry5.ioc.Resource;
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+import org.apache.tapestry5.ioc.internal.util.InternalUtils;
+import org.apache.tapestry5.ioc.internal.util.TapestryException;
+
 /**
- * Implementation of {@link org.apache.tapestry5.internal.services.TemplateParser} based on the <a
- * href="http://en.wikipedia.org/wiki/StAX">Streaming API for XML</a>.   It uses a few features of Stax2 and is
- * therefore dependent on the Woodstock STAX parser.
+ * SAX-based template parser logic, taking a {@link Resource} to a Tapestry
+ * template file and returning
+ * a {@link ComponentTemplate}.
+ * <p>
+ * Earlier versions of this code used the StAX (streaming XML parser), but that
+ * was really, really bad for Google App Engine. This version uses SAX under the
+ * covers, but kind of replicates the important bits of the StAX API as
+ * {@link XMLTokenStream}.
+ * 
+ * @since 5.2.0
  */
-@SuppressWarnings({ "JavaDoc" })
-public class StaxTemplateParser
+@SuppressWarnings(
+{ "JavaDoc" })
+public class SaxTemplateParser
 {
     private static final String MIXINS_ATTRIBUTE_NAME = "mixins";
 
@@ -61,76 +80,83 @@
      */
     public static final String TAPESTRY_SCHEMA_5_1_0 = "http://tapestry.apache.org/schema/tapestry_5_1_0.xsd";
 
-    // Might want to change this from a Set to a map from URI to version number (if we hit a 3rd version of the namespace URI).
-    private static final Set<String> TAPESTRY_SCHEMA_URIS = CollectionFactory.newSet(TAPESTRY_SCHEMA_5_0_0,
-                                                                                     TAPESTRY_SCHEMA_5_1_0);
+    // Might want to change this from a Set to a map from URI to version number
+    // (if we hit a 3rd version of the namespace URI).
+    private static final Set<String> TAPESTRY_SCHEMA_URIS = CollectionFactory.newSet(
+            TAPESTRY_SCHEMA_5_0_0, TAPESTRY_SCHEMA_5_1_0);
 
     /**
-     * Special namespace used to denote Block parameters to components, as a (preferred) alternative to the t:parameter
-     * element.  The simple element name is the name of the parameter.
+     * Special namespace used to denote Block parameters to components, as a
+     * (preferred) alternative to the t:parameter
+     * element. The simple element name is the name of the parameter.
      */
     private static final String TAPESTRY_PARAMETERS_URI = "tapestry:parameter";
 
     /**
-     * URI prefix used to identify a Tapestry library, the remainder of the URI becomes a prefix on the element name.
+     * URI prefix used to identify a Tapestry library, the remainder of the URI
+     * becomes a prefix on the element name.
      */
     private static final String LIB_NAMESPACE_URI_PREFIX = "tapestry-library:";
 
     /**
-     * Pattern used to parse the path portion of the library namespace URI.  A series of simple identifiers with slashes
+     * Pattern used to parse the path portion of the library namespace URI. A
+     * series of simple identifiers with slashes
      * allowed as seperators.
      */
 
     private static final Pattern LIBRARY_PATH_PATTERN = Pattern.compile("^[a-z]\\w*(/[a-z]\\w*)*$",
-                                                                        Pattern.CASE_INSENSITIVE);
+            Pattern.CASE_INSENSITIVE);
 
-    private static final Pattern ID_PATTERN = Pattern.compile("^[a-z]\\w*$", Pattern.CASE_INSENSITIVE);
+    private static final Pattern ID_PATTERN = Pattern.compile("^[a-z]\\w*$",
+            Pattern.CASE_INSENSITIVE);
 
     /**
-     * Any amount of mixed simple whitespace (space, tab, form feed) mixed with at least one carriage return or line
-     * feed, followed by any amount of whitespace.  Will be reduced to a single linefeed.
+     * Any amount of mixed simple whitespace (space, tab, form feed) mixed with
+     * at least one carriage return or line
+     * feed, followed by any amount of whitespace. Will be reduced to a single
+     * linefeed.
      */
-    private static final Pattern REDUCE_LINEBREAKS_PATTERN = Pattern.compile("[ \\t\\f]*[\\r\\n]\\s*",
-                                                                             Pattern.MULTILINE);
+    private static final Pattern REDUCE_LINEBREAKS_PATTERN = Pattern.compile(
+            "[ \\t\\f]*[\\r\\n]\\s*", Pattern.MULTILINE);
 
     /**
-     * Used when compressing whitespace, matches any sequence of simple whitespace (space, tab, formfeed). Applied after
+     * Used when compressing whitespace, matches any sequence of simple
+     * whitespace (space, tab, formfeed). Applied after
      * REDUCE_LINEBREAKS_PATTERN.
      */
-    private static final Pattern REDUCE_WHITESPACE_PATTERN = Pattern.compile("[ \\t\\f]+", Pattern.MULTILINE);
+    private static final Pattern REDUCE_WHITESPACE_PATTERN = Pattern.compile("[ \\t\\f]+",
+            Pattern.MULTILINE);
 
-    // Note the use of the non-greedy modifier; this prevents the pattern from merging multiple
+    // Note the use of the non-greedy modifier; this prevents the pattern from
+    // merging multiple
     // expansions on the same text line into a single large
     // but invalid expansion.
 
     private static final Pattern EXPANSION_PATTERN = Pattern.compile("\\$\\{\\s*(.*?)\\s*}");
 
-    private static final String[] EVENT_NAMES = { "",
-            "START_ELEMENT", "END_ELEMENT", "PROCESSING_INSTRUCTION",
-            "CHARACTERS", "COMMENT", "SPACE", "START_DOCUMENT",
-            "END_DOCUMENT", "ENTITY_REFERENCE", "ATTRIBUTE", "DTD", "CDATA",
-            "NAMESPACE", "NOTATION_DECLARATION", "ENTITY_DECLARATION" };
-
     private static final Set<String> MUST_BE_ROOT = CollectionFactory.newSet("extend", "container");
 
     private final Resource resource;
 
-    private final XMLStreamReader2 reader;
+    private final XMLTokenStream tokenStream;
 
     private final StringBuilder textBuffer = new StringBuilder();
 
     private final List<TemplateToken> tokens = CollectionFactory.newList();
 
-    // This starts pointing at tokens but occasionally shifts to a list inside the overrides Map.
+    // This starts pointing at tokens but occasionally shifts to a list inside
+    // the overrides Map.
     private List<TemplateToken> tokenAccumulator = tokens;
 
     /**
-     * Primarily used as a set of componentIds (to check for duplicates and conflicts).
+     * Primarily used as a set of componentIds (to check for duplicates and
+     * conflicts).
      */
     private final Map<String, Location> componentIds = CollectionFactory.newCaseInsensitiveMap();
 
     /**
-     * Map from override id to a list of tokens; this actually works both for overrides defined by this template and
+     * Map from override id to a list of tokens; this actually works both for
+     * overrides defined by this template and
      * overrides provided by this template.
      */
     private Map<String, List<TemplateToken>> overrides;
@@ -141,47 +167,38 @@
 
     private boolean active = true;
 
-    private Location cachedLocation;
-
-    public StaxTemplateParser(Resource resource, XMLInputFactory2 inputFactory) throws XMLStreamException, IOException
+    public SaxTemplateParser(Resource resource, Map<String, URL> publicIdToURL)
     {
         this.resource = resource;
-        this.reader = (XMLStreamReader2) inputFactory.createXMLStreamReader(resource.openStream());
+        this.tokenStream = new XMLTokenStream(resource, publicIdToURL);
     }
 
     public ComponentTemplate parse(boolean compressWhitespace)
     {
-        TemplateParserState initialParserState = new TemplateParserState().compressWhitespace(compressWhitespace);
-
         try
         {
+            tokenStream.parse();
+
+            TemplateParserState initialParserState = new TemplateParserState()
+                    .compressWhitespace(compressWhitespace);
+
             root(initialParserState);
 
-            reader.close();
+            return new ComponentTemplateImpl(resource, tokens, componentIds, extension, overrides);
         }
         catch (Exception ex)
         {
-            try
-            {
-                reader.closeCompletely();
-            }
-            catch (XMLStreamException e)
-            {
-                // Ignore it.
-            }
-
-            throw new TapestryException(ServicesMessages.templateParseError(resource, ex), getLocation(),
-                                        ex);
+            throw new TapestryException(String.format("Failure parsing template %s: %s", resource,
+                    InternalUtils.toMessage(ex)), tokenStream.getLocation(), ex);
         }
 
-        return new ComponentTemplateImpl(resource, tokens, componentIds, extension, overrides);
     }
 
-    void root(TemplateParserState state) throws XMLStreamException
+    void root(TemplateParserState state)
     {
-        while (active && reader.hasNext())
+        while (active && tokenStream.hasNext())
         {
-            switch (reader.next())
+            switch (tokenStream.next())
             {
                 case DTD:
 
@@ -205,12 +222,12 @@
         }
     }
 
-    private void rootElement(TemplateParserState initialState) throws XMLStreamException
+    private void rootElement(TemplateParserState initialState)
     {
         TemplateParserState state = setupForElement(initialState);
 
-        String uri = reader.getNamespaceURI();
-        String name = reader.getLocalName();
+        String uri = tokenStream.getNamespaceURI();
+        String name = tokenStream.getLocalName();
 
         if (TAPESTRY_SCHEMA_5_1_0.equals(uri))
         {
@@ -230,23 +247,21 @@
             }
         }
 
-
         element(state);
     }
 
-    private void extend(TemplateParserState state) throws XMLStreamException
+    private void extend(TemplateParserState state)
     {
         extension = true;
 
         while (active)
         {
-            switch (reader.next())
+            switch (tokenStream.next())
             {
                 case START_ELEMENT:
 
-                    if (reader.getNamespaceURI().equals(
-                            TAPESTRY_SCHEMA_5_1_0) && reader.getLocalName().equalsIgnoreCase(
-                            "replace"))
+                    if (tokenStream.getNamespaceURI().equals(TAPESTRY_SCHEMA_5_1_0)
+                            && tokenStream.getLocalName().equalsIgnoreCase("replace"))
                     {
                         replace(state);
                         break;
@@ -258,7 +273,7 @@
 
                     return;
 
-                // Ignore spaces and characters inside <extend>.
+                    // Ignore spaces and characters inside <extend>.
 
                 case COMMENT:
                 case SPACE:
@@ -267,7 +282,7 @@
                 // Other content (characters, etc.) are forbidden.
 
                 case CHARACTERS:
-                    if (InternalUtils.isBlank(reader.getText()))
+                    if (InternalUtils.isBlank(tokenStream.getText()))
                         break;
 
                 default:
@@ -276,7 +291,7 @@
         }
     }
 
-    private void replace(TemplateParserState state) throws XMLStreamException
+    private void replace(TemplateParserState state)
     {
         String id = getRequiredIdAttribute();
 
@@ -285,28 +300,23 @@
 
     private void unexpectedEventType()
     {
-        int eventType = reader.getEventType();
+        XMLTokenType eventType = tokenStream.getEventType();
 
-        throw new IllegalStateException(
-                String.format("Unexpected XML parse event %s.", EVENT_NAMES[eventType]));
+        throw new IllegalStateException(String.format("Unexpected XML parse event %s.", eventType
+                .name()));
     }
 
-    private void dtd() throws XMLStreamException
+    private void dtd()
     {
-        DTDInfo dtdInfo = reader.getDTDInfo();
+        DTDData dtdInfo = tokenStream.getDTDInfo();
 
-        tokenAccumulator.add(new DTDToken(dtdInfo.getDTDRootName(), dtdInfo.getDTDPublicId(), dtdInfo.getDTDSystemId(),
-                                          getLocation()));
+        tokenAccumulator.add(new DTDToken(dtdInfo.getRootName(), dtdInfo.getPublicId(), dtdInfo
+                .getSystemId(), getLocation()));
     }
 
     private Location getLocation()
     {
-        int lineNumber = reader.getLocation().getLineNumber();
-
-        if (cachedLocation == null || cachedLocation.getLine() != lineNumber)
-            cachedLocation = new LocationImpl(resource, lineNumber);
-
-        return cachedLocation;
+        return tokenStream.getLocation();
     }
 
     /**
@@ -316,7 +326,7 @@
      * <p/>
      * a Tapestry component via &lt;t:type&gt;
      * <p/>
-     * a Tapestry component via t:type="type"  and/or t:id="id"
+     * a Tapestry component via t:type="type" and/or t:id="id"
      * <p/>
      * a Tapestry component via a library namespace
      * <p/>
@@ -334,12 +344,12 @@
      * <p/>
      * An ordinary element
      */
-    void element(TemplateParserState initialState) throws XMLStreamException
+    void element(TemplateParserState initialState)
     {
         TemplateParserState state = setupForElement(initialState);
 
-        String uri = reader.getNamespaceURI();
-        String name = reader.getLocalName();
+        String uri = tokenStream.getNamespaceURI();
+        String name = tokenStream.getLocalName();
 
         if (TAPESTRY_SCHEMA_5_1_0.equals(uri))
         {
@@ -365,10 +375,8 @@
                 return;
             }
 
-            if (name.equalsIgnoreCase("replace"))
-            {
-                throw new RuntimeException("The <replace> element may only appear directly within an extend element.");
-            }
+            if (name.equalsIgnoreCase("replace")) { throw new RuntimeException(
+                    "The <replace> element may only appear directly within an extend element."); }
 
             if (MUST_BE_ROOT.contains(name))
                 mustBeRoot(name);
@@ -401,7 +409,7 @@
                 return;
             }
 
-            possibleTapestryComponent(state, null, reader.getLocalName().replace('.', '/'));
+            possibleTapestryComponent(state, null, tokenStream.getLocalName().replace('.', '/'));
 
             return;
         }
@@ -422,22 +430,22 @@
 
         // Just an ordinary element ... unless it has t:id or t:type
 
-        possibleTapestryComponent(state, reader.getLocalName(), null);
+        possibleTapestryComponent(state, tokenStream.getLocalName(), null);
     }
 
     /**
-     * Processes a body of an element including text and (recursively) nested elements. Adds an {@link
-     * org.apache.tapestry5.internal.parser.TokenType#END_ELEMENT} token before returning.
-     *
+     * Processes a body of an element including text and (recursively) nested
+     * elements. Adds an
+     * {@link org.apache.tapestry5.internal.parser.TokenType#END_ELEMENT} token
+     * before returning.
+     * 
      * @param state
-     * @throws XMLStreamException
      */
     private void processBody(TemplateParserState state)
-            throws XMLStreamException
     {
         while (active)
         {
-            switch (reader.next())
+            switch (tokenStream.next())
             {
                 case START_ELEMENT:
 
@@ -470,15 +478,17 @@
     }
 
     /**
-     * Handles an extension point, putting a RenderExtension token in position in the template.
-     *
+     * Handles an extension point, putting a RenderExtension token in position
+     * in the template.
+     * 
      * @param state
-     * @throws XMLStreamException
      */
-    private void extensionPoint(TemplateParserState state) throws XMLStreamException
+    private void extensionPoint(TemplateParserState state)
     {
-        // An extension point adds a token that represents where the override (either the default
-        // provided in the parent template, or the true override from a child template) is positioned.
+        // An extension point adds a token that represents where the override
+        // (either the default
+        // provided in the parent template, or the true override from a child
+        // template) is positioned.
 
         String id = getRequiredIdAttribute();
 
@@ -493,19 +503,20 @@
 
         if (InternalUtils.isBlank(id))
             throw new RuntimeException(String.format("The <%s> element must have an id attribute.",
-                                                     reader.getLocalName()));
+                    tokenStream.getLocalName()));
 
         return id;
     }
 
     private void addContentToOverride(TemplateParserState state, String id)
-            throws XMLStreamException
+
     {
         List<TemplateToken> savedTokenAccumulator = tokenAccumulator;
 
         tokenAccumulator = CollectionFactory.newList();
 
-        // TODO: id should probably be unique; i.e., you either define an override or you
+        // TODO: id should probably be unique; i.e., you either define an
+        // override or you
         // provide an override, but you don't do both in the same template.
 
         if (overrides == null)
@@ -515,7 +526,7 @@
 
         while (active)
         {
-            switch (reader.next())
+            switch (tokenStream.next())
             {
                 case START_ELEMENT:
                     element(state);
@@ -525,7 +536,8 @@
 
                     processTextBuffer(state);
 
-                    // Restore everthing to how it was before the extention-point was reached.
+                    // Restore everthing to how it was before the
+                    // extention-point was reached.
 
                     tokenAccumulator = savedTokenAccumulator;
                     return;
@@ -538,40 +550,43 @@
 
     private void mustBeRoot(String name)
     {
-        throw new RuntimeException(
-                String.format("Element <%s> is only valid as the root element of a template.", name));
+        throw new RuntimeException(String.format(
+                "Element <%s> is only valid as the root element of a template.", name));
     }
 
     /**
-     * Triggered by &lt;t:content&gt; element; limits template content to just what's inside.
+     * Triggered by &lt;t:content&gt; element; limits template content to just
+     * what's inside.
      */
 
-    private void limitContent(TemplateParserState state) throws XMLStreamException
+    private void limitContent(TemplateParserState state)
     {
         if (state.isCollectingContent())
             throw new IllegalStateException(
                     "The <content> element may not be nested within another <content> element.");
 
-
         TemplateParserState newState = state.collectingContent().insideComponent(false);
 
         // Clear out any tokens that precede the <t:content> element
 
         tokens.clear();
 
-        // I'm not happy about this; you really shouldn't define overrides just to clear them out,
-        // but it is consistent. Perhaps this should be an error if overrides is non-empty.
+        // I'm not happy about this; you really shouldn't define overrides just
+        // to clear them out,
+        // but it is consistent. Perhaps this should be an error if overrides is
+        // non-empty.
 
         overrides = null;
 
-        // Make sure that if the <t:content> appears inside a <t:replace> or <t:extension-point>, that
+        // Make sure that if the <t:content> appears inside a <t:replace> or
+        // <t:extension-point>, that
         // it is still handled correctly.
 
         tokenAccumulator = tokens;
 
         while (active)
         {
-            switch (reader.next())
+            switch (tokenStream.next())
             {
                 case START_ELEMENT:
                     element(newState);
@@ -579,7 +594,8 @@
 
                 case END_ELEMENT:
 
-                    // The active flag is global, once we hit it, the entire parse is aborted, leaving
+                    // The active flag is global, once we hit it, the entire
+                    // parse is aborted, leaving
                     // tokens with just tokens defined inside <t:content>.
 
                     active = false;
@@ -593,13 +609,13 @@
 
     }
 
-    private void removeContent() throws XMLStreamException
+    private void removeContent()
     {
         int depth = 1;
 
         while (active)
         {
-            switch (reader.next())
+            switch (tokenStream.next())
             {
                 case START_ELEMENT:
                     depth++;
@@ -610,7 +626,8 @@
                 case END_ELEMENT:
                     depth--;
 
-                    if (depth == 0) return;
+                    if (depth == 0)
+                        return;
 
                     break;
 
@@ -625,13 +642,12 @@
         return InternalUtils.isBlank(input) ? null : input;
     }
 
-
     /**
      * Added in release 5.1.
      */
-    private void libraryNamespaceComponent(TemplateParserState state) throws XMLStreamException
+    private void libraryNamespaceComponent(TemplateParserState state)
     {
-        String uri = reader.getNamespaceURI();
+        String uri = tokenStream.getNamespaceURI();
 
         // The library path is encoded into the namespace URI.
 
@@ -640,21 +656,23 @@
         if (!LIBRARY_PATH_PATTERN.matcher(path).matches())
             throw new RuntimeException(ServicesMessages.invalidPathForLibraryNamespace(uri));
 
-        possibleTapestryComponent(state, null, path + "/" + reader.getLocalName());
+        possibleTapestryComponent(state, null, path + "/" + tokenStream.getLocalName());
     }
 
     /**
      * @param elementName
-     * @param identifiedType the type of the element, usually null, but may be the component type derived from element
+     * @param identifiedType
+     *            the type of the element, usually null, but may be the
+     *            component type derived from element
      */
-    private void possibleTapestryComponent(TemplateParserState state, String elementName, String identifiedType)
-            throws XMLStreamException
+    private void possibleTapestryComponent(TemplateParserState state, String elementName,
+            String identifiedType)
     {
         String id = null;
         String type = identifiedType;
         String mixins = null;
 
-        int count = reader.getAttributeCount();
+        int count = tokenStream.getAttributeCount();
 
         Location location = getLocation();
 
@@ -662,19 +680,21 @@
 
         for (int i = 0; i < count; i++)
         {
-            QName qname = reader.getAttributeName(i);
+            QName qname = tokenStream.getAttributeName(i);
 
-            if (isXMLSpaceAttribute(qname)) continue;
+            if (isXMLSpaceAttribute(qname))
+                continue;
 
             // The name will be blank for an xmlns: attribute
 
             String localName = qname.getLocalPart();
 
-            if (InternalUtils.isBlank(localName)) continue;
+            if (InternalUtils.isBlank(localName))
+                continue;
 
             String uri = qname.getNamespaceURI();
 
-            String value = reader.getAttributeValue(i);
+            String value = tokenStream.getAttributeValue(i);
 
             if (TAPESTRY_SCHEMA_URIS.contains(uri))
             {
@@ -699,20 +719,23 @@
                     continue;
                 }
 
-                // Anything else is the name of a Tapestry component parameter that is simply
-                // not part of the template's doctype for the element being instrumented.
+                // Anything else is the name of a Tapestry component parameter
+                // that is simply
+                // not part of the template's doctype for the element being
+                // instrumented.
             }
 
-
             attributeTokens.add(new AttributeToken(uri, localName, value, location));
         }
 
         boolean isComponent = (id != null || type != null);
 
-        // If provided t:mixins but not t:id or t:type, then its not quite a component
+        // If provided t:mixins but not t:id or t:type, then its not quite a
+        // component
 
         if (mixins != null && !isComponent)
-            throw new TapestryException(ServicesMessages.mixinsInvalidWithoutIdOrType(elementName), location, null);
+            throw new TapestryException(ServicesMessages.mixinsInvalidWithoutIdOrType(elementName),
+                    location, null);
 
         if (isComponent)
         {
@@ -720,7 +743,8 @@
         }
         else
         {
-            tokenAccumulator.add(new StartElementToken(reader.getNamespaceURI(), elementName, location));
+            tokenAccumulator.add(new StartElementToken(tokenStream.getNamespaceURI(), elementName,
+                    location));
         }
 
         addDefineNamespaceTokens();
@@ -735,33 +759,36 @@
 
     private void addDefineNamespaceTokens()
     {
-        for (int i = 0; i < reader.getNamespaceCount(); i++)
+        for (int i = 0; i < tokenStream.getNamespaceCount(); i++)
         {
-            String uri = reader.getNamespaceURI(i);
+            String uri = tokenStream.getNamespaceURI(i);
 
-            // These URIs are strictly part of the server-side Tapestry template and are not ever sent to the client.
+            // These URIs are strictly part of the server-side Tapestry template
+            // and are not ever sent to the client.
 
-            if (TAPESTRY_SCHEMA_URIS.contains(uri)) continue;
+            if (TAPESTRY_SCHEMA_URIS.contains(uri))
+                continue;
 
-            if (uri.equals(TAPESTRY_PARAMETERS_URI)) continue;
+            if (uri.equals(TAPESTRY_PARAMETERS_URI))
+                continue;
 
-            if (uri.startsWith(LIB_NAMESPACE_URI_PREFIX)) continue;
+            if (uri.startsWith(LIB_NAMESPACE_URI_PREFIX))
+                continue;
 
-            tokenAccumulator.add(new DefineNamespacePrefixToken(uri, reader.getNamespacePrefix(i),
-                                                                getLocation()));
+            tokenAccumulator.add(new DefineNamespacePrefixToken(uri, tokenStream
+                    .getNamespacePrefix(i), getLocation()));
         }
     }
 
-
     private TemplateParserState checkForXMLSpaceAttribute(TemplateParserState state)
     {
-        for (int i = 0; i < reader.getAttributeCount(); i++)
+        for (int i = 0; i < tokenStream.getAttributeCount(); i++)
         {
-            QName qName = reader.getAttributeName(i);
+            QName qName = tokenStream.getAttributeName(i);
 
             if (isXMLSpaceAttribute(qName))
             {
-                boolean compress = !"preserve".equals(reader.getAttributeValue(i));
+                boolean compress = !"preserve".equals(tokenStream.getAttributeValue(i));
 
                 return state.compressWhitespace(compress);
             }
@@ -781,15 +808,17 @@
     }
 
     /**
-     * Handler for Tapestry 5.0's "classic" &lt;t:parameter&gt; element. This turns into a {@link
-     * org.apache.tapestry5.internal.parser.ParameterToken} and the body and end element are provided normally.
+     * Handler for Tapestry 5.0's "classic" &lt;t:parameter&gt; element. This
+     * turns into a {@link org.apache.tapestry5.internal.parser.ParameterToken}
+     * and the body and end element are provided normally.
      */
-    private void classicParameter(TemplateParserState state) throws XMLStreamException
+    private void classicParameter(TemplateParserState state)
     {
         String parameterName = getSingleParameter("name");
 
         if (InternalUtils.isBlank(parameterName))
-            throw new TapestryException(ServicesMessages.parameterElementNameRequired(), getLocation(), null);
+            throw new TapestryException(ServicesMessages.parameterElementNameRequired(),
+                    getLocation(), null);
 
         ensureParameterWithinComponent(state);
 
@@ -801,64 +830,68 @@
     private void ensureParameterWithinComponent(TemplateParserState state)
     {
         if (!state.isInsideComponent())
-            throw new RuntimeException("Block parameters are only allowed directly within component elements.");
+            throw new RuntimeException(
+                    "Block parameters are only allowed directly within component elements.");
     }
 
     /**
-     * Tapestry 5.1 uses a special namespace (usually mapped to "p:") and the name becomes the parameter element.
+     * Tapestry 5.1 uses a special namespace (usually mapped to "p:") and the
+     * name becomes the parameter element.
      */
-    private void parameterElement(TemplateParserState state) throws XMLStreamException
+    private void parameterElement(TemplateParserState state)
     {
         ensureParameterWithinComponent(state);
 
-        if (reader.getAttributeCount() > 0)
-            throw new TapestryException(ServicesMessages.parameterElementDoesNotAllowAttributes(), getLocation(),
-                                        null);
+        if (tokenStream.getAttributeCount() > 0)
+            throw new TapestryException(ServicesMessages.parameterElementDoesNotAllowAttributes(),
+                    getLocation(), null);
 
-        tokenAccumulator.add(new ParameterToken(reader.getLocalName(), getLocation()));
+        tokenAccumulator.add(new ParameterToken(tokenStream.getLocalName(), getLocation()));
 
         processBody(state.insideComponent(false));
     }
 
-
     /**
-     * Checks that a body element is empty. Returns after the body's close element. Adds a single body token (but not an
+     * Checks that a body element is empty. Returns after the body's close
+     * element. Adds a single body token (but not an
      * end token).
      */
-    private void body() throws XMLStreamException
+    private void body()
     {
         tokenAccumulator.add(new BodyToken(getLocation()));
 
         while (active)
         {
-            switch (reader.next())
+            switch (tokenStream.next())
             {
                 case END_ELEMENT:
                     return;
 
                 default:
-                    throw new IllegalStateException(ServicesMessages.contentInsideBodyNotAllowed(getLocation()));
+                    throw new IllegalStateException(ServicesMessages
+                            .contentInsideBodyNotAllowed(getLocation()));
             }
         }
     }
 
     /**
-     * Driven by the &lt;t:container&gt; element, this state adds elements for its body but not its start or end tags.
-     *
+     * Driven by the &lt;t:container&gt; element, this state adds elements for
+     * its body but not its start or end tags.
+     * 
      * @param state
-     * @throws XMLStreamException
      */
-    private void container(TemplateParserState state) throws XMLStreamException
+    private void container(TemplateParserState state)
     {
         while (active)
         {
-            switch (reader.next())
+            switch (tokenStream.next())
             {
                 case START_ELEMENT:
                     element(state);
                     break;
 
-                // The matching end-element for the container. Don't add a token.
+                // The matching end-element for the container. Don't add a
+                // token.
 
                 case END_ELEMENT:
 
@@ -873,9 +906,10 @@
     }
 
     /**
-     * A block adds a token for its start tag and end tag and allows any content within.
+     * A block adds a token for its start tag and end tag and allows any content
+     * within.
      */
-    private void block(TemplateParserState state) throws XMLStreamException
+    private void block(TemplateParserState state)
     {
         String blockId = getSingleParameter("id");
 
@@ -890,23 +924,23 @@
     {
         String result = null;
 
-        for (int i = 0; i < reader.getAttributeCount(); i++)
+        for (int i = 0; i < tokenStream.getAttributeCount(); i++)
         {
-            QName qName = reader.getAttributeName(i);
+            QName qName = tokenStream.getAttributeName(i);
 
-            if (isXMLSpaceAttribute(qName)) continue;
+            if (isXMLSpaceAttribute(qName))
+                continue;
 
             if (qName.getLocalPart().equalsIgnoreCase(attributeName))
             {
-                result = reader.getAttributeValue(i);
+                result = tokenStream.getAttributeValue(i);
                 continue;
             }
 
             // Only the named attribute is allowed.
 
-            throw new TapestryException(ServicesMessages.undefinedTapestryAttribute(reader.getLocalName(),
-                                                                                    qName.toString(), attributeName),
-                                        getLocation(), null);
+            throw new TapestryException(ServicesMessages.undefinedTapestryAttribute(tokenStream
+                    .getLocalName(), qName.toString(), attributeName), getLocation(), null);
         }
 
         return result;
@@ -914,9 +948,11 @@
 
     private void validateId(String id, String messageKey)
     {
-        if (id == null) return;
+        if (id == null)
+            return;
 
-        if (ID_PATTERN.matcher(id).matches()) return;
+        if (ID_PATTERN.matcher(id).matches())
+            return;
 
         // Not a match.
 
@@ -925,20 +961,20 @@
 
     private boolean isXMLSpaceAttribute(QName qName)
     {
-        return XML_NAMESPACE_URI.equals(qName.getNamespaceURI()) &&
-                "space".equals(qName.getLocalPart());
+        return XML_NAMESPACE_URI.equals(qName.getNamespaceURI())
+                && "space".equals(qName.getLocalPart());
     }
 
-
     /**
-     * Processes text content if in the correct state, or throws an exception. This is used as a default for matching
+     * Processes text content if in the correct state, or throws an exception.
+     * This is used as a default for matching
      * case statements.
-     *
+     * 
      * @param state
      */
     private void textContent(TemplateParserState state)
     {
-        switch (reader.getEventType())
+        switch (tokenStream.getEventType())
         {
             case COMMENT:
                 comment(state);
@@ -963,23 +999,24 @@
         if (textStartLocation == null)
             textStartLocation = getLocation();
 
-        textBuffer.append(reader.getText());
+        textBuffer.append(tokenStream.getText());
     }
 
     private void cdata(TemplateParserState state)
     {
         processTextBuffer(state);
 
-        tokenAccumulator.add(new CDATAToken(reader.getText(), getLocation()));
+        tokenAccumulator.add(new CDATAToken(tokenStream.getText(), getLocation()));
     }
 
     private void comment(TemplateParserState state)
     {
         processTextBuffer(state);
 
-        // Trim the excess whitespace; the Comment DOM node will add a leading/trailing space.
+        // Trim the excess whitespace; the Comment DOM node will add a
+        // leading/trailing space.
 
-        String comment = reader.getText().trim();
+        String comment = tokenStream.getText().trim();
 
         tokenAccumulator.add(new CommentToken(comment, getLocation()));
     }
@@ -1005,15 +1042,17 @@
         {
             text = compressWhitespaceInText(text);
 
-            if (InternalUtils.isBlank(text)) return;
+            if (InternalUtils.isBlank(text))
+                return;
         }
 
         addTokensForText(text);
     }
 
     /**
-     * Reduces vertical whitespace to a single newline, then reduces horizontal whitespace to a single space.
-     *
+     * Reduces vertical whitespace to a single newline, then reduces horizontal
+     * whitespace to a single space.
+     * 
      * @param text
      * @return compressed version of text
      */
@@ -1025,11 +1064,14 @@
     }
 
     /**
-     * Scans the text, using a regular expression pattern, for expansion patterns, and adds appropriate tokens for what
+     * Scans the text, using a regular expression pattern, for expansion
+     * patterns, and adds appropriate tokens for what
      * it finds.
-     *
-     * @param text to add as {@link org.apache.tapestry5.internal.parser.TextToken}s and {@link
-     *             org.apache.tapestry5.internal.parser.ExpansionToken}s
+     * 
+     * @param text
+     *            to add as
+     *            {@link org.apache.tapestry5.internal.parser.TextToken}s and
+     *            {@link org.apache.tapestry5.internal.parser.ExpansionToken}s
      */
     private void addTokensForText(String text)
     {
@@ -1037,10 +1079,14 @@
 
         int startx = 0;
 
-        // The big problem with all this code is that everything gets assigned to the
-        // start of the text block, even if there are line breaks leading up to it.
-        // That's going to take a lot more work and there are bigger fish to fry.  In addition,
-        // TAPESTRY-2028 means that the whitespace has likely been stripped out of the text
+        // The big problem with all this code is that everything gets assigned
+        // to the
+        // start of the text block, even if there are line breaks leading up to
+        // it.
+        // That's going to take a lot more work and there are bigger fish to
+        // fry. In addition,
+        // TAPESTRY-2028 means that the whitespace has likely been stripped out
+        // of the text
         // already anyway.
 
         while (matcher.find())
@@ -1054,7 +1100,8 @@
                 tokenAccumulator.add(new TextToken(prefix, textStartLocation));
             }
 
-            // Group 1 includes the real text of the expansion, with whitespace around the
+            // Group 1 includes the real text of the expansion, with whitespace
+            // around the
             // expression (but inside the curly braces) excluded.
 
             String expression = matcher.group(1);
@@ -1067,7 +1114,8 @@
         // Catch anything after the final regexp match.
 
         if (startx < text.length())
-            tokenAccumulator.add(new TextToken(text.substring(startx, text.length()), textStartLocation));
+            tokenAccumulator.add(new TextToken(text.substring(startx, text.length()),
+                    textStartLocation));
     }
 
 }

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ServicesMessages.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ServicesMessages.java?rev=889446&r1=889445&r2=889446&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ServicesMessages.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ServicesMessages.java Thu Dec 10 22:38:39 2009
@@ -71,21 +71,11 @@
         return MESSAGES.format("class-not-transformed", className);
     }
 
-    static String newParserError(Resource resource, Throwable cause)
-    {
-        return MESSAGES.format("new-parser-error", resource, cause);
-    }
-
     static String missingTemplateResource(Resource resource)
     {
         return MESSAGES.format("missing-template-resource", resource);
     }
 
-    static String templateParseError(Resource resource, Throwable cause)
-    {
-        return MESSAGES.format("template-parse-error", resource, cause);
-    }
-
     static String contentInsideBodyNotAllowed(Location location)
     {
         return MESSAGES.format("content-inside-body-not-allowed", location);

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/TemplateParserImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/TemplateParserImpl.java?rev=889446&r1=889445&r2=889446&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/TemplateParserImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/TemplateParserImpl.java Thu Dec 10 22:38:39 2009
@@ -14,54 +14,35 @@
 
 package org.apache.tapestry5.internal.services;
 
+import java.net.URL;
+import java.util.Map;
+
 import org.apache.tapestry5.SymbolConstants;
 import org.apache.tapestry5.internal.parser.ComponentTemplate;
 import org.apache.tapestry5.ioc.Resource;
 import org.apache.tapestry5.ioc.annotations.Symbol;
 import org.apache.tapestry5.ioc.internal.util.InternalUtils;
-import org.codehaus.stax2.XMLInputFactory2;
-
-import javax.xml.stream.XMLInputFactory;
-import javax.xml.stream.XMLResolver;
-import javax.xml.stream.XMLStreamException;
-import java.io.IOException;
-import java.net.URL;
-import java.util.Map;
 
 /**
- * Responsible for acquiring a StAX reader and configuring an instance of {@link org.apache.tapestry5.internal.services.StaxTemplateParser},
- * which does all the real work. This is dependent on a few features of StAX2, and therefore, on the Woodstock StAX
- * parser.
- *
+ * Parses Tapestry XML template files into {@link ComponentTemplate} instances.
+ * A new instance of {@link SaxTemplateParser} is created for each document
+ * parsed.
+ * 
  * @since 5.1.0.0
  */
-public class TemplateParserImpl implements TemplateParser, XMLResolver
+public class TemplateParserImpl implements TemplateParser
 {
     private final Map<String, URL> configuration;
 
     private final boolean defaultCompressWhitespace;
 
-    private final XMLInputFactory2 inputFactory = (XMLInputFactory2) XMLInputFactory2.newInstance();
-
     public TemplateParserImpl(Map<String, URL> configuration,
 
-                              @Symbol(SymbolConstants.COMPRESS_WHITESPACE)
-                              boolean defaultCompressWhitespace)
+    @Symbol(SymbolConstants.COMPRESS_WHITESPACE)
+    boolean defaultCompressWhitespace)
     {
-
         this.configuration = configuration;
         this.defaultCompressWhitespace = defaultCompressWhitespace;
-
-        inputFactory.configureForSpeed();
-
-        inputFactory.setXMLResolver(this);
-
-        // Coalescing must be off, or CDATA sections can "coealesce" into CHARACTER events
-        inputFactory.setProperty(XMLInputFactory.IS_COALESCING, false);
-
-        inputFactory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, true);
-
-        inputFactory.setProperty(XMLInputFactory.SUPPORT_DTD, true);
     }
 
     public ComponentTemplate parseTemplate(Resource templateResource)
@@ -69,43 +50,8 @@
         if (!templateResource.exists())
             throw new RuntimeException(ServicesMessages.missingTemplateResource(templateResource));
 
-
-        StaxTemplateParser parser;
-
-        try
-        {
-            parser = new StaxTemplateParser(templateResource, inputFactory);
-        }
-        catch (Exception ex)
-        {
-            throw new RuntimeException(ServicesMessages.newParserError(templateResource, ex), ex);
-        }
-
-        return parser.parse(defaultCompressWhitespace);
+        return new SaxTemplateParser(templateResource, configuration)
+                .parse(defaultCompressWhitespace);
     }
 
-    // XMLResolver methods
-
-    public Object resolveEntity(String publicID,
-                                String systemID,
-                                String baseURI,
-                                String namespace) throws XMLStreamException
-    {
-        URL url = configuration.get(publicID);
-
-        try
-        {
-            if (url != null)
-                return url.openStream();
-        }
-        catch (IOException ex)
-        {
-            throw new XMLStreamException(
-                    String.format("Unable to open stream for resource %s: %s",
-                                  url,
-                                  InternalUtils.toMessage(ex)), ex);
-        }
-
-        return null;
-    }
 }

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/TemplateParserState.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/TemplateParserState.java?rev=889446&r1=889445&r2=889446&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/TemplateParserState.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/TemplateParserState.java Thu Dec 10 22:38:39 2009
@@ -15,7 +15,7 @@
 package org.apache.tapestry5.internal.services;
 
 /**
- * Used to track behaviors inside {@link org.apache.tapestry5.internal.services.StaxTemplateParser}. Internal state is
+ * Used to track behaviors inside {@link org.apache.tapestry5.internal.services.SaxTemplateParser}. Internal state is
  * immutable, the set-like methods return a new immutable instance.
  *
  * @since 5.1.0.0

Added: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/XMLToken.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/XMLToken.java?rev=889446&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/XMLToken.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/XMLToken.java Thu Dec 10 22:38:39 2009
@@ -0,0 +1,49 @@
+// Copyright 2009 The Apache Software Foundation
+//
+// Licensed 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.
+
+package org.apache.tapestry5.internal.services;
+
+import java.util.List;
+
+import org.apache.tapestry5.ioc.BaseLocatable;
+import org.apache.tapestry5.ioc.Location;
+
+/**
+ * A token parsed from an XML file, used when parsing templates.
+ * 
+ * @since 5.2.0
+ */
+class XMLToken extends BaseLocatable
+{
+    final XMLTokenType type;
+
+    DTDData dtdData;
+
+    String uri, localName, qName;
+
+    List<AttributeInfo> attributes;
+
+    List<NamespaceMapping> namespaceMappings;
+
+    // COMMENT, CDATA, CHARACTERS, WHITESPACE
+    String text;
+
+    XMLToken(XMLTokenType type, Location location)
+    {
+        super(location);
+
+        this.type = type;
+    }
+
+}

Propchange: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/XMLToken.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/XMLTokenStream.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/XMLTokenStream.java?rev=889446&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/XMLTokenStream.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/XMLTokenStream.java Thu Dec 10 22:38:39 2009
@@ -0,0 +1,412 @@
+// Copyright 2009 The Apache Software Foundation
+//
+// Licensed 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.
+
+package org.apache.tapestry5.internal.services;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import javax.xml.namespace.QName;
+
+import org.apache.tapestry5.ioc.Location;
+import org.apache.tapestry5.ioc.Resource;
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+import org.apache.tapestry5.ioc.internal.util.InternalUtils;
+import org.apache.tapestry5.ioc.internal.util.LocationImpl;
+import org.apache.tapestry5.ioc.internal.util.TapestryException;
+import org.xml.sax.Attributes;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.EntityResolver;
+import org.xml.sax.InputSource;
+import org.xml.sax.Locator;
+import org.xml.sax.SAXException;
+import org.xml.sax.XMLReader;
+import org.xml.sax.ext.LexicalHandler;
+import org.xml.sax.helpers.XMLReaderFactory;
+
+/** Parses a document as a stream of XML tokens */
+public class XMLTokenStream
+{
+    private final class SaxHandler implements LexicalHandler, EntityResolver, ContentHandler
+    {
+        private Locator locator;
+
+        private int currentLine = -1;
+
+        private Location cachedLocation;
+
+        private Location textLocation;
+
+        private final StringBuilder builder = new StringBuilder();
+
+        private boolean inCDATA, insideDTD;
+
+        private List<NamespaceMapping> namespaceMappings = CollectionFactory.newList();
+
+        private Location getLocation()
+        {
+            int line = locator.getLineNumber();
+
+            if (currentLine != line)
+                cachedLocation = null;
+
+            if (cachedLocation == null)
+            {
+                cachedLocation = new LocationImpl(resource, line);
+            }
+
+            return cachedLocation;
+        }
+
+        private XMLToken add(XMLTokenType type)
+        {
+            XMLToken token = new XMLToken(type, getLocation());
+
+            tokens.add(token);
+
+            return token;
+        }
+
+        public InputSource resolveEntity(String publicId, String systemId) throws SAXException,
+                IOException
+        {
+            URL url = publicIdToURL.get(publicId);
+
+            try
+            {
+                if (url != null)
+                    return new InputSource(url.openStream());
+            }
+            catch (IOException ex)
+            {
+                throw new SAXException(String.format("Unable to open stream for resource %s: %s",
+                        url, InternalUtils.toMessage(ex)), ex);
+            }
+
+            return null;
+        }
+
+        public void comment(char[] ch, int start, int length) throws SAXException
+        {
+            if (insideDTD)
+                return;
+
+            // TODO: Coalesce?
+            add(XMLTokenType.COMMENT).text = new String(ch, start, length);
+        }
+
+        public void startCDATA() throws SAXException
+        {
+            // TODO: Flush characters?
+
+            inCDATA = true;
+        }
+
+        public void endCDATA() throws SAXException
+        {
+            if (builder.length() != 0)
+            {
+                add(XMLTokenType.CDATA).text = builder.toString();
+            }
+
+            builder.setLength(0);
+            inCDATA = false;
+        }
+
+        public void characters(char[] ch, int start, int length) throws SAXException
+        {
+            if (inCDATA)
+            {
+                builder.append(ch, start, length);
+                return;
+            }
+
+            XMLToken token = new XMLToken(XMLTokenType.CHARACTERS, textLocation);
+            token.text = new String(ch, start, length);
+
+            tokens.add(token);
+        }
+
+        public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException
+        {
+        }
+
+        public void startDTD(final String name, final String publicId, final String systemId)
+                throws SAXException
+        {
+            insideDTD = true;
+
+            DTDData data = new DTDData()
+            {
+
+                public String getSystemId()
+                {
+                    return systemId;
+
+                }
+
+                public String getRootName()
+                {
+                    return name;
+                }
+
+                public String getPublicId()
+                {
+                    return publicId;
+                }
+            };
+
+            add(XMLTokenType.DTD).dtdData = data;
+        }
+
+        public void endDocument() throws SAXException
+        {
+            add(XMLTokenType.END_DOCUMENT);
+        }
+
+        public void endElement(String uri, String localName, String qName) throws SAXException
+        {
+            add(XMLTokenType.END_ELEMENT);
+        }
+
+        public void setDocumentLocator(Locator locator)
+        {
+            this.locator = locator;
+        }
+
+        public void startElement(String uri, String localName, String qName, Attributes attributes)
+                throws SAXException
+        {
+            XMLToken token = add(XMLTokenType.START_ELEMENT);
+
+            token.uri = uri;
+            token.localName = localName;
+            token.qName = qName;
+
+            // The XML parser tends to reuse the same Attributes object, so
+            // capture the data out of it.
+
+            if (attributes.getLength() == 0)
+            {
+                token.attributes = Collections.emptyList();
+            }
+            else
+            {
+                token.attributes = CollectionFactory.newList();
+
+                for (int i = 0; i < attributes.getLength(); i++)
+                {
+                    String prefixedName = attributes.getQName(i);
+
+                    int lastColon = prefixedName.lastIndexOf(':');
+
+                    String prefix = lastColon > 0 ? prefixedName.substring(0, lastColon) : "";
+
+                    QName qname = new QName(attributes.getURI(i), attributes.getLocalName(i),
+                            prefix);
+
+                    token.attributes.add(new AttributeInfo(qname, attributes.getValue(i)));
+                }
+            }
+
+            token.namespaceMappings = CollectionFactory.newList(namespaceMappings);
+
+            namespaceMappings.clear();
+
+            // Any text collected starts here as well:
+
+            textLocation = getLocation();
+        }
+
+        public void startPrefixMapping(String prefix, String uri) throws SAXException
+        {
+            namespaceMappings.add(new NamespaceMapping(prefix, uri));
+        }
+
+        public void endDTD() throws SAXException
+        {
+            insideDTD = false;
+        }
+
+        public void endEntity(String name) throws SAXException
+        {
+        }
+
+        public void startEntity(String name) throws SAXException
+        {
+        }
+
+        public void endPrefixMapping(String prefix) throws SAXException
+        {
+        }
+
+        public void processingInstruction(String target, String data) throws SAXException
+        {
+        }
+
+        public void skippedEntity(String name) throws SAXException
+        {
+        }
+
+        public void startDocument() throws SAXException
+        {
+        }
+    }
+
+    private int cursor = -1;
+
+    private final List<XMLToken> tokens = CollectionFactory.newList();
+
+    private final Resource resource;
+
+    private final Map<String, URL> publicIdToURL;
+
+    private Location exceptionLocation;
+
+    public XMLTokenStream(Resource resource, Map<String, URL> publicIdToURL)
+    {
+        this.resource = resource;
+        this.publicIdToURL = publicIdToURL;
+    }
+
+    public void parse() throws SAXException, IOException
+    {
+        SaxHandler handler = new SaxHandler();
+
+        XMLReader reader = XMLReaderFactory.createXMLReader();
+
+        reader.setContentHandler(handler);
+        reader.setEntityResolver(handler);
+        reader.setProperty("http://xml.org/sax/properties/lexical-handler", handler);
+
+        InputStream stream = resource.openStream();
+
+        try
+        {
+            reader.parse(new InputSource(stream));
+        }
+        catch (IOException ex)
+        {
+            this.exceptionLocation = handler.getLocation();
+
+            throw ex;
+        }
+        catch (SAXException ex)
+        {
+            this.exceptionLocation = handler.getLocation();
+
+            throw ex;
+        }
+        catch (RuntimeException ex)
+        {
+            this.exceptionLocation = handler.getLocation();
+
+            throw ex;
+        }
+        finally
+        {
+            InternalUtils.close(stream);
+        }
+    }
+
+    private XMLToken token()
+    {
+        return tokens.get(cursor);
+    }
+
+    /**
+     * Returns the type of the next token.
+     */
+    public XMLTokenType next()
+    {
+        cursor++;
+
+        // TODO: Check for overflow?
+
+        return getEventType();
+    }
+
+    public int getAttributeCount()
+    {
+        return token().attributes.size();
+    }
+
+    public QName getAttributeName(int i)
+    {
+        return token().attributes.get(i).attributeName;
+    }
+
+    public DTDData getDTDInfo()
+    {
+        return token().dtdData;
+    }
+
+    public XMLTokenType getEventType()
+    {
+        return token().type;
+    }
+
+    public String getLocalName()
+    {
+        return token().localName;
+    }
+
+    public Location getLocation()
+    {
+        if (exceptionLocation != null)
+            return exceptionLocation;
+
+        return token().getLocation();
+    }
+
+    public int getNamespaceCount()
+    {
+        return token().namespaceMappings.size();
+    }
+
+    public String getNamespacePrefix(int i)
+    {
+        return token().namespaceMappings.get(i).prefix;
+    }
+
+    public String getNamespaceURI()
+    {
+        return token().uri;
+    }
+
+    public String getNamespaceURI(int i)
+    {
+        return token().namespaceMappings.get(i).uri;
+    }
+
+    public String getText()
+    {
+        return token().text;
+    }
+
+    public boolean hasNext()
+    {
+        return cursor < tokens.size() - 1;
+    }
+
+    public String getAttributeValue(int i)
+    {
+        return token().attributes.get(i).value;
+    }
+
+}

Propchange: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/XMLTokenStream.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/XMLTokenType.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/XMLTokenType.java?rev=889446&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/XMLTokenType.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/XMLTokenType.java Thu Dec 10 22:38:39 2009
@@ -0,0 +1,25 @@
+// Copyright 2009 The Apache Software Foundation
+//
+// Licensed 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.
+
+package org.apache.tapestry5.internal.services;
+
+/**
+ * Identifies type of {@link XMLToken}.
+ * 
+ * @since 5.2.0
+ */
+enum XMLTokenType
+{
+    DTD, START_ELEMENT, END_ELEMENT, END_DOCUMENT, COMMENT, SPACE, CHARACTERS, CDATA, ENTITY_REFERENCE, ATTRIBUTE, NAMESPACE, NOTATION_DECLARATION, ENTITY_DECLARATION
+}

Propchange: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/XMLTokenType.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/services/ServicesStrings.properties
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/services/ServicesStrings.properties?rev=889446&r1=889445&r2=889446&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/services/ServicesStrings.properties (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/services/ServicesStrings.properties Thu Dec 10 22:38:39 2009
@@ -21,9 +21,7 @@
 field-already-claimed=Field %s of class %s is already claimed by %s and can not be claimed by %s.
 no-declared-method=Class %s does not declare method '%s'.
 class-not-transformed=Class %s was not transformed for use as a component; this can happen if it is an interface, or was not in a package subject to component transformation.
-new-parser-error=Failure obtaining a SAX parser for resource %s: %s
 missing-template-resource=Template resource %s does not exist.
-template-parse-error=Failure parsing template %s: %s
 content-inside-body-not-allowed=Content inside a Tapestry body element is not allowed (at %s). The content has been ignored.
 method-compile-error=Error compiling method %s (%s): %s
 render-queue-error=Render queue error in %s: %s