You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tapestry.apache.org by hl...@apache.org on 2007/01/03 22:41:46 UTC

svn commit: r492313 - in /tapestry/tapestry5/tapestry-core/trunk/src: main/java/org/apache/tapestry/internal/parser/ main/java/org/apache/tapestry/internal/services/ main/java/org/apache/tapestry/internal/test/ main/java/org/apache/tapestry/services/ m...

Author: hlship
Date: Wed Jan  3 13:41:45 2007
New Revision: 492313

URL: http://svn.apache.org/viewvc?view=rev&rev=492313
Log:
Remove ClasspathAssetSource, moving its functionality to AssetSource.
Allow for "invisibile instrumentation" inside component templates.
Allow page ("root component") templates to be stored in the web application root.

Added:
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageTemplateLocator.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageTemplateLocatorImpl.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/pagelevel/PageTesterContext.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/app1/SimpleForm.html
      - copied, changed from r491920, tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/integration/app1/pages/SimpleForm.html
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/PageTemplateLocatorImplTest.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/internal/services/instrumented_element.html
    tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/internal/services/mixin_requires_id_or_type.html
    tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/internal/services/unexpected_attribute_in_instrumented_element.html
Removed:
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ClasspathAssetSource.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ClasspathAssetSourceImpl.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/integration/app1/pages/SimpleForm.html
Modified:
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/parser/StartComponentToken.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/AssetSourceImpl.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentTemplateSourceImpl.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InjectStandardStylesheetCommand.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalModule.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageLoaderImpl.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ServicesMessages.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/StaticFilesFilter.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/TemplateParserImpl.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/test/InternalBaseTestCase.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/AssetSource.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/TapestryModule.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/TapestryTestCase.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/pagelevel/PageTester.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/internal/services/ServicesStrings.properties
    tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/templates.apt
    tapestry/tapestry5/tapestry-core/trunk/src/site/apt/index.apt
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/IntegrationTests.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/AssetSourceImplTest.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentTemplateSourceImplTest.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/InjectStandardStylesheetCommandTest.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/PageLoaderImplTest.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/TemplateParserImplTest.java

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/parser/StartComponentToken.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/parser/StartComponentToken.java?view=diff&rev=492313&r1=492312&r2=492313
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/parser/StartComponentToken.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/parser/StartComponentToken.java Wed Jan  3 13:41:45 2007
@@ -12,106 +12,118 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package org.apache.tapestry.internal.parser;
-
+package org.apache.tapestry.internal.parser;
+
 import org.apache.tapestry.ioc.Location;
-
-/**
- * The start element of a component within the template. Will be followed by a series of
- * {@link org.apache.tapestry.internal.parser.AttributeToken}s for any attributes (outside of id
- * and type), and eventually will be balanced by an
- * {@link org.apache.tapestry.internal.parser.EndElementToken}.
- */
-public class StartComponentToken extends TemplateToken
-{
-    private final String _id;
-
-    private final String _type;
-
-    private final String _mixins;
-
-    /**
-     * @param id
-     *            the id of the component (may be null for anonymous components)
-     * @param type
-     *            the type of component (may be null if the component type is specified outside the
-     *            template)
-     * @param mixins
-     *            a comma-separated list of mixins (possibly null)
-     * @param location
-     *            the location within the template at which the element was parsed
-     */
-    public StartComponentToken(String id, String type, String mixins, Location location)
-    {
-        super(TokenType.START_COMPONENT, location);
-
-        // TODO: id or type may be null, but not both!
-
-        _id = id;
-        _type = type;
-        _mixins = mixins;
-    }
-
-    /**
-     * Returns a non-blank id if one was provided in the template. If the id attribute was missing
-     * (or the value was blank), returns null.
-     */
-    public String getId()
-    {
-        return _id;
-    }
-
-    /**
-     * Returns a non-blank component type if one was provided in the template. If the type attribute
-     * was missing (or the value was blank), returns null.
-     */
-    public String getType()
-    {
-        return _type;
-    }
-
-    @Override
-    public String toString()
-    {
-        StringBuilder builder = new StringBuilder("StartComponentToken[");
-
-        boolean first = true;
-
-        if (_id != null)
-        {
-            builder.append("id=");
-            builder.append(_id);
-            first = false;
-        }
-
-        if (_type != null)
-        {
-            if (!first)
-                builder.append(" ");
-            builder.append("type=");
-            builder.append(_type);
-            first = false;
-        }
-
-        if (_mixins != null)
-        {
-            if (!first)
-                builder.append(" ");
-            builder.append("mixins=");
-            builder.append(_mixins);
-        }
-
-        builder.append("]");
-
-        return builder.toString();
-    }
-
-    /**
-     * Returns the list of mixins for this component instance, or null for no mixins.
-     */
-    public String getMixins()
-    {
-        return _mixins;
-    }
-
-}
+
+/**
+ * The start element of a component within the template. Will be followed by a series of
+ * {@link org.apache.tapestry.internal.parser.AttributeToken}s for any attributes (outside of id
+ * and type), and eventually will be balanced by an
+ * {@link org.apache.tapestry.internal.parser.EndElementToken}.
+ */
+public class StartComponentToken extends TemplateToken
+{
+    private final String _element;
+
+    private final String _id;
+
+    private final String _type;
+
+    private final String _mixins;
+
+    /**
+     * @param element
+     *            the name of the element from which this component was parsed, or null if the
+     *            element was the t:comp placeholder
+     * @param id
+     *            the id of the component (may be null for anonymous components)
+     * @param type
+     *            the type of component (may be null if the component type is specified outside the
+     *            template)
+     * @param mixins
+     *            a comma-separated list of mixins (possibly null)
+     * @param location
+     *            the location within the template at which the element was parsed
+     */
+    public StartComponentToken(String element, String id, String type, String mixins,
+            Location location)
+    {
+        super(TokenType.START_COMPONENT, location);
+
+        // TODO: id or type may be null, but not both!
+
+        _element = element;
+        _id = id;
+        _type = type;
+        _mixins = mixins;
+    }
+
+    /**
+     * Returns the element for this component. When using the <t:comp> placeholder, this value
+     * will be null. When using "invisible instrumentation", where t:id or t:type attributes are
+     * added to existing elements, this is the local name of the element so attached.
+     * 
+     * @return the element name or null
+     */
+    public String getElement()
+    {
+        return _element;
+    }
+
+    /**
+     * Returns a non-blank id if one was provided in the template. If the id attribute was missing
+     * (or the value was blank), returns null.
+     */
+    public String getId()
+    {
+        return _id;
+    }
+
+    /**
+     * Returns a non-blank component type if one was provided in the template. If the type attribute
+     * was missing (or the value was blank), returns null.
+     */
+    public String getType()
+    {
+        return _type;
+    }
+
+    @Override
+    public String toString()
+    {
+        StringBuilder builder = new StringBuilder();
+
+        add(builder, "element", _element);
+        add(builder, "id", _id);
+        add(builder, "type", _type);
+        add(builder, "mixins", _mixins);
+
+        builder.insert(0, "STartComponentToken[");
+        builder.append("]");
+
+        return builder.toString();
+    }
+
+    private void add(StringBuilder builder, String label, String value)
+    {
+        if (value == null)
+            return;
+
+        if (builder.length() > 0)
+            builder.append(" ");
+
+        builder.append(label);
+        builder.append("=");
+        builder.append(value);
+    }
+
+    /**
+     * Returns the list of mixins for this component instance, or null for no mixins.
+     */
+    public String getMixins()
+    {
+        return _mixins;
+    }
+
+}

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/AssetSourceImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/AssetSourceImpl.java?view=diff&rev=492313&r1=492312&r2=492313
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/AssetSourceImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/AssetSourceImpl.java Wed Jan  3 13:41:45 2007
@@ -16,6 +16,8 @@
 
 import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newMap;
 import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newThreadSafeMap;
+import static org.apache.tapestry.ioc.internal.util.Defense.notBlank;
+import static org.apache.tapestry.ioc.internal.util.Defense.notNull;
 
 import java.util.Locale;
 import java.util.Map;
@@ -57,8 +59,19 @@
         _registry = StrategyRegistry.newInstance(AssetFactory.class, byResourceClass);
     }
 
+    public Asset getClasspathAsset(String path, Locale locale)
+    {
+        Resource baseResource = _prefixToRootResource.get("classpath");
+
+        return findAsset(baseResource, path, locale);
+    }
+
     public Asset findAsset(Resource baseResource, String path, Locale locale)
     {
+        notNull(baseResource, "baseResource");
+        notBlank(path, "path");
+        notNull(locale, "locale");
+
         int colonx = path.indexOf(':');
 
         if (colonx < 0)

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentTemplateSourceImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentTemplateSourceImpl.java?view=diff&rev=492313&r1=492312&r2=492313
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentTemplateSourceImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentTemplateSourceImpl.java Wed Jan  3 13:41:45 2007
@@ -29,7 +29,6 @@
 import org.apache.tapestry.internal.util.MultiKey;
 import org.apache.tapestry.internal.util.URLChangeTracker;
 import org.apache.tapestry.ioc.Resource;
-import org.apache.tapestry.ioc.internal.util.ClasspathResource;
 import org.apache.tapestry.model.ComponentModel;
 
 /**
@@ -38,10 +37,13 @@
 public final class ComponentTemplateSourceImpl extends InvalidationEventHubImpl implements
         ComponentTemplateSource, UpdateListener
 {
-    private final ClassLoader _loader;
 
     private final TemplateParser _parser;
 
+    private final PageTemplateLocator _locator;
+
+    private final URLChangeTracker _tracker;
+
     /**
      * Caches from a key (combining component name and locale) to a resource. Often, many different
      * keys will point to the same resource (i.e., "foo:en_US", "foo:en_UK", and "foo:en" may all be
@@ -55,8 +57,6 @@
      */
     private final Map<Resource, ComponentTemplate> _templates = newThreadSafeMap();
 
-    private final URLChangeTracker _tracker;
-
     private final ComponentTemplate _missingTemplate = new ComponentTemplate()
     {
         public Set<String> getComponentIds()
@@ -80,20 +80,16 @@
         }
     };
 
-    public ComponentTemplateSourceImpl(TemplateParser parser)
-    {
-        this(Thread.currentThread().getContextClassLoader(), parser);
-    }
-
-    ComponentTemplateSourceImpl(ClassLoader loader, TemplateParser parser)
+    public ComponentTemplateSourceImpl(TemplateParser parser, PageTemplateLocator locator)
     {
-        this(loader, parser, new URLChangeTracker());
+        this(parser, locator, new URLChangeTracker());
     }
 
-    ComponentTemplateSourceImpl(ClassLoader loader, TemplateParser parser, URLChangeTracker tracker)
+    ComponentTemplateSourceImpl(TemplateParser parser, PageTemplateLocator locator,
+            URLChangeTracker tracker)
     {
-        _loader = loader;
         _parser = parser;
+        _locator = locator;
         _tracker = tracker;
     }
 
@@ -167,6 +163,14 @@
             if (localized != null)
                 return localized;
 
+            // Not on the classpath, the the locator see if its a) a page and b) a resource inside
+            // the context
+
+            localized = _locator.findPageTemplateResource(model, locale);
+
+            if (localized != null)
+                return localized;
+
             // Otherwise, this component doesn't have its own template ... lets work up to its
             // base class and check there.
 
@@ -181,13 +185,7 @@
 
     private Resource baseResourceForModel(ComponentModel model)
     {
-        String componentName = model.getComponentClassName();
-
-        // TODO: Currently hard-coded to a ".html" extension!
-
-        String path = componentName.replace('.', '/') + ".html";
-
-        return new ClasspathResource(_loader, path);
+        return model.getBaseResource().withExtension("html");
     }
 
     /**

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InjectStandardStylesheetCommand.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InjectStandardStylesheetCommand.java?view=diff&rev=492313&r1=492312&r2=492313
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InjectStandardStylesheetCommand.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InjectStandardStylesheetCommand.java Wed Jan  3 13:41:45 2007
@@ -18,6 +18,7 @@
 import org.apache.tapestry.dom.Document;
 import org.apache.tapestry.dom.Element;
 import org.apache.tapestry.ioc.services.ThreadLocale;
+import org.apache.tapestry.services.AssetSource;
 import org.apache.tapestry.services.Environment;
 import org.apache.tapestry.services.PageRenderCommand;
 
@@ -29,13 +30,13 @@
 {
     private final ThreadLocale _threadLocale;
 
-    private final ClasspathAssetSource _classpathAssetSource;
+    private final AssetSource _assetSource;
 
     public InjectStandardStylesheetCommand(ThreadLocale threadLocale,
-            ClasspathAssetSource classpathAssetSource)
+            AssetSource classpathAssetSource)
     {
         _threadLocale = threadLocale;
-        _classpathAssetSource = classpathAssetSource;
+        _assetSource = classpathAssetSource;
     }
 
     public void setup(Environment environment)
@@ -51,7 +52,7 @@
         if (head == null)
             return;
 
-        Asset asset = _classpathAssetSource.getClasspathAsset(
+        Asset asset = _assetSource.getClasspathAsset(
                 "org/apache/tapestry/default.css",
                 _threadLocale.getLocale());
 

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalModule.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalModule.java?view=diff&rev=492313&r1=492312&r2=492313
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalModule.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalModule.java Wed Jan  3 13:41:45 2007
@@ -50,7 +50,6 @@
 import org.apache.tapestry.services.ApplicationInitializer;
 import org.apache.tapestry.services.ApplicationInitializerFilter;
 import org.apache.tapestry.services.AssetFactory;
-import org.apache.tapestry.services.AssetSource;
 import org.apache.tapestry.services.Binding;
 import org.apache.tapestry.services.BindingFactory;
 import org.apache.tapestry.services.BindingSource;
@@ -141,9 +140,10 @@
     }
 
     public ComponentTemplateSource buildComponentTemplateSource(@InjectService("TemplateParser")
-    TemplateParser parser)
+    TemplateParser parser, @InjectService("PageTemplateLocator")
+    PageTemplateLocator locator)
     {
-        ComponentTemplateSourceImpl service = new ComponentTemplateSourceImpl(parser);
+        ComponentTemplateSourceImpl service = new ComponentTemplateSourceImpl(parser, locator);
 
         _updateListenerHub.addUpdateListener(service);
 
@@ -531,12 +531,10 @@
         return new ResourceStreamerImpl(_response);
     }
 
-    public AssetFactory buildContextAssetFactory(@Inject("service:tapestry.ApplicationGlobals")
+    public AssetFactory buildContextAssetFactory(@Inject("infrastructure:ApplicationGlobals")
     ApplicationGlobals globals)
     {
-        ContextAssetFactory factory = new ContextAssetFactory(_request, globals.getContext());
-
-        return factory;
+        return new ContextAssetFactory(_request, globals.getContext());
     }
 
     public AssetFactory buildClasspathAssetFactory(@InjectService("ResourceCache")
@@ -583,11 +581,12 @@
         return _request;
     }
 
-    public static ClasspathAssetSource buildClasspathAssetSource(
-            @InjectService("ClasspathAssetFactory")
-            AssetFactory classpathAssetFactory, @Inject("infrastructure:AssetSource")
-            AssetSource assetSource)
+    public PageTemplateLocator buildPageTemplateLocator(@InjectService("ContextAssetFactory")
+    AssetFactory contextAssetFactory, @Inject("infrastructure:ComponentClassResolver")
+    ComponentClassResolver componentClassResolver)
     {
-        return new ClasspathAssetSourceImpl(classpathAssetFactory.getRootResource(), assetSource);
+        return new PageTemplateLocatorImpl(contextAssetFactory.getRootResource(),
+                componentClassResolver);
     }
+
 }

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageLoaderImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageLoaderImpl.java?view=diff&rev=492313&r1=492312&r2=492313
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageLoaderImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageLoaderImpl.java Wed Jan  3 13:41:45 2007
@@ -194,6 +194,7 @@
         List<ComponentPageElement> activeComponentStack = newList();
 
         boolean directlyInsideSubcomponent = false;
+        String defaultBindingPrefix = null;
 
         for (TemplateToken token : template.getTokens())
         {
@@ -337,6 +338,9 @@
 
                     directlyInsideSubcomponent = true;
 
+                    defaultBindingPrefix = startComponent.getElement() == null ? InternalConstants.PROP_BINDING_PREFIX
+                            : InternalConstants.LITERAL_BINDING_PREFIX;
+
                     break;
 
                 case ATTRIBUTE:
@@ -345,7 +349,11 @@
 
                     if (directlyInsideSubcomponent)
                     {
-                        addBindingToComponent(loadingElement, activeComponent, attribute);
+                        addBindingToComponent(
+                                loadingElement,
+                                activeComponent,
+                                defaultBindingPrefix,
+                                attribute);
                     }
                     else
                         add(loadingElement, activeComponent, _pageElementFactory
@@ -412,7 +420,7 @@
 
     // This is for bindings from the template.
     private void addBindingToComponent(ComponentPageElement loadingElement,
-            ComponentPageElement component, AttributeToken token)
+            ComponentPageElement component, String defaultBindingPrefix, AttributeToken token)
     {
         String name = token.getName();
         ComponentResources resources = component.getComponentResources();
@@ -424,16 +432,11 @@
         if (resources.isBound(name))
             return;
 
-        // When using the <t:comp> element (all that's supported right now), parameter
-        // are assumed to be prop expressions unless specifically other. When we add invisible
-        // instrumentation back in, LITERAL_BINDING_PREFIX will be the default for those
-        // attributes.
-
         Binding binding = _bindingSource.newBinding(
                 "parameter " + name,
                 loadingElement.getComponentResources(),
                 component.getComponentResources(),
-                InternalConstants.PROP_BINDING_PREFIX,
+                defaultBindingPrefix,
                 token.getValue(),
                 token.getLocation());
 

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageTemplateLocator.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageTemplateLocator.java?view=auto&rev=492313
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageTemplateLocator.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageTemplateLocator.java Wed Jan  3 13:41:45 2007
@@ -0,0 +1,24 @@
+package org.apache.tapestry.internal.services;
+
+import java.util.Locale;
+
+import org.apache.tapestry.ioc.Resource;
+import org.apache.tapestry.model.ComponentModel;
+
+/**
+ * Responsible for locating page templates in the web application context.
+ */
+public interface PageTemplateLocator
+{
+    /**
+     * Given model, determines if the model is for a page (rather than a component) and if so, sees
+     * if there is a localized template for the page in the web application context.
+     * 
+     * @param model
+     *            the component model defining the page to search for
+     * @param locale
+     *            the desired localization of the template
+     * @return the template resource, or null if not found or the model is not a page
+     */
+    Resource findPageTemplateResource(ComponentModel model, Locale locale);
+}

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageTemplateLocatorImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageTemplateLocatorImpl.java?view=auto&rev=492313
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageTemplateLocatorImpl.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageTemplateLocatorImpl.java Wed Jan  3 13:41:45 2007
@@ -0,0 +1,35 @@
+package org.apache.tapestry.internal.services;
+
+import java.util.Locale;
+
+import org.apache.tapestry.ioc.Resource;
+import org.apache.tapestry.model.ComponentModel;
+import org.apache.tapestry.services.ComponentClassResolver;
+
+public class PageTemplateLocatorImpl implements PageTemplateLocator
+{
+    private final Resource _contextRoot;
+
+    private final ComponentClassResolver _resolver;
+
+    public PageTemplateLocatorImpl(Resource contextRoot, ComponentClassResolver resolver)
+    {
+        _contextRoot = contextRoot;
+        _resolver = resolver;
+    }
+
+    public Resource findPageTemplateResource(ComponentModel model, Locale locale)
+    {
+        String className = model.getComponentClassName();
+
+        // A bit of a hack, but should work.
+
+        if (!className.contains(".pages."))
+            return null;
+
+        String logicalName = _resolver.resolvePageClassNameToPageName(className);
+
+        return _contextRoot.forFile(logicalName + ".html").forLocale(locale);
+    }
+
+}

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ServicesMessages.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ServicesMessages.java?view=diff&rev=492313&r1=492312&r2=492313
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ServicesMessages.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ServicesMessages.java Wed Jan  3 13:41:45 2007
@@ -287,4 +287,14 @@
                 cursor + 1,
                 specification);
     }
+
+    static String unexpectedTapestryAttribute(String qName)
+    {
+        return MESSAGES.format("unexpected-tapestry-attribute", qName);
+    }
+
+    static String mixinsInvalidWithoutIdOrType(String elementName)
+    {
+        return MESSAGES.format("mixins-invalid-without-id-or-type", elementName);
+    }
 }

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/StaticFilesFilter.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/StaticFilesFilter.java?view=diff&rev=492313&r1=492312&r2=492313
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/StaticFilesFilter.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/StaticFilesFilter.java Wed Jan  3 13:41:45 2007
@@ -12,42 +12,49 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package org.apache.tapestry.internal.services;
-
-import java.io.IOException;
-import java.net.URL;
-
-import org.apache.tapestry.services.Context;
-import org.apache.tapestry.services.Request;
-import org.apache.tapestry.services.RequestFilter;
-import org.apache.tapestry.services.RequestHandler;
-import org.apache.tapestry.services.Response;
-
-/**
- * Identifies requests that are for actual resource files in the context. For those, Tapestry allows
- * the servlet container to process the request.
- * 
- * 
- */
-public class StaticFilesFilter implements RequestFilter
-{
-    private final Context _context;
-
-    public StaticFilesFilter(Context context)
-    {
-        _context = context;
-    }
-
-    public boolean service(Request request, Response response, RequestHandler handler)
-            throws IOException
-    {
-        String path = request.getPath();
-
-        URL url = _context.getResource(path);
-
-        if (url != null)
-            return false;
-
-        return handler.service(request, response);
-    }
-}
+package org.apache.tapestry.internal.services;
+
+import java.io.IOException;
+import java.net.URL;
+
+import org.apache.tapestry.services.Context;
+import org.apache.tapestry.services.Request;
+import org.apache.tapestry.services.RequestFilter;
+import org.apache.tapestry.services.RequestHandler;
+import org.apache.tapestry.services.Response;
+
+/**
+ * Identifies requests that are for actual resource files in the context. For those, Tapestry allows
+ * the servlet container to process the request.
+ */
+public class StaticFilesFilter implements RequestFilter
+{
+    private final Context _context;
+
+    public StaticFilesFilter(Context context)
+    {
+        _context = context;
+    }
+
+    public boolean service(Request request, Response response, RequestHandler handler)
+            throws IOException
+    {
+        String path = request.getPath();
+
+        // A hopefully temporary hack. .html files *may* be page templates, which are now allowed to
+        // exist up in the web context. Eventually, though, we may support other extensions than
+        // .html, and there's a further issue handling truly static files with an .html
+        // extension.
+
+        if (!path.endsWith(".html"))
+        {
+
+            URL url = _context.getResource(path);
+
+            if (url != null)
+                return false;
+        }
+
+        return handler.service(request, response);
+    }
+}

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/TemplateParserImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/TemplateParserImpl.java?view=diff&rev=492313&r1=492312&r2=492313
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/TemplateParserImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/TemplateParserImpl.java Wed Jan  3 13:41:45 2007
@@ -15,12 +15,10 @@
 package org.apache.tapestry.internal.services;
 
 import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newList;
-import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newMap;
 import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newSet;
 
 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;
@@ -44,19 +42,25 @@
 import org.apache.tapestry.ioc.internal.util.LocationImpl;
 import org.apache.tapestry.ioc.internal.util.TapestryException;
 import org.xml.sax.Attributes;
+import org.xml.sax.ContentHandler;
 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.DefaultHandler;
 import org.xml.sax.helpers.XMLReaderFactory;
 
 /**
  * Non-threadsafe implementation; the IOC service uses the perthread lifecycle.
  */
-public class TemplateParserImpl extends DefaultHandler implements TemplateParser, LexicalHandler
+public class TemplateParserImpl implements TemplateParser, LexicalHandler, ContentHandler
 {
+    private static final String MIXINS_ATTRIBUTE_NAME = "mixins";
+
+    private static final String TYPE_ATTRIBUTE_NAME = "type";
+
+    private static final String ID_ATTRIBUTE_NAME = "id";
+
     public static final String TAPESTRY_SCHEMA_5_0_0 = "http://tapestry.apache.org/schema/tapestry_5_0_0.xsd";
 
     private XMLReader _reader;
@@ -68,10 +72,6 @@
 
     private final List<TemplateToken> _tokens = newList();
 
-    // A stack of maps, each map contains mappings from prefix to namespace URL
-
-    private final List<Map<String, String>> _prefixResolutionStack = newList();
-
     // Non-blank ids from start component (<comp>) elements
 
     private final Set<String> _componentIds = newSet();
@@ -108,7 +108,6 @@
     private void reset()
     {
         _tokens.clear();
-        _prefixResolutionStack.clear();
         _componentIds.clear();
         _templateResource = null;
         _locator = null;
@@ -130,8 +129,6 @@
                 _reader = XMLReaderFactory.createXMLReader();
 
                 _reader.setContentHandler(this);
-                _reader.setErrorHandler(this);
-                _reader.setEntityResolver(this);
 
                 _reader.setFeature("http://xml.org/sax/features/namespace-prefixes", true);
 
@@ -149,9 +146,6 @@
         if (resourceURL == null)
             throw new RuntimeException(ServicesMessages.missingTemplateResource(templateResource));
 
-        Map<String, String> rootPrefixMap = newMap();
-        _prefixResolutionStack.add(rootPrefixMap);
-
         _templateResource = templateResource;
 
         try
@@ -178,35 +172,12 @@
         }
     }
 
-    @Override
     public void setDocumentLocator(Locator locator)
     {
         _locator = locator;
     }
 
-    /**
-     * Creates a new prefix to URI mapping map and adds this new prefix/URI mapping into the map.
-     * The new map is pushed onto the stack of such maps.
-     */
-    @Override
-    public void startPrefixMapping(String prefix, String uri) throws SAXException
-    {
-        Map<String, String> topMap = _prefixResolutionStack.get(0);
-        Map<String, String> newMap = newMap(topMap);
-        newMap.put(prefix, uri);
-
-        _prefixResolutionStack.add(0, newMap);
-    }
-
-    /** Pops the top prefix mapping map off the stack. */
-    @Override
-    public void endPrefixMapping(String prefix) throws SAXException
-    {
-        _prefixResolutionStack.remove(0);
-    }
-
     /** Accumulates the characters into a text buffer. */
-    @Override
     public void characters(char[] ch, int start, int length) throws SAXException
     {
         if (_ignoreEvents)
@@ -284,7 +255,6 @@
             _tokens.add(new TextToken(text.substring(startx, text.length()), _textStartLocation));
     }
 
-    @Override
     public void startElement(String uri, String localName, String qName, Attributes attributes)
             throws SAXException
     {
@@ -303,16 +273,24 @@
             return;
         }
 
-        // TODO: Handle tapestry namespace elements
         // TODO: Handle tapestry namespace attributes in ordinary namespace elements?
         // TODO: Handle interpolations inside attributes?
 
+        startStaticElement(localName, attributes);
+    }
+
+    private void startStaticElement(String localName, Attributes attributes)
+    {
         Location location = getCurrentLocation();
 
-        _tokens.add(new StartElementToken(localName, location));
+        List<TemplateToken> attributeTokens = newList();
 
         int count = attributes.getLength();
 
+        String id = null;
+        String type = null;
+        String mixins = null;
+
         for (int i = 0; i < count; i++)
         {
             String name = attributes.getLocalName(i);
@@ -322,10 +300,58 @@
             if (InternalUtils.isBlank(name))
                 continue;
 
+            String uri = attributes.getURI(i);
+
             String value = attributes.getValue(i);
 
-            _tokens.add(new AttributeToken(name, value, location));
+            if (TAPESTRY_SCHEMA_5_0_0.equals(uri))
+            {
+                if (InternalUtils.isNonBlank(value))
+                {
+                    if (name.equals(ID_ATTRIBUTE_NAME))
+                    {
+                        id = value;
+                        continue;
+                    }
+
+                    if (name.equals(TYPE_ATTRIBUTE_NAME))
+                    {
+                        type = value;
+                        continue;
+                    }
+
+                    if (name.equals(MIXINS_ATTRIBUTE_NAME))
+                    {
+                        mixins = value;
+                        continue;
+                    }
+
+                    throw new TapestryException(ServicesMessages
+                            .unexpectedTapestryAttribute(attributes.getQName(i)), location, null);
+                }
+            }
+
+            attributeTokens.add(new AttributeToken(name, 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 (mixins != null && !isComponent)
+            throw new TapestryException(ServicesMessages.mixinsInvalidWithoutIdOrType(localName),
+                    location, null);
+
+        if (isComponent)
+        {
+            _tokens.add(new StartComponentToken(localName, id, type, mixins, location));
+        }
+        else
+        {
+            _tokens.add(new StartElementToken(localName, location));
+        }
+
+        _tokens.addAll(attributeTokens);
     }
 
     /**
@@ -383,14 +409,14 @@
 
             // TODO: Validate that the id is a reasonable string.
 
-            if (name.equals("id"))
+            if (name.equals(ID_ATTRIBUTE_NAME))
             {
                 if (InternalUtils.isNonBlank(value))
                     id = value;
                 continue;
             }
 
-            if (name.equals("type"))
+            if (name.equals(TYPE_ATTRIBUTE_NAME))
             {
 
                 if (InternalUtils.isNonBlank(value))
@@ -398,7 +424,7 @@
                 continue;
             }
 
-            if (name.equals("mixins"))
+            if (name.equals(MIXINS_ATTRIBUTE_NAME))
             {
                 if (InternalUtils.isNonBlank(value))
                     mixins = value;
@@ -421,7 +447,7 @@
             _componentIds.add(id);
 
         // Add the component
-        _tokens.add(new StartComponentToken(id, type, mixins, location));
+        _tokens.add(new StartComponentToken(null, id, type, mixins, location));
         _tokens.addAll(attributeTokens);
     }
 
@@ -433,7 +459,6 @@
         _insideBodyErrorLogged = false;
     }
 
-    @Override
     public void endElement(String uri, String localName, String qName) throws SAXException
     {
         processTextBuffer();
@@ -491,14 +516,6 @@
         _textIsCData = false;
     }
 
-    public void endDTD() throws SAXException
-    {
-    }
-
-    public void endEntity(String name) throws SAXException
-    {
-    }
-
     public void startCDATA() throws SAXException
     {
         if (_ignoreEvents || insideBody())
@@ -512,12 +529,72 @@
         _textIsCData = true;
     }
 
+    // Empty methods defined by the various interfaces.
+
+    public void endDTD() throws SAXException
+    {
+        // TODO Auto-generated method stub
+
+    }
+
+    public void endEntity(String name) throws SAXException
+    {
+        // TODO Auto-generated method stub
+
+    }
+
     public void startDTD(String name, String publicId, String systemId) throws SAXException
     {
+        // TODO Auto-generated method stub
+
     }
 
     public void startEntity(String name) throws SAXException
     {
+        // TODO Auto-generated method stub
+
+    }
+
+    public void endDocument() throws SAXException
+    {
+        // TODO Auto-generated method stub
+
+    }
+
+    public void endPrefixMapping(String prefix) throws SAXException
+    {
+        // TODO Auto-generated method stub
+
+    }
+
+    public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException
+    {
+        // TODO Auto-generated method stub
+
+    }
+
+    public void processingInstruction(String target, String data) throws SAXException
+    {
+        // TODO Auto-generated method stub
 
     }
+
+    public void skippedEntity(String name) throws SAXException
+    {
+        // TODO Auto-generated method stub
+
+    }
+
+    public void startDocument() throws SAXException
+    {
+        // TODO Auto-generated method stub
+
+    }
+
+    public void startPrefixMapping(String prefix, String uri) throws SAXException
+    {
+        // TODO Auto-generated method stub
+
+    }
+
 }

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/test/InternalBaseTestCase.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/test/InternalBaseTestCase.java?view=diff&rev=492313&r1=492312&r2=492313
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/test/InternalBaseTestCase.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/test/InternalBaseTestCase.java Wed Jan  3 13:41:45 2007
@@ -33,6 +33,7 @@
 import org.apache.tapestry.internal.services.PageElementFactory;
 import org.apache.tapestry.internal.services.PageLoader;
 import org.apache.tapestry.internal.services.PagePool;
+import org.apache.tapestry.internal.services.PageTemplateLocator;
 import org.apache.tapestry.internal.services.RequestPageCache;
 import org.apache.tapestry.internal.services.ResourceCache;
 import org.apache.tapestry.internal.services.ResourceStreamer;
@@ -398,5 +399,16 @@
     protected final void train_get(RequestPageCache cache, String pageName, Page page)
     {
         expect(cache.get(pageName)).andReturn(page).atLeastOnce();
+    }
+
+    protected final void train_findPageTemplateResource(PageTemplateLocator locator,
+            ComponentModel model, Locale locale, Resource resource)
+    {
+        expect(locator.findPageTemplateResource(model, locale)).andReturn(resource).atLeastOnce();
+    }
+
+    protected final PageTemplateLocator newPageTemplateLocator()
+    {
+        return newMock(PageTemplateLocator.class);
     }
 }

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/AssetSource.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/AssetSource.java?view=diff&rev=492313&r1=492312&r2=492313
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/AssetSource.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/AssetSource.java Wed Jan  3 13:41:45 2007
@@ -36,8 +36,21 @@
      * @param baseResource
      *            base resource for computing relative paths
      * @param path
+     *            relative to the base resource
      * @param locale
-     * @return
+     *            locale to localize the final resource to
+     * @return the asset
      */
     Asset findAsset(Resource baseResource, String path, Locale locale);
-}
+
+    /**
+     * Convienience for finding assets on the classpath.
+     * 
+     * @param path
+     *            path to the base resource, relative to classpath root
+     * @param locale
+     *            to localize the resource to
+     * @return the asset
+     */
+    Asset getClasspathAsset(String path, Locale locale);
+}
\ No newline at end of file

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/TapestryModule.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/TapestryModule.java?view=diff&rev=492313&r1=492312&r2=492313
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/TapestryModule.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/TapestryModule.java Wed Jan  3 13:41:45 2007
@@ -49,8 +49,6 @@
 import org.apache.tapestry.internal.services.ActionLinkHandlerImpl;
 import org.apache.tapestry.internal.services.ApplicationGlobalsImpl;
 import org.apache.tapestry.internal.services.AssetDispatcher;
-import org.apache.tapestry.internal.services.ClasspathAssetSource;
-import org.apache.tapestry.internal.services.InjectAssetWorker;
 import org.apache.tapestry.internal.services.AssetSourceImpl;
 import org.apache.tapestry.internal.services.BindingSourceImpl;
 import org.apache.tapestry.internal.services.ClasspathAssetAliasManagerImpl;
@@ -74,6 +72,7 @@
 import org.apache.tapestry.internal.services.InfrastructureImpl;
 import org.apache.tapestry.internal.services.InfrastructureManagerImpl;
 import org.apache.tapestry.internal.services.InjectAnonymousWorker;
+import org.apache.tapestry.internal.services.InjectAssetWorker;
 import org.apache.tapestry.internal.services.InjectComponentWorker;
 import org.apache.tapestry.internal.services.InjectNamedWorker;
 import org.apache.tapestry.internal.services.InjectPageWorker;
@@ -167,13 +166,13 @@
 
     public TapestryModule(@InjectService("tapestry.ioc.PipelineBuilder")
     PipelineBuilder pipelineBuilder, @InjectService("tapestry.ioc.PropertyShadowBuilder")
-    PropertyShadowBuilder shadowBuilder, @InjectService("RequestGlobals")
-    RequestGlobals requestGlobals, @InjectService("ApplicationGlobals")
+    PropertyShadowBuilder shadowBuilder, @Inject("infrastructure:RequestGlobals")
+    RequestGlobals requestGlobals, @Inject("infrastructure:ApplicationGlobals")
     ApplicationGlobals applicationGlobals, @InjectService("tapestry.ioc.ChainBuilder")
     ChainBuilder chainBuilder, @InjectService("tapestry.internal.RequestPageCache")
     RequestPageCache requestPageCache, @InjectService("tapestry.internal.PageResponseRenderer")
     PageResponseRenderer pageResponseRenderer, @Inject("infrastructure:Request")
-    Request request, @InjectService("Environment")
+    Request request, @Inject("infrastructure:Environment")
     Environment environment, @InjectService("tapestry.ioc.StrategyBuilder")
     StrategyBuilder strategyBuilder)
     {
@@ -427,12 +426,15 @@
         add(
                 configuration,
                 locator,
+                ApplicationGlobals.class,
+                RequestGlobals.class,
                 MarkupWriterFactory.class,
                 PersistentFieldManager.class,
                 Environment.class,
                 ComponentSource.class,
                 BindingSource.class,
                 ComponentMessagesSource.class,
+                ComponentClassResolver.class,
                 AssetSource.class,
                 ResourceDigestGenerator.class,
                 ClasspathAssetAliasManager.class,
@@ -720,8 +722,8 @@
     public static void contributePageRenderInitializer(
             OrderedConfiguration<PageRenderCommand> configuration,
             @InjectService("tapestry.ioc.ThreadLocale")
-            ThreadLocale threadLocale, @InjectService("tapestry.internal.ClasspathAssetSource")
-            ClasspathAssetSource classpathAssetSource)
+            ThreadLocale threadLocale, @Inject("infrastructure:AssetSource")
+            AssetSource assetSource)
     {
         configuration.add("PageRenderSupport", new PageRenderCommand()
         {
@@ -754,7 +756,7 @@
         });
 
         configuration.add("InjectStandardStylesheet", new InjectStandardStylesheetCommand(
-                threadLocale, classpathAssetSource));
+                threadLocale, assetSource));
     }
 
     /** A public service since extensions may provide new persistent strategies. */

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/TapestryTestCase.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/TapestryTestCase.java?view=diff&rev=492313&r1=492312&r2=492313
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/TapestryTestCase.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/TapestryTestCase.java Wed Jan  3 13:41:45 2007
@@ -51,6 +51,7 @@
 import org.apache.tapestry.model.ParameterModel;
 import org.apache.tapestry.runtime.Component;
 import org.apache.tapestry.services.AssetFactory;
+import org.apache.tapestry.services.AssetSource;
 import org.apache.tapestry.services.Binding;
 import org.apache.tapestry.services.BindingFactory;
 import org.apache.tapestry.services.BindingSource;
@@ -58,6 +59,7 @@
 import org.apache.tapestry.services.ClasspathAssetAliasManager;
 import org.apache.tapestry.services.ComponentClassResolver;
 import org.apache.tapestry.services.Context;
+import org.apache.tapestry.services.Environment;
 import org.apache.tapestry.services.FieldValidatorSource;
 import org.apache.tapestry.services.InjectionProvider;
 import org.apache.tapestry.services.MethodFilter;
@@ -585,5 +587,30 @@
     protected final BindingSource newBindingSource()
     {
         return newMock(BindingSource.class);
+    }
+
+    protected final void train_getClasspathAsset(AssetSource source, String path, Locale locale, Asset asset)
+    {
+        expect(source.getClasspathAsset(path, locale)).andReturn(asset);
+    }
+
+    protected final void toClientURL(Asset asset, String clientURL)
+    {
+        expect(asset.toClientURL()).andReturn(clientURL);
+    }
+
+    protected final <T> void train_peek(Environment env, Class<T> type, T value)
+    {
+        expect(env.peek(type)).andReturn(value);
+    }
+
+    protected final Environment newEnvironment()
+    {
+        return newMock(Environment.class);
+    }
+
+    protected final AssetSource newAssetSource()
+    {
+        return newMock(AssetSource.class);
     }
 }

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/pagelevel/PageTester.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/pagelevel/PageTester.java?view=diff&rev=492313&r1=492312&r2=492313
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/pagelevel/PageTester.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/pagelevel/PageTester.java Wed Jan  3 13:41:45 2007
@@ -31,6 +31,7 @@
 import org.apache.tapestry.ioc.Registry;
 import org.apache.tapestry.ioc.internal.util.Defense;
 import org.apache.tapestry.ioc.util.StrategyRegistry;
+import org.apache.tapestry.services.ApplicationGlobals;
 
 /**
  * This class is used to run a Tapestry app in an in-process testing environment. You can ask it to
@@ -55,15 +56,19 @@
 
     private LocalizationSetter _localizationSetter;
 
+    public static final String DEFAULT_CONTEXT_PATH = "src/main/webapp";
+
+    private final String _contextPath;
+
     /**
      * Initializes a PageTester without overriding any services.
      * 
-     * @see #PageTester(String, String, Map)
+     * @see #PageTester(String, String, String, Map)
      */
     @SuppressWarnings("unchecked")
     public PageTester(String appPackage, String appName)
     {
-        this(appPackage, appName, Collections.EMPTY_MAP);
+        this(appPackage, appName, DEFAULT_CONTEXT_PATH, Collections.EMPTY_MAP);
     }
 
     /**
@@ -77,13 +82,24 @@
      * @param serviceOverrides
      *            The mock implementation (value) for some services (key).
      */
-    public PageTester(String appPackage, String appName, Map<String, Object> serviceOverrides)
+    public PageTester(String appPackage, String appName, String contextPath,
+            Map<String, Object> serviceOverrides)
     {
+        _contextPath = contextPath;
+
         _registry = new TapestryAppInitializer(appPackage, appName, "test",
                 addDefaultOverrides(serviceOverrides)).getRegistry();
+
         _localizationSetter = _registry.getService(
                 "tapestry.internal.LocalizationSetter",
                 LocalizationSetter.class);
+
+        ApplicationGlobals globals = _registry.getObject(
+                "infrastructure:ApplicationGlobals",
+                ApplicationGlobals.class);
+
+        globals.store(new PageTesterContext(_contextPath));
+
         buildInvokersRegistry();
     }
 

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/pagelevel/PageTesterContext.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/pagelevel/PageTesterContext.java?view=auto&rev=492313
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/pagelevel/PageTesterContext.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/pagelevel/PageTesterContext.java Wed Jan  3 13:41:45 2007
@@ -0,0 +1,37 @@
+package org.apache.tapestry.test.pagelevel;
+
+import java.io.File;
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import org.apache.tapestry.services.Context;
+
+public class PageTesterContext implements Context
+{
+    private final String _contextRoot;
+
+    public PageTesterContext(final String contextRoot)
+    {
+        _contextRoot = contextRoot;
+    }
+
+    public String getInitParameter(String name)
+    {
+        return null;
+    }
+
+    public URL getResource(String path)
+    {
+        File f = new File(_contextRoot + path);
+
+        try
+        {
+            return f.toURL();
+        }
+        catch (MalformedURLException ex)
+        {
+            throw new RuntimeException(ex);
+        }
+    }
+
+}

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/internal/services/ServicesStrings.properties
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/internal/services/ServicesStrings.properties?view=diff&rev=492313&r1=492312&r2=492313
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/internal/services/ServicesStrings.properties (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/internal/services/ServicesStrings.properties Wed Jan  3 13:41:45 2007
@@ -40,7 +40,8 @@
 non-private-fields=Class %s contains field(s) (%s) that are not private. Tapestry will ignore these fields, even if they \
   have annotations. Runtime behavior, especially in production, may not be what you expect. \
   You should change these fields to private, and add accessor methods if needed.  
-comp-requires-id-or-type=The <comp> element requires either an id or a type attribute to be specified.
+comp-requires-id-or-type=The <comp> element requires either an id or a type attribute to be specified.
+mixins-invalid-without-id-or-type=You may not specify mixins for element <%s> because it does not represent a component (which requires either an id attribute or a type attribute).
 comp-type-conflict=Embedded component '%s' provides a type attribute in the template ('%s') as well as in the component class ('%s'). \
   You should not provide a type attribute in the template when defining an embedded component within the component class.
 no-type-for-embedded-component=Embedded component '%s' has no type. You should specify a type in the component template, \
@@ -65,4 +66,5 @@
 wrong-asset-digest=The asset digest in the request does not match the actual digest for asset '%s'. This indicates that the content of the asset has changed between requests. 
 component-not-assignable-to-field=Component %s is not assignable to field %s (of type %s).
 unknown-validator-type=Unknown validator type '%s'.  Configured validators are %s.
-validator-specification-parse-error=Unexpected character '%s' at position %d of input string: %s
\ No newline at end of file
+validator-specification-parse-error=Unexpected character '%s' at position %d of input string: %s
+unexpected-tapestry-attribute=Attribute '%s' is not defined in the Tapestry template schema.
\ No newline at end of file

Modified: tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/templates.apt
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/templates.apt?view=diff&rev=492313&r1=492312&r2=492313
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/templates.apt (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/templates.apt Wed Jan  3 13:41:45 2007
@@ -28,8 +28,12 @@
   the corresponding template will be <<<src/main/resources/org/example/myapp/pages/MyPage.html>>>.
   
   The template and the compiled class will be packaged together in the WEB-INF/classes folder of the application WAR.
+
+  For <pages> (not <components>), a second location will be searched: in the web application context.
+  The location is based on the logical name of the page, in the previous example, the template
+  would be <<<MyPage.html>>> in the root folder of the web application.
   
-  <<TODO: Is the ".html" template still useful? And do we need control over the template extension?>>
+  A template on the classpath takes precendence over a file in the web application context.
   
 Template Localization
 
@@ -67,7 +71,7 @@
 
   Tapestry elements are elements defined using the Tapestry namespace prefix.
   
-  <<Tapestry 4 style templates with "invisible annotations" will be re-implemented soon. They are not being abandoned.>>  
+  All other elements should be in the default namespace, with no prefix.
   
 * \<comp\>
 
@@ -164,9 +168,35 @@
    Tapestry 4 users will recognize the \<body\> element as a replacement for the
    RenderBody component.
    
+Invisible Instrumentation
+
+  A favorite feature of Tapestry 4 is <invisible instrumentation>, the ability to mark ordinary HTML elements as components. This has the advantage
+  of providing more concise template that are often more readable.
+  
+  For Tapestry 5, you make use of <namespaced> id or type attributes to mark an element as a component, for example:
+  
++---+
+<p>
+    Merry Christmas:
+    <span t:type="Count" end="3">
+        Ho!
+    </span>
+</p>
++---+   
+
+  Only the id, type and mixins attributes are placed in the Tapestry namespace; all other attributes have no prefix.
+  
+  <Note: this may change; since often component parameters do not match X/HTML elements, we may shift this to allow
+  any attribute to be placed in the Tapestry namespace; this would allow input documents to be not only well formed
+  but validatable.>
+   
+  <<Parameters are always literal strings.>> Unlike the use of attributes with the \<t:comp\> element, 
+  parameter values (such as end, in the previous example)
+  are assumed to be literal strings.  You must use the "prop:" prefix if the value is name of a property of the component.
+   
 Expansions
 
-  Another option for rendering output are <expansions>.  Expansions
+  Another option when rendering output is the use of  <expansions>.  Expansions
   are special strings that may be emdedded in template bodies, and borrow some syntax
   from the {{{http://ant.apache.org}Ant}} build tool.
   

Modified: tapestry/tapestry5/tapestry-core/trunk/src/site/apt/index.apt
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/site/apt/index.apt?view=diff&rev=492313&r1=492312&r2=492313
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/site/apt/index.apt (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/site/apt/index.apt Wed Jan  3 13:41:45 2007
@@ -31,6 +31,19 @@
   
   * Super-duper Ajax integration built on {{{http://dojotoolkit.org} Dojo}}
   
+New And Of Note
+
+  Progress on Tapestry 5 is really taking off. This space lists some cool new features that have been added
+  recently.
+  
+  * Page templates are now allowed to be stored in the web application root, as well as on the classpath.
+  
+  * Invisible instrumentation, hiding Tapestry components inside ordinary HTML elements (a favorite feature of Tapestry 4), has been added to Tapestry 5.
+  
+  * Component parameter defaults may be computed on the fly.
+
+  * Component parameters may have default values.
+  
 Adaptive API
 
   A key feature of Tapestry 5 is <adaptive API>.

Copied: tapestry/tapestry5/tapestry-core/trunk/src/test/app1/SimpleForm.html (from r491920, tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/integration/app1/pages/SimpleForm.html)
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/app1/SimpleForm.html?view=diff&rev=492313&p1=tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/integration/app1/pages/SimpleForm.html&r1=491920&p2=tapestry/tapestry5/tapestry-core/trunk/src/test/app1/SimpleForm.html&r2=492313
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/integration/app1/pages/SimpleForm.html (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/app1/SimpleForm.html Wed Jan  3 13:41:45 2007
@@ -3,24 +3,23 @@
 
     <p> This is the <em>very early</em> start to Tapestry 5 form support. </p>
 
-    <t:comp type="Form">
-        <t:comp type="Checkbox" id="disabled"/>
-        <t:comp type="Label" field="component:disabled"/>
+    <form t:type="Form">
+        <input t:type="Checkbox" t:id="disabled"/>
+        <label t:type="Label" field="component:disabled"/>
         
         <hr/>
         
-        <t:comp type="Label"  field="component:email">This isn't used</t:comp>: <t:comp
-            type="TextField" id="email" value="incident.email" size="50"  disabled="disabled"/>
+        <label t:type="Label"  field="component:email">This isn't used</label>: <input
+            t:type="TextField" t:id="email" value="prop:incident.email" size="50"  disabled="prop:disabled"/>
         <br/>
-        <t:comp type="Label"  field="component:message"/>: <t:comp type="TextArea" id="message" label="literal:Incident Message"
-            value="incident.message" cols="50" rows="10" disabled="disabled"> You can put text here, but it isn't used. </t:comp>
+        <label t:type="Label"  field="component:message"/>: <input t:type="TextArea" t:id="message" label="Incident Message"
+            value="prop:incident.message" cols="50" rows="10" disabled="prop:disabled"> You can put text here, but it isn't used. </input>
         <br/>
-        <t:comp type="Checkbox" id="urgent" value="incident.urgent" disabled="disabled"/>
-        <t:comp type="Label" field="component:urgent"/>
+        <input t:type="Checkbox" t:id="urgent" value="prop:incident.urgent" disabled="prop:disabled"/>
+        <label t:type="Label" field="component:urgent"/>
         <br/>
         <input type="submit"/>
-    </t:comp>
-
+    </form>
 
     <hr/>
 

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/IntegrationTests.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/IntegrationTests.java?view=diff&rev=492313&r1=492312&r2=492313
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/IntegrationTests.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/IntegrationTests.java Wed Jan  3 13:41:45 2007
@@ -289,7 +289,10 @@
         assertTextPresent("[BEGIN-TRACER-MIXIN BEGIN-ABSTRACT-TRACER BEGIN-TRACER BODY AFTER-TRACER AFTER-ABSTRACT-TRACER AFTER-TRACER-MIXIN]");
     }
 
-    /** Tests for forms and form submissions and basic form control components. */
+    /**
+     * Tests for forms and form submissions and basic form control components. This also tests a few
+     * other things, such as computed default bindings and invisible instrumentation.
+     */
     @Test
     public void simple_form()
     {

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/AssetSourceImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/AssetSourceImplTest.java?view=diff&rev=492313&r1=492312&r2=492313
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/AssetSourceImplTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/AssetSourceImplTest.java Wed Jan  3 13:41:45 2007
@@ -63,6 +63,33 @@
     }
 
     @Test
+    public void get_classpath_asset()
+    {
+        AssetFactory factory = newAssetFactory();
+        Asset asset = newAsset();
+
+        Resource expectedResource = _baseResource.forFile("SimpleComponent_en_GB.properties");
+
+        train_getRootResource(factory, _rootResource);
+
+        train_createAsset(factory, expectedResource, asset);
+
+        Map<String, AssetFactory> configuration = Collections.singletonMap("classpath", factory);
+
+        replay();
+
+        AssetSource source = new AssetSourceImpl(configuration);
+
+        // First try creates it:
+
+        assertSame(source.getClasspathAsset(
+                "org/apache/tapestry/internal/services/SimpleComponent.properties",
+                Locale.UK), asset);
+
+        verify();
+    }
+
+    @Test
     public void absolute_asset_with_known_prefix()
     {
         AssetFactory factory = newAssetFactory();

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentTemplateSourceImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentTemplateSourceImplTest.java?view=diff&rev=492313&r1=492312&r2=492313
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentTemplateSourceImplTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentTemplateSourceImplTest.java Wed Jan  3 13:41:45 2007
@@ -29,9 +29,6 @@
 import org.apache.tapestry.model.ComponentModel;
 import org.testng.annotations.Test;
 
-/**
- * 
- */
 public class ComponentTemplateSourceImplTest extends InternalBaseTestCase
 {
     private static final String PACKAGE = "org.apache.tapestry.internal.pageload";
@@ -73,7 +70,7 @@
     @Test
     public void caching()
     {
-        Resource r = newResource("Fred.html");
+        Resource baseResource = newResource("Fred.class");
 
         TemplateParser parser = newTemplateParser();
         ComponentTemplate template = newComponentTemplate();
@@ -81,11 +78,13 @@
 
         train_getComponentClassName(model, PACKAGE + ".Fred");
 
-        train_parseTemplate(parser, r, template);
+        train_getBaseResource(model, baseResource);
+
+        train_parseTemplate(parser, baseResource.withExtension("html"), template);
 
         replay();
 
-        ComponentTemplateSource source = new ComponentTemplateSourceImpl(parser);
+        ComponentTemplateSource source = new ComponentTemplateSourceImpl(parser, null);
 
         assertSame(source.getTemplate(model, Locale.ENGLISH), template);
 
@@ -112,7 +111,8 @@
 
         f.createNewFile();
 
-        Resource localized = new ClasspathResource(loader, "baz/Biff.html");
+        Resource baseResource = new ClasspathResource(loader, "baz/Biff.class");
+        Resource localized = baseResource.withExtension("html");
 
         TemplateParser parser = newTemplateParser();
         ComponentTemplate template = newComponentTemplate();
@@ -120,11 +120,13 @@
 
         train_getComponentClassName(model, "baz.Biff");
 
+        train_getBaseResource(model, baseResource);
+
         train_parseTemplate(parser, localized, template);
 
         replay();
 
-        ComponentTemplateSourceImpl source = new ComponentTemplateSourceImpl(loader, parser);
+        ComponentTemplateSourceImpl source = new ComponentTemplateSourceImpl(parser, null);
         source.addInvalidationListener(listener);
 
         assertSame(source.getTemplate(model, Locale.ENGLISH), template);
@@ -156,6 +158,8 @@
 
         train_getComponentClassName(model, "baz.Biff");
 
+        train_getBaseResource(model, baseResource);
+
         train_parseTemplate(parser, localized, template);
 
         replay();
@@ -169,7 +173,7 @@
     @Test
     public void localization_to_same()
     {
-        Resource r = newResource("Fred.html");
+        Resource baseResource = newResource("Fred.class");
 
         TemplateParser parser = newTemplateParser();
         ComponentTemplate template = newComponentTemplate();
@@ -177,11 +181,13 @@
 
         train_getComponentClassName(model, PACKAGE + ".Fred");
 
-        train_parseTemplate(parser, r, template);
+        train_getBaseResource(model, baseResource);
+
+        train_parseTemplate(parser, baseResource.withExtension("html"), template);
 
         replay();
 
-        ComponentTemplateSourceImpl source = new ComponentTemplateSourceImpl(parser);
+        ComponentTemplateSourceImpl source = new ComponentTemplateSourceImpl(parser, null);
 
         assertSame(source.getTemplate(model, Locale.ENGLISH), template);
 
@@ -198,18 +204,57 @@
     }
 
     @Test
+    public void page_template_found_in_context()
+    {
+        Resource baseResource = newResource("NotInClasspath.class");
+
+        // Simpler to do it this way ...
+
+        Resource contextTemplateResource = newResource("Fred.html");
+
+        TemplateParser parser = newTemplateParser();
+        ComponentTemplate template = newComponentTemplate();
+        ComponentModel model = newComponentModel();
+        PageTemplateLocator locator = newPageTemplateLocator();
+        Locale locale = Locale.FRENCH;
+
+        train_getComponentClassName(model, PACKAGE + ".NotInClasspath");
+
+        train_getBaseResource(model, baseResource);
+
+        train_findPageTemplateResource(locator, model, locale, contextTemplateResource);
+
+        train_parseTemplate(parser, contextTemplateResource, template);
+
+        replay();
+
+        ComponentTemplateSourceImpl source = new ComponentTemplateSourceImpl(parser, locator);
+
+        assertSame(source.getTemplate(model, locale), template);
+
+        verify();
+    }
+
+    @Test
     public void no_template_found()
     {
         TemplateParser parser = newTemplateParser();
         ComponentModel model = newComponentModel();
+        PageTemplateLocator locator = newPageTemplateLocator();
+
+        Resource baseResource = newResource("Barney.class");
 
         train_getComponentClassName(model, PACKAGE + ".Barney");
 
+        train_getBaseResource(model, baseResource);
+
+        train_findPageTemplateResource(locator, model, Locale.ENGLISH, null);
+
         train_getParentModel(model, null);
 
         replay();
 
-        ComponentTemplateSourceImpl source = new ComponentTemplateSourceImpl(parser);
+        ComponentTemplateSourceImpl source = new ComponentTemplateSourceImpl(parser, locator);
 
         ComponentTemplate template = source.getTemplate(model, Locale.ENGLISH);
 
@@ -221,7 +266,9 @@
     @Test
     public void child_component_inherits_parent_template()
     {
-        Resource r = newResource("Fred.html");
+        Resource baseFred = newResource("Fred.class");
+        Resource baseBarney = baseFred.forFile("Barney.class");
+        PageTemplateLocator locator = newPageTemplateLocator();
 
         TemplateParser parser = newTemplateParser();
         ComponentTemplate template = newComponentTemplate();
@@ -230,15 +277,19 @@
 
         train_getComponentClassName(model, PACKAGE + ".Barney");
 
+        train_getBaseResource(model, baseBarney);
+
+        train_findPageTemplateResource(locator, model, Locale.ENGLISH, null);
+
         train_getParentModel(model, parentModel);
 
-        train_getComponentClassName(parentModel, PACKAGE + ".Fred");
+        train_getBaseResource(parentModel, baseFred);
 
-        train_parseTemplate(parser, r, template);
+        train_parseTemplate(parser, baseFred.withExtension("html"), template);
 
         replay();
 
-        ComponentTemplateSource source = new ComponentTemplateSourceImpl(parser);
+        ComponentTemplateSource source = new ComponentTemplateSourceImpl(parser, locator);
 
         assertSame(source.getTemplate(model, Locale.ENGLISH), template);
 

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/InjectStandardStylesheetCommandTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/InjectStandardStylesheetCommandTest.java?view=diff&rev=492313&r1=492312&r2=492313
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/InjectStandardStylesheetCommandTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/InjectStandardStylesheetCommandTest.java Wed Jan  3 13:41:45 2007
@@ -20,6 +20,7 @@
 import org.apache.tapestry.dom.Document;
 import org.apache.tapestry.internal.test.InternalBaseTestCase;
 import org.apache.tapestry.ioc.services.ThreadLocale;
+import org.apache.tapestry.services.AssetSource;
 import org.apache.tapestry.services.Environment;
 import org.testng.annotations.Test;
 
@@ -30,7 +31,7 @@
     {
         Document d = new Document();
         ThreadLocale tl = newThreadLocale();
-        ClasspathAssetSource source = newClasspathAssetSource();
+        AssetSource source = newAssetSource();
         Environment env = newEnvironment();
 
         d.newRootElement("foo");
@@ -52,7 +53,7 @@
     {
         Document d = new Document();
         ThreadLocale tl = newThreadLocale();
-        ClasspathAssetSource source = newClasspathAssetSource();
+        AssetSource source = newAssetSource();
         Environment env = newEnvironment();
         Asset asset = newAsset();
         Locale l = Locale.FRENCH;
@@ -74,31 +75,5 @@
         assertEquals(
                 d.toString(),
                 "<html><head><link href=\"{clientURL}\" rel=\"stylesheet\" type=\"text/css\"></head></html>");
-    }
-
-    private void train_getClasspathAsset(ClasspathAssetSource source, String path, Locale locale,
-            Asset asset)
-    {
-        expect(source.getClasspathAsset(path, locale)).andReturn(asset);
-    }
-
-    private void toClientURL(Asset asset, String clientURL)
-    {
-        expect(asset.toClientURL()).andReturn(clientURL);
-    }
-
-    protected final <T> void train_peek(Environment env, Class<T> type, T value)
-    {
-        expect(env.peek(type)).andReturn(value);
-    }
-
-    protected final Environment newEnvironment()
-    {
-        return newMock(Environment.class);
-    }
-
-    protected final ClasspathAssetSource newClasspathAssetSource()
-    {
-        return newMock(ClasspathAssetSource.class);
     }
 }

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/PageLoaderImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/PageLoaderImplTest.java?view=diff&rev=492313&r1=492312&r2=492313
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/PageLoaderImplTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/PageLoaderImplTest.java Wed Jan  3 13:41:45 2007
@@ -122,7 +122,7 @@
 
         train_getTokens(
                 template,
-                new StartComponentToken("foo", "Fred", null, l),
+                new StartComponentToken(null, "foo", "Fred", null, l),
                 new EndElementToken(null));
 
         train_getEmbeddedComponentModel(model, "foo", emodel);

Added: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/PageTemplateLocatorImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/PageTemplateLocatorImplTest.java?view=auto&rev=492313
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/PageTemplateLocatorImplTest.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/PageTemplateLocatorImplTest.java Wed Jan  3 13:41:45 2007
@@ -0,0 +1,95 @@
+package org.apache.tapestry.internal.services;
+
+import java.util.Locale;
+
+import org.apache.tapestry.internal.test.InternalBaseTestCase;
+import org.apache.tapestry.ioc.Resource;
+import org.apache.tapestry.model.ComponentModel;
+import org.apache.tapestry.services.ComponentClassResolver;
+import org.testng.annotations.Test;
+
+public class PageTemplateLocatorImplTest extends InternalBaseTestCase
+{
+    @Test
+    public void not_a_page_class()
+    {
+        ComponentModel model = newComponentModel();
+        Resource root = newResource();
+        ComponentClassResolver resolver = newComponentClassResolver();
+
+        train_getComponentClassName(model, "foo.bar.Baz");
+
+        replay();
+
+        PageTemplateLocator locator = new PageTemplateLocatorImpl(root, resolver);
+
+        assertNull(locator.findPageTemplateResource(model, Locale.FRENCH));
+
+        verify();
+    }
+
+    @Test
+    public void template_found()
+    {
+        ComponentModel model = newComponentModel();
+        Resource root = newResource();
+        Resource withExtension = newResource();
+        Resource forLocale = newResource();
+        Locale locale = Locale.FRENCH;
+        String className = "myapp.pages.Foo";
+
+        ComponentClassResolver resolver = newComponentClassResolver();
+
+        train_getComponentClassName(model, className);
+
+        train_resolvePageClassNameToPageName(resolver, className, "Foo");
+
+        train_forFile(root, "Foo.html", withExtension);
+        train_forLocale(withExtension, locale, forLocale);
+
+        replay();
+
+        PageTemplateLocator locator = new PageTemplateLocatorImpl(root, resolver);
+
+        assertSame(locator.findPageTemplateResource(model, locale), forLocale);
+
+        verify();
+    }
+
+    @Test
+    public void template_not_found()
+    {
+        ComponentModel model = newComponentModel();
+        Resource root = newResource();
+        Resource withExtension = newResource();
+        Locale locale = Locale.GERMAN;
+        String className = "myapp.pages.bar.Baz";
+
+        ComponentClassResolver resolver = newComponentClassResolver();
+
+        train_getComponentClassName(model, className);
+
+        train_resolvePageClassNameToPageName(resolver, className, "bar/Baz");
+
+        train_forFile(root, "bar/Baz.html", withExtension);
+        train_forLocale(withExtension, locale, null);
+
+        replay();
+
+        PageTemplateLocator locator = new PageTemplateLocatorImpl(root, resolver);
+
+        assertNull(locator.findPageTemplateResource(model, locale));
+
+        verify();
+    }
+
+    protected final void train_forLocale(Resource base, Locale locale, Resource resource)
+    {
+        expect(base.forLocale(locale)).andReturn(resource);
+    }
+
+    protected final void train_forFile(Resource root, String path, Resource resource)
+    {
+        expect(root.forFile(path)).andReturn(resource);
+    }
+}

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/TemplateParserImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/TemplateParserImplTest.java?view=diff&rev=492313&r1=492312&r2=492313
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/TemplateParserImplTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/TemplateParserImplTest.java Wed Jan  3 13:41:45 2007
@@ -44,8 +44,6 @@
 /**
  * This is used to test the template parser ... and in some cases, the underlying behavior of the
  * SAX APIs.
- * <p>
- * The tests are run sequentially, as they all share a single template parser.
  */
 public class TemplateParserImplTest extends TapestryTestCase
 {
@@ -278,6 +276,7 @@
 
         assertEquals(start.getId(), "fred");
         assertEquals(start.getType(), "Fred");
+        assertNull(start.getElement());
 
         AttributeToken attr = get(tokens, 1);
 
@@ -288,6 +287,61 @@
     }
 
     @Test
+    public void instrumented_element()
+    {
+        List<TemplateToken> tokens = tokens("instrumented_element.html");
+
+        assertEquals(tokens.size(), 3);
+
+        StartComponentToken start = get(tokens, 0);
+
+        assertEquals(start.getId(), "fred");
+        assertEquals(start.getType(), "Fred");
+        assertEquals(start.getElement(), "html");
+
+        AttributeToken attr = get(tokens, 1);
+
+        assertEquals(attr.getName(), "param");
+        assertEquals(attr.getValue(), "value");
+
+        assertTrue(EndElementToken.class.isInstance(tokens.get(2)));
+    }
+
+    @Test
+    public void unexpected_attribute_in_instrumented_element()
+    {
+        try
+        {
+            tokens("unexpected_attribute_in_instrumented_element.html");
+            unreachable();
+        }
+        catch (TapestryException ex)
+        {
+            assertTrue(ex.getMessage().contains(
+                    "Attribute 't:xid' is not defined in the Tapestry template schema."));
+            assertNotNull(ex.getLocation());
+        }
+    }
+
+    @Test
+    public void mixin_requires_id_or_type()
+    {
+        try
+        {
+            tokens("mixin_requires_id_or_type.html");
+            unreachable();
+        }
+        catch (TapestryException ex)
+        {
+            assertTrue(ex
+                    .getMessage()
+                    .contains(
+                            "You may not specify mixins for element <span> because it does not represent a component (which requires either an id attribute or a type attribute)."));
+            assertNotNull(ex.getLocation());
+        }
+    }
+
+    @Test
     void body_element()
     {
         List<TemplateToken> tokens = tokens("body_element.html");
@@ -295,7 +349,7 @@
         // start(html), text, body, text, end(html)
         assertEquals(tokens.size(), 5);
 
-        // javac bug is requires use of isInstance() instead of instanceof
+        // javac bug requires use of isInstance() instead of instanceof
         // https://bugs.eclipse.org/bugs/show_bug.cgi?id=113218
         assertTrue(BodyToken.class.isInstance(get(tokens, 2)));
     }

Added: tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/internal/services/instrumented_element.html
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/internal/services/instrumented_element.html?view=auto&rev=492313
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/internal/services/instrumented_element.html (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/internal/services/instrumented_element.html Wed Jan  3 13:41:45 2007
@@ -0,0 +1 @@
+<html t:id="fred" t:type="Fred" param="value" xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd"/>

Added: tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/internal/services/mixin_requires_id_or_type.html
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/internal/services/mixin_requires_id_or_type.html?view=auto&rev=492313
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/internal/services/mixin_requires_id_or_type.html (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/internal/services/mixin_requires_id_or_type.html Wed Jan  3 13:41:45 2007
@@ -0,0 +1,3 @@
+<html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd">
+    <span t:mixins="Whatever" param="value" />    
+</html>
\ No newline at end of file

Added: tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/internal/services/unexpected_attribute_in_instrumented_element.html
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/internal/services/unexpected_attribute_in_instrumented_element.html?view=auto&rev=492313
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/internal/services/unexpected_attribute_in_instrumented_element.html (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/internal/services/unexpected_attribute_in_instrumented_element.html Wed Jan  3 13:41:45 2007
@@ -0,0 +1,3 @@
+<html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd">
+    <span t:xid="fred" t:type="Fred" param="value" />    
+</html>
\ No newline at end of file