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 2006/10/01 23:44:10 UTC

svn commit: r451817 [2/3] - in /tapestry/tapestry5/tapestry-core/trunk/src: main/java/org/apache/tapestry/annotations/ main/java/org/apache/tapestry/corelib/ main/java/org/apache/tapestry/corelib/components/ main/java/org/apache/tapestry/corelib/pages/...

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/ClassPropertyAdapter.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/ClassPropertyAdapter.java?view=diff&rev=451817&r1=451816&r2=451817
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/ClassPropertyAdapter.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/ClassPropertyAdapter.java Sun Oct  1 14:44:07 2006
@@ -14,6 +14,8 @@
 
 package org.apache.tapestry.ioc.services;
 
+import java.util.List;
+
 /**
  * Organizes all {@link org.apache.tapestry.ioc.services.PropertyAdapter}s for a particular class.
  * 
@@ -21,6 +23,9 @@
  */
 public interface ClassPropertyAdapter
 {
+    /** Returns the names of all properties, sorted into alphabetic order. */
+    List<String> getPropertyNames();
+
     /**
      * Returns the property adapter with the given name, or null if no such adapter exists.
      */

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/ExceptionAnalysis.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/ExceptionAnalysis.java?view=auto&rev=451817
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/ExceptionAnalysis.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/ExceptionAnalysis.java Sun Oct  1 14:44:07 2006
@@ -0,0 +1,19 @@
+package org.apache.tapestry.ioc.services;
+
+import java.util.List;
+
+/**
+ * An analysis of an exception (including nested exceptions).
+ * <p>
+ * TODO: Make serializable and/or convert to XML format.
+ * 
+ * @author Howard M. Lewis Ship
+ */
+public interface ExceptionAnalysis
+{
+    /**
+     * Returns the analyzed exception info for each exception. The are ordered outermost exception
+     * to innermost.
+     */
+    List<ExceptionInfo> getExceptionInfos();
+}

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/ExceptionAnalyzer.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/ExceptionAnalyzer.java?view=auto&rev=451817
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/ExceptionAnalyzer.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/ExceptionAnalyzer.java Sun Oct  1 14:44:07 2006
@@ -0,0 +1,12 @@
+package org.apache.tapestry.ioc.services;
+
+/**
+ * Analyzes an exception, providing an analysis. The analysis easily exposes properties of the
+ * exception, the stack trace, and nested exceptions.
+ * 
+ * @author Howard M. Lewis Ship
+ */
+public interface ExceptionAnalyzer
+{
+    ExceptionAnalysis analyze(Throwable rootException);
+}

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/ExceptionInfo.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/ExceptionInfo.java?view=auto&rev=451817
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/ExceptionInfo.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/ExceptionInfo.java Sun Oct  1 14:44:07 2006
@@ -0,0 +1,30 @@
+package org.apache.tapestry.ioc.services;
+
+import java.util.List;
+
+/**
+ * Contains information about an analyzed exception.
+ * 
+ * @author Howard M. Lewis Ship
+ * @see {@link ExceptionAnalysis}
+ */
+public interface ExceptionInfo
+{
+    /** The exception class name. */
+    String getClassName();
+
+    /** The message associated with the exception, possibly null. */
+    String getMessage();
+
+    /** Returns the names of the properties of the exception, sorted alphabetically. */
+    List<String> getPropertyNames();
+
+    /** Returns a specific property of the exception by name. */
+    Object getProperty(String name);
+
+    /**
+     * Returns the stack trace elements. Generally this is an empty list except for the deepest
+     * exception.
+     */
+    List<String> getStackTrace();
+}

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/TapestryIOCModule.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/TapestryIOCModule.java?view=diff&rev=451817&r1=451816&r2=451817
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/TapestryIOCModule.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/TapestryIOCModule.java Sun Oct  1 14:44:07 2006
@@ -18,6 +18,7 @@
 
 import org.apache.tapestry.internal.ioc.services.ChainBuilderImpl;
 import org.apache.tapestry.internal.ioc.services.DefaultImplementationBuilderImpl;
+import org.apache.tapestry.internal.ioc.services.ExceptionAnalyzerImpl;
 import org.apache.tapestry.internal.ioc.services.ExceptionTrackerImpl;
 import org.apache.tapestry.internal.ioc.services.LoggingDecoratorImpl;
 import org.apache.tapestry.internal.ioc.services.MasterObjectProvider;
@@ -156,5 +157,11 @@
     public ExceptionTracker buildExceptionTracker()
     {
         return new ExceptionTrackerImpl();
+    }
+
+    public ExceptionAnalyzer buildExceptionAnalyzer(@InjectService("PropertyAccess")
+    PropertyAccess access)
+    {
+        return new ExceptionAnalyzerImpl(access);
     }
 }

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/model/EmbeddedComponentModel.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/model/EmbeddedComponentModel.java?view=diff&rev=451817&r1=451816&r2=451817
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/model/EmbeddedComponentModel.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/model/EmbeddedComponentModel.java Sun Oct  1 14:44:07 2006
@@ -16,6 +16,8 @@
 
 import java.util.List;
 
+import org.apache.tapestry.annotations.Component;
+
 /**
  * The model for a component embedded within another component, as defined by the
  * {@link org.apache.tapestry.annotations.Component} annotation.
@@ -27,8 +29,14 @@
     /** A unique id for the embedded component. */
     String getId();
 
-    /** The type of the component. */
+    /** The type of the component, which may be blank. */
     String getComponentType();
+
+    /**
+     * The class name of the component, as derived from the field to which the {@link Component}
+     * annotation is applied. This value is only used when the componentType property is blank.
+     */
+    String getComponentClassName();
 
     /** A sorted list of the names of all bound parameters. */
     List<String> getParameterNames();

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/model/MutableComponentModel.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/model/MutableComponentModel.java?view=diff&rev=451817&r1=451816&r2=451817
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/model/MutableComponentModel.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/model/MutableComponentModel.java Sun Oct  1 14:44:07 2006
@@ -26,7 +26,7 @@
      * Adds a new parameter to the model.
      * 
      * @param name
-     *            new, unique name for the parameter
+     *            new, unique n`ame for the parameter
      * @param required
      *            if true, the parameter must be bound
      * @throws IllegalArgumentException
@@ -40,8 +40,11 @@
      * @param id
      *            the unique id for the embedded component, which must not already exist.
      * @param type
-     *            the type of the component
+     *            the type of the component (posslibly blank)
+     * @param componentClassName
+     *            the fully qualified class name (derived from the field), used if the type is blank
      * @return a mutable model allowing parameters to be set
      */
-    MutableEmbeddedComponentModel addEmbeddedComponent(String id, String type);
+    MutableEmbeddedComponentModel addEmbeddedComponent(String id, String type,
+            String componentClassName);
 }

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/CoercionTuple.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/CoercionTuple.java?view=diff&rev=451817&r1=451816&r2=451817
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/CoercionTuple.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/CoercionTuple.java Sun Oct  1 14:44:07 2006
@@ -26,7 +26,7 @@
  * @param <T>
  *            target (output) type
  */
-public class CoercionTuple<S, T>
+public final class CoercionTuple<S, T>
 {
     private final Class<S> _sourceType;
 

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/ComponentClassResolver.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/ComponentClassResolver.java?view=diff&rev=451817&r1=451816&r2=451817
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/ComponentClassResolver.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/ComponentClassResolver.java Sun Oct  1 14:44:07 2006
@@ -15,7 +15,46 @@
 package org.apache.tapestry.services;
 
 /**
- * Resolves partial names of pages (i.e., root components) and components.
+ * Resolves page names and component types to fully qualified class names. Pages and components may
+ * be provided by the application or inside a <em>mapped package</em>. Page names often appear
+ * inside URLs, and component types often appear in component template (when specifying the type of
+ * an embedded component).
+ * <p>
+ * The service is configured using a collection of {@link LibraryMapping}s. Each mapping maps a
+ * prefix, such as "core" to a root package name, such as "org.apache.tapestry.corelib". The root
+ * package is expected to have two sub-packages, "pages" and "components". Page names are searched
+ * for in the pages package, and components types are searched for the components package.
+ * <p>
+ * When searching, the portion of the page name (or component type) before the slash is compared
+ * with known prefixes in order to find the correct root package name. Thus when encountering the
+ * page name (or component type) "foo/Bar", a search for a mapping for prefix "foo" will occur. If
+ * "foo" is mapped, then the final class name will be built from foo's root package, then "pages"
+ * (or "components"), then "Bar".
+ * <p>
+ * If "foo" is not mapped, then the name is resolved as part of the application. The final class
+ * name will be "<em>application-root</em>.pages.foo.Bar", meaning that the prefix is
+ * interpreted as a package name under the appropriate root package.
+ * <p>
+ * Prefixes are only search for based on using the forward slash ("/") as a delimiter. Following the
+ * slash, a period (".") may be used to signify, unambiguously, a sub-package.
+ * <p>
+ * Prefixes themselves may be more complex; a search for "foo/bar/Baz" will first search for a
+ * "foo/bar" prefix, then (if not found), a "foo" prefix.
+ * <p>
+ * When a package name or component type can not be resolved as is, the special library mapping,
+ * "core" is used (this represents the Tapestry core components, as package under
+ * org.apache.tapestry.corelib). In this way, the names of "builtin" components can be referenced as
+ * if they were part of the application. Further, an application may <em>override</em> the builtin
+ * components (though this should rarely, if ever, be necessary and should only be undertaken with
+ * extreme caution).
+ * <p>
+ * A given mapping may have <em>multiple root packages</em>. This is occasionally useful, but
+ * (again) should be used with care, as this can cause distruptive behavior in the application if
+ * abused, especiallyl in the face of ambiguities such as duplicate named classes in different
+ * packages mapped to the same prefix.
+ * <p>
+ * Certain ambiguities occur if mapped packages overlap, either in terms of the the prefixes or the
+ * package names. Keep things clearly seperate to avoid lookup problems.
  * 
  * @author Howard M. Lewis Ship
  */
@@ -27,7 +66,7 @@
      * 
      * @param pageName
      *            partial name
-     * @return fully qualified class name
+     * @return fully qualified class name of null if the page name can not be resolved
      */
     String resolvePageNameToClassName(String pageName);
 
@@ -37,7 +76,7 @@
      * 
      * @param componentType
      *            either a partial component class name, or a complete class name
-     * @return fully qualified class name
+     * @return fully qualified class name or null if the component type can not be resolved
      */
     String resolveComponentTypeToClassName(String componentType);
 

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/ExceptionReporter.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/ExceptionReporter.java?view=auto&rev=451817
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/ExceptionReporter.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/ExceptionReporter.java Sun Oct  1 14:44:07 2006
@@ -0,0 +1,17 @@
+package org.apache.tapestry.services;
+
+/**
+ * Interface implemented by a page used for reporting exceptions.
+ * 
+ * @author Howard M. Lewis Ship
+ * @see RequestExceptionHandler
+ */
+public interface ExceptionReporter
+{
+    /**
+     * Used to communicate to the page what exception is to be reported.
+     * 
+     * @param exception
+     */
+    void reportException(Throwable exception);
+}

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/LibraryMapping.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/LibraryMapping.java?view=auto&rev=451817
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/LibraryMapping.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/LibraryMapping.java Sun Oct  1 14:44:07 2006
@@ -0,0 +1,39 @@
+package org.apache.tapestry.services;
+
+/**
+ * Used to configure the {@link ComponentClassResolver}, to allow it to map prefixes to library
+ * root packages (the application namespace is a special case of this). In each case, a prefix on
+ * the path is mapped to a package. Prefixes should start with a character and end with a slash, as
+ * in "core". The root package name should have two sub-packages: "pages" to contain named pages,
+ * and "components" to contain named components.
+ * 
+ * @author Howard M. Lewis Ship
+ */
+public final class LibraryMapping
+{
+    private final String _pathPrefix;
+
+    private final String _rootPackage;
+
+    public LibraryMapping(String pathPrefix, String rootPackage)
+    {
+        _pathPrefix = pathPrefix;
+        _rootPackage = rootPackage;
+    }
+
+    public String getPathPrefix()
+    {
+        return _pathPrefix;
+    }
+
+    public String getRootPackage()
+    {
+        return _rootPackage;
+    }
+
+    @Override
+    public String toString()
+    {
+        return String.format("LibraryMapping[%s, %s]", _pathPrefix, _rootPackage);
+    }
+}

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/RequestExceptionHandler.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/RequestExceptionHandler.java?view=auto&rev=451817
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/RequestExceptionHandler.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/RequestExceptionHandler.java Sun Oct  1 14:44:07 2006
@@ -0,0 +1,22 @@
+package org.apache.tapestry.services;
+
+import java.io.IOException;
+
+/**
+ * Service invoked when an uncaught exception occurs. The error handler is responsible for providing
+ * a response to the user to describe the error.
+ * 
+ * @author Howard M. Lewis Ship
+ */
+public interface RequestExceptionHandler
+{
+    /**
+     * Reponsible for handling the error <em>in some way</em> and providing <em>some response</em>
+     * to the client. A default implementation may render an error response page.
+     * 
+     * @param exception
+     *            uncaught exception to be reported
+     * @throws IOException
+     */
+    void handleRequestException(Throwable exception) throws IOException;
+}

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=451817&r1=451816&r2=451817
==============================================================================
--- 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 Sun Oct  1 14:44:07 2006
@@ -202,12 +202,11 @@
     }
 
     /** Dispatcher that recognizes full-page HTML documents by the .html extension. */
-    public Dispatcher buildHTMLDispatcher(@InjectService("ComponentClassResolver")
-    ComponentClassResolver resolver, @InjectService("tapestry.internal.PageResponseRenderer")
+    public Dispatcher buildHTMLDispatcher(@InjectService("tapestry.internal.PageResponseRenderer")
     PageResponseRenderer renderer, @InjectService("tapestry.internal.RequestPageCache")
     RequestPageCache cache)
     {
-        return new HTMLDispatcher(resolver, renderer, cache);
+        return new HTMLDispatcher(renderer, cache);
     }
 
     public HttpServletRequestHandler buildHttpServletRequestHandler(Log log,
@@ -277,6 +276,15 @@
         return _shadowBuilder.build(_requestGlobals, "request", WebRequest.class);
     }
 
+    /**
+     * Builds a shadow of the RequestGlobals.response property. Note again that the shadow can be an
+     * ordinary singleton, even though RequestGlobals is perthread.
+     */
+    public WebResponse buildWebResponse()
+    {
+        return _shadowBuilder.build(_requestGlobals, "response", WebResponse.class);
+    }
+
     public WebRequestHandler buildWebRequestHandler(Log log, List<WebRequestFilter> configuration,
             @InjectService("MasterDispatcher")
             final Dispatcher masterDispatcher)
@@ -306,11 +314,36 @@
      */
     public void contributeWebRequestHandler(OrderedConfiguration<WebRequestFilter> configuration,
             @InjectService("WebContext")
-            WebContext webContext)
+            WebContext webContext,
+            @InjectService("tapestry.internal.DefaultRequestExceptionHandler")
+            final RequestExceptionHandler exceptionHandler)
     {
-        WebRequestFilter filter = new StaticFilesFilter(webContext);
+        WebRequestFilter staticFilesFilter = new StaticFilesFilter(webContext);
+
+        configuration.add("StaticFilesFilter", staticFilesFilter);
+
+        WebRequestFilter errorFilter = new WebRequestFilter()
+        {
+            public boolean service(WebRequest request, WebResponse response,
+                    WebRequestHandler handler) throws IOException
+            {
+                try
+                {
+                    return handler.service(request, response);
+                }
+                catch (RuntimeException ex)
+                {
+                    exceptionHandler.handleRequestException(ex);
 
-        configuration.add("StaticFilesFilter", filter);
+                    // We assume a reponse has been sent and there's no need to handle the request
+                    // further.
+
+                    return true;
+                }
+            }
+        };
+
+        configuration.add("ErrorFilter", errorFilter);
     }
 
     /**
@@ -371,9 +404,20 @@
 
     public ComponentClassResolver buildComponentClassResolver(
             @InjectService("tapestry.internal.ComponentInstantiatorSource")
-            ComponentInstantiatorSource source)
+            ComponentInstantiatorSource source, Collection<LibraryMapping> configuration)
+    {
+        ComponentClassResolverImpl service = new ComponentClassResolverImpl(source, configuration);
+
+        // Allow the resolver to clean its cache when the source is invalidated
+
+        source.addInvalidationListener(service);
+
+        return service;
+    }
+
+    public void contributeComponentClassResolver(Configuration<LibraryMapping> configuration)
     {
-        return new ComponentClassResolverImpl(source);
+        configuration.add(new LibraryMapping("core", "org.apache.tapestry.corelib"));
     }
 
     public BindingSource buildBindingSource(Map<String, BindingFactory> configuration)

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/corelib/pages/ExceptionReport.html
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/corelib/pages/ExceptionReport.html?view=auto&rev=451817
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/corelib/pages/ExceptionReport.html (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/corelib/pages/ExceptionReport.html Sun Oct  1 14:44:07 2006
@@ -0,0 +1,21 @@
+<html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd">
+    <head>
+        <title>An Exception Has Occurred</title>
+    </head>
+    <body>
+        <p> A runtime exception has occurred. </p>
+
+        <ul class="tapestry-exception-report">
+            <t:comp type="Loop" source="prop:stack" value="prop:info">
+                <li>${info.className} <dl>
+                        <t:comp type="If" test="prop:info.message">
+                            <dt>Message:</dt>
+                            <dd>${info.message}</dd>
+                        </t:comp>
+                    </dl>
+                </li>
+            </t:comp>
+        </ul>
+
+    </body>
+</html>

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/internal/bindings/BindingsStrings.properties
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/internal/bindings/BindingsStrings.properties?view=diff&rev=451817&r1=451816&r2=451817
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/internal/bindings/BindingsStrings.properties (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/internal/bindings/BindingsStrings.properties Sun Oct  1 14:44:07 2006
@@ -14,4 +14,5 @@
 
 binding-is-read-only=Binding %s is read-only.
 binding-is-write-only=Binding %s is write-only.
-no-such-property=Class %s does not contain a property named '%s'.
\ No newline at end of file
+no-such-property=Class %s does not contain a property named '%s' (within property path '%s').
+write-only-property=Property '%s' of class %s (within property path '%s') is not readable (it has no read accessor method).

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=451817&r1=451816&r2=451817
==============================================================================
--- 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 Sun Oct  1 14:44:07 2006
@@ -47,4 +47,6 @@
   or define the component inside class %s using the @Component annotation on a private instance variable.
 embedded-components-not-in-template=Embedded component(s) %s are defined within component class %s, but are not present in the component template.
 binding-source-failure=Could not convert '%s' into a component parameter binding: %s
-no-coercion-found=Could not find a coercion from type %s to type %s.  Available coercions: %s.
\ No newline at end of file
+no-coercion-found=Could not find a coercion from type %s to type %s.  Available coercions: %s.
+unable-to-resolve-component-type=Unable to resolve component '%s' to a component class name.
+page-does-not-exist=Page '%s' is not defined by this application.
\ No newline at end of file

Modified: tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/coercion.apt
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/coercion.apt?view=diff&rev=451817&r1=451816&r2=451817
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/coercion.apt (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/coercion.apt Sun Oct  1 14:44:07 2006
@@ -9,11 +9,11 @@
   Type coercions occur when a value passed into a parameter (as bound in template or
   in an annoation) does not match the type of the parameter.
   
-  For example, consider the Loop component:
+  For example, consider the Count component:
   
 +---+
 @ComponentClass
-public class Loop
+public class Count
 {
     @Parameter
     private int _start = 1;
@@ -32,7 +32,7 @@
   However, it is likely that the component will be used as so:
   
 +---+
-  Merry Christmas: <t:comp type="Loop" end="3"> Ho! </t:comp>
+  Merry Christmas: <t:comp type="Count" end="3"> Ho! </t:comp>
 +---+
 
   Here the end parameter is bound to the <literal string> "3".
@@ -44,7 +44,12 @@
   The {{{../apidoc/org/apache/tapestry/services/TypeCoercer.html}tapestry.TypeCoercer}} service
   is responsible for this type coercion.
   
-  It is configured with a set of
+  The service is quite flexible; it is configured with a 
+  {{{../apidocs/org/apache/tapestry/services/TapestryModule.html#contributeTypeCoercer}basic set of coercions}}
+  for common cases, such as String --\> Long or Object --\> String, and can automatically
+  discover more complex coercions (for example, StringBuffer --\> String --\> Long --\> Integer). 
+  
+  The service's configuration is a collection of
   {{{../apidoc/org/apache/tapestry/service/CoercionTuple.html}CoercionTuple}}s.  Each of
   these tuples defines a source type, a target type, and a bit of code to perform the coersion.
   
@@ -61,17 +66,9 @@
   }
 );
 +---+
-
-  The service starts with
-  {{{../apidocs/org/apache/tapestry/services/TapestryModule.html#contributeTypeCoercer}a number of coercions}}. The service
-  can infer additional coercions as needed.  The service automatically searches up the inheritance hierarchy to find potential
-  coercions, and can combine existing coercions to create new ones.
-  
-  For example, to coerce an instance of StringBuffer into an Integer, the service will use the Object --> String coercion,
-  then the String --> Double coercion, then the Number --> Integer coercion.
   
-  As a special case, the service treats null input values as if they were instances of void. This allows tuples
-  for converting nulls:
+  As a special case, the service treats null input values as if they were instances of the special type Void. 
+  This allows tuples for converting nulls:
   
 +---+
 new CoercionTuple<Void,Boolean>(Void.class, Boolean.class,

Modified: tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/component-classes.apt
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/component-classes.apt?view=diff&rev=451817&r1=451816&r2=451817
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/component-classes.apt (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/component-classes.apt Sun Oct  1 14:44:07 2006
@@ -143,33 +143,40 @@
   Example:
   
 +---+
+package org.example.app.pages;
+
+import org.apache.tapestry.annotations.Component;
+import org.apache.tapestry.annotations.ComponentClass;
+import org.example.app.components.Count;
+
 @ComponentClass
 public class Countdown
 {
     @Component(parameters =
-    { "start=5", "end=1", "value=count" })
-    private Loop _loop;  
+    { "start=5", "end=1", "value=countValue" })
+    private Count _count;  
   
-    private int _count;
+    private int _countValue;
 
-    public int getCount()
+    public int getCountValue()
     {
-        return _count;
+        return _countValue;
     }
 
-    public void setCount(int count)
+    public void setCountValue(int countValue)
     {
-        _count = count;
+        _countValue = countValue;
     }
 }  
 +---+
 
-  The above defines a component whose embedded id is "loop" (this id is derived from the name of the field).  The type
-  of component is Loop.  The start and end parameters of the Loop component are bound to literal values, and the value
-  parameter of the Loop component is bound to the count property of the Countdown component.
+  The above defines a component whose embedded id is "count" (this id is derived from the name of the field).  The type
+  of component is org.example.app.components.Count.  
+  The start and end parameters of the Count component are bound to literal values, and the value
+  parameter of the Count component is bound to the countValue property of the Countdown component.
   
   Note that inside the component class, the default binding prefix is "prop:", whereas inside a component template,
-  the default binding prefix is "literal:".  In the example we could write <<<"value=prop:count">>> if we desired to be
+  the default binding prefix is "literal:".  In the example we could write <<<"value=prop:countValue">>> if we desired to be
   fully explicit.
   
   However, certain literal values, such as the numeric literals in the example,
@@ -182,7 +189,8 @@
   
   <<TODO: May want a more complex check; what if user uses prop: in the template and there's a conflict?>>
   
-  You may override the id using the id() attribute of the Component annotation.
+  You may override the default component id (as derived from the field name)
+  using the id() attribute of the Component annotation.
   
   If you define a component in the component class, and there is no corresponding \<comp\> element in the template,
   Tapestry will log an error.

Modified: tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/inject.apt
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/inject.apt?view=diff&rev=451817&r1=451816&r2=451817
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/inject.apt (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/inject.apt Sun Oct  1 14:44:07 2006
@@ -13,7 +13,7 @@
   
 Inject Annotation
 
-  The {{{../apidocs/org/apache/tapestry/annotations/Inject.html}@Inject annotation}} is used to identify fields that will contain injected services and other resources.
+  The {{{../apidocs/org/apache/tapestry/annotations/Inject.html}Inject annotation}} is used to identify fields that will contain injected services and other resources.
   
   Tapestry allows for two kinds of injection:
   
@@ -54,7 +54,7 @@
   A very common example occurs when a component needs access to its
   {{{../apidocs/org/apache/tapestry/ComponentResources.html}resources}}.  The component
   can define a field of the appropriate type
-  and use the @Inject annotation without a value:
+  and use the Inject annotation without a value:
   
 +----+
 @Inject

Modified: tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/parameters.apt
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/parameters.apt?view=diff&rev=451817&r1=451816&r2=451817
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/parameters.apt (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/parameters.apt Sun Oct  1 14:44:07 2006
@@ -21,7 +21,7 @@
   it will automatically count up or down depending on whether start or end is larger.
   
 +---+
-package org.example.myapp.components;
+package org.example.app.components;
 
 import org.apache.tapestry.annotations.AfterRender;
 import org.apache.tapestry.annotations.ComponentClass;
@@ -29,7 +29,7 @@
 import org.apache.tapestry.annotations.SetupRender;
 
 @ComponentClass
-public class Loop
+public class Count
 {
     @Parameter
     private int _start = 1;
@@ -60,7 +60,7 @@
             if (newValue <= _end)
             {
                 _value = newValue;
-                return true; // re-render body
+                return true; 
             }
         }
         else
@@ -70,7 +70,7 @@
             if (newValue >= _end)
             {
                 _value = newValue;
-                return true; // re-render body
+                return true; 
             }
         }
 
@@ -89,21 +89,22 @@
   
 +---+
 <t:comp type="Border" xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd">
-    <p> Merry Christmas: <t:comp type="Loop" end="3"> Ho! </t:comp>
+    <p> Merry Christmas: <t:comp type="Count" end="3"> Ho! </t:comp>
     </p>
 </t:comp>
 +---+  
   
   Inside the \<comp\> element, the end attribute is used to <bind> the end parameter of the
-  Loop component.  Here, it is being bound to the string value "3", which is automatically
+  Count component.  Here, it is being bound to the string value "3", which is automatically
   {{{coercion.html}coerced}} by Tapestry into the int value, 3.
     
   Any number of parameters may be bound this way.
   
   Component parameters may also be bound using the
-  {{{component-classes.html#Embedded Components}@Component annotation}} inside the component class.
+  {{{component-classes.html#Embedded Components}Component annotation}} inside the component class.
   
-  Where conflicts occur, the component takes precendence over parameter bindings
+  Where conflicts occur, the parameters bound using the Component annotation will
+  take precendence over parameter bindings
   in the template.
     
 Binding Expressions
@@ -170,15 +171,15 @@
 +---+
 <t:comp type="Border" xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd">
     <p> Countdown:
-        <t:comp type="Loop" start="5" end="1" value="prop:index"> 
+        <t:comp type="Count" start="5" end="1" value="prop:index"> 
           ${index} ...  
         </t:comp>
     </p>
 </t:comp>
 +---+   
 
-  Because the Loop component updates its value parameter (the _value field), the index property
-  of the containing component is updated.  Inside the Loop's body, we output the current
+  Because the Count component updates its value parameter (the _value field), the index property
+  of the containing component is updated.  Inside the Count's body, we output the current
   value of the index property, using the expansion <<<$\{index\}>>>. The resulting output
   will look something like:
   
@@ -200,7 +201,7 @@
 
   Parameters which are not required, are optional.  
   
-  You may set a default value for optional parameters as you would for any other field. In the Loop component,
+  You may set a default value for optional parameters as you would for any other field. In the Count component,
   the min parameter has a default value of 1. That value is used unless the min parameter is bound,
   in which case, the bound value supercedes the default.
   
@@ -208,7 +209,7 @@
 
   If a parameter is not bound (and is optional), then the value may be read or <updated> at any time.
   
-  Updates to unbound parameters cause no side effects.  In the first example, the value parameter of the Loop
+  Updates to unbound parameters cause no side effects.  In the first example, the value parameter of the Count
   component is not bound, and this is perfectly valid.
   
   Note: updates to such fields are temporary; when the component finishes rendering, the field
@@ -268,7 +269,7 @@
   The above sketch illustrates the approach.  Because the parameter type is a primitive type, int,
   it is hard to distinguish between no binding, and binding explicitly to the value 0.
   
-  The @Inject annotation will inject the
+  The Inject annotation will inject the
   {{{../apidocs/org/apache/tapestry/ComponentResources.html}ComponentResources}} for the component.
   These resources are the linkage between the Java class you provide, and the infrastructure Tapestry
   builds around your class.  In any case, once the resources are injected,

Modified: tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/rendering.apt
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/rendering.apt?view=diff&rev=451817&r1=451816&r2=451817
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/rendering.apt (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/rendering.apt Sun Oct  1 14:44:07 2006
@@ -8,7 +8,7 @@
  
  Rendering was a recursive process. Each component implemented a render() method
  (inherited from an IRender interface).
- Component's would invoke render() on the objects in their template, including
+ Components would invoke render() on the objects in their template, including
  other components. 
  
  {{{http://blog.rapidred.com/}Bruce Tate}} has said "if you get veritgo, don't
@@ -48,11 +48,12 @@
   
   These methods are <<optional>>, a default behavior is associated with each phase.
  
-  Here's the source for a looping component that renders its body a number of times,
+  Here's the source for a looping component that counts up or down between two values,
+  renders its body a number of times,
   and stores the current index value in a parameter:
   
 +---+
-package org.example.myapp.components;
+package org.example.app.components;
 
 import org.apache.tapestry.annotations.ComponentClass;
 import org.apache.tapestry.annotations.Parameter;
@@ -60,32 +61,49 @@
 import org.apache.tapestry.annotations.SetupRender;
 
 @ComponentClass
-public class Loop
+public class Count
 {
     @Parameter
-    private int _min = 1;
+    private int _start = 1;
 
     @Parameter(required = true)
-    private int _max;
+    private int _end;
 
     @Parameter
     private int _value;
 
+    private boolean _increment;
+
     @SetupRender
     void initializeValue()
     {
-        _value = _min;
+        _value = _start;
+
+        _increment = _start < _end;
     }
 
     @AfterRender
-    boolean increment()
+    boolean next()
     {
-        int newValue = _value + 1;
+        if (_increment)
+        {
+            int newValue = _value + 1;
 
-        if (newValue <= _max)
+            if (newValue <= _end)
+            {
+                _value = newValue;
+                return true;
+            }
+        }
+        else
         {
-            _value = newValue;
-            return true;
+            int newValue = _value - 1;
+
+            if (newValue >= _end)
+            {
+                _value = newValue;
+                return true; 
+            }
         }
 
         return false;
@@ -93,7 +111,7 @@
 }
 +---+
   
-  Returning true from increment() causes Tapestry to re-run the BeginRender phase,
+  Returning true from next() causes Tapestry to re-run the BeginRender phase,
   and from there, re-render the component's body (this component does not have a template).
   Returning false transitions to the CleanupRender phase.
   
@@ -151,7 +169,7 @@
   This phase complements BeginRender, and is often used to render the close tag
   that matches the start tag rendered in the BeginRender phase.  In any case, the
   AfterRender phase can continue on to CleanupRender, or revert back to BeginRender (as
-  in our Loop component example, above).
+  in our Count component example, above).
   
   <TODO: Perhaps this should be called "FinishRender"?>
   

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=451817&r1=451816&r2=451817
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/templates.apt (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/templates.apt Sun Oct  1 14:44:07 2006
@@ -71,24 +71,24 @@
   
   The type attribute is optional; when not specified, Tapestry will expect the class to define
   the type of the component (with 
-  {{{component-classes.html#Embedded Components}a @Component annotation}}}).
+  {{{component-classes.html#Embedded Components}a Component annotation}}).
   
   Additional attributes are used to {{{parameters.html}bind parameters of the component}}.  
   When parameters are bound
-  in this way, the values are interpreted as literals unless a specific prefix is given.
+  in this way, the values are interpreted as literal string values unless a specific prefix is given.
   
-  The element defines where, within the containing component's template, the embedded component is active.
+  The \<comp\> element defines where, within the containing component's template, the embedded component is active.
   
   It also defines the <<body>> of the embedded component, the portion of the template enclosed by the open and close
   \<comp\> tags.
   
-  The following example presumes a component, "Loop" that iterates from a minimum value to
-  a maximum value, rendering its body on each iteration:
+  The following example presumes a component, "Count" that iterates from a start value (which defaults to 1) to
+  an end value (here specified as 3), rendering its body on each iteration:
   
 +----+
 <p>
     Merry Christmas:
-    <t:comp type="Loop" min="1" max="3">
+    <t:comp type="Count" end="3">
         Ho!
     </t:comp>
 </p>
@@ -102,7 +102,7 @@
   The \<body\> element is used to identify where, within a component's template, its
   body (from the container's template) is to be rendered.
   
-  Components have control over if, and even how often, its body is rendered.
+  Components have control over if, and even how often, their body is rendered.
   
   The following example is a Border component, that adds basic HTML elements
   around the page specific content:

Modified: tapestry/tapestry5/tapestry-core/trunk/src/site/resources/tap5devwiki.html
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/site/resources/tap5devwiki.html?view=diff&rev=451817&r1=451816&r2=451817
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/site/resources/tap5devwiki.html (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/site/resources/tap5devwiki.html Sun Oct  1 14:44:07 2006
@@ -5172,7 +5172,7 @@
 <div tiddler="MainMenu" modifier="HowardLewisShip" modified="200609210701" created="200609210643" tags="">MasterIndex\n[[RSS feed|tap5devwiki.xml]]\n\n[[Tapestry 5 Home|http://tapestry.apache.org/tapestry5/]]\n[[Howard's Blog|http://howardlewisship.com/blog/]]\n\n[[Formatting Help|http://www.blogjones.com/TiddlyWikiTutorial.html#EasyToEdit%20Welcome%20NewFeatures%20WhereToFindHelp]]</div>
 <div tiddler="MasterIndex" modifier="HowardLewisShip" modified="200609251541" created="200609202214" tags="">* PropBinding -- Notes on the workhorse &quot;prop:&quot; binding prefix\n* TypeCoercion -- How Tapestry 5 extensibly addresses type conversion\n* FormProcessing\n* DynamicPageState -- tracking changes to page state during the render\n* EnvironmentalServices -- how components cooperate during page render</div>
 <div tiddler="OGNL" modifier="HowardLewisShip" modified="200609202255" created="200609202254" tags="">The [[Object Graph Navigation Library|http://ognl.org]] was an essential part of Tapestry 4.\n\nOGNL is both exceptionally powerful (especially the higher order things it can do, such as list selections and projections). However, for the highest\nend sites, it is also a performance problem, both because of its heavy use of reflection, and because it uses a lot of code inside synchronized blocks.\n\nIt will be optional in Tapestry 5. I believe it will not be part of the tapestry-core, but may be packaged as tapestry-ognl.\n\nThe &quot;prop:&quot; binding prefix is a partial replacement for OGNL in Tapestry 5.  \n\nAs of this writing (Sep 20 2006), the built in support is limited to just simple property names.  At some point in the near future, the PropBindingImprovements will be implemented.</div>
-<div tiddler="PropBinding" modifier="HowardLewisShip" modified="200609232252" created="200609202203" tags="bindings">&quot;prop:&quot; the default in a  lot of cases, i.e., in any Java code.\n\nThis binding prefix  supports several common idioms even though they are not, precisely, the names of properties.  In many cases, this will save developers the bother of using a &quot;literal:&quot; prefix.\n\nThe goal of the &quot;prop:&quot; prefix is to be highly efficient and useful in 90%+ of the cases. [[OGNL]], or synthetic properties in the component class, will pick up the remaining cases.\n\n!Numeric literals\n\nSimple numeric literals should be parsed into read-only, invariant bindings.\n{{{\nprop:5\n\nprop:-22.7\n}}}\n\n\nThe resulting objects will be of type Long or type Double. TypeCoercion will ensure that component parameters get values (say, int or float) of the correct type.\n\n!Boolean literals\n\n&quot;true&quot; and &quot;false&quot; should also be converted to in
 variant bindings.\n{{{\nprop:true\n\nprop:false\n}}}\n\n!String literals\n\n//Simple// string literals, enclosed in single quotes.  Example:\n{{{\nprop:'Hello World'\n}}}\n\n//Remember that the binding expression will always be enclosed in double quotes.//\n\n!This literal\n\nIn some cases, it is useful to be able to identify the current component:\n{{{\nprop:this\n}}}\n\nEven though a component is not immutable, the value of //this// does not ever change,\nand this binding is also invariant.\n\n!Null literal\n\n{{{\nprop:null\n}}}\n\nThis value is always exactly null. This can be used to set a parameter who'se default value is non-null to the explicit value null.\n\n!Property paths\n\nMulti-step property paths are extremely important.\n\n{{{\nprop:poll.title\n\nprop:identity.user.name\n}}}\n\nThe initial terms need to be readable, they are never updated. Only the final property name must be read/write, and in fact, it is valid to be read-only or write-only.\n\nThe prop: bin
 ding factory builds a Java expression to read and update properties. It does not use reflection at runtime. Therefore, the properties of the //declared// type are used. By contrast, [[OGNL]] uses the //actual// type, which is reflection-intensive.\n\n''Currently, only simple properties, not property paths, are implemented.''\n</div>
+<div tiddler="PropBinding" modifier="YourName" modified="200610012127" created="200609202203" tags="bindings">&quot;prop:&quot; the default in a  lot of cases, i.e., in any Java code.\n\nThis binding prefix  supports several common idioms even though they are not, precisely, the names of properties.  In many cases, this will save developers the bother of using a &quot;literal:&quot; prefix.\n\nThe goal of the &quot;prop:&quot; prefix is to be highly efficient and useful in 90%+ of the cases. [[OGNL]], or synthetic properties in the component class, will pick up the remaining cases.\n\n!Numeric literals\n\nSimple numeric literals should be parsed into read-only, invariant bindings.\n{{{\nprop:5\n\nprop:-22.7\n}}}\n\n\nThe resulting objects will be of type Long or type Double. TypeCoercion will ensure that component parameters get values (say, int or float) of the correct type.\n\n!Boolean literals\n\n&quot;true&quot; and &quot;false&quot; should also be converted to invariant
  bindings.\n{{{\nprop:true\n\nprop:false\n}}}\n\n!String literals\n\n//Simple// string literals, enclosed in single quotes.  Example:\n{{{\nprop:'Hello World'\n}}}\n\n//Remember that the binding expression will always be enclosed in double quotes.//\n\n!This literal\n\nIn some cases, it is useful to be able to identify the current component:\n{{{\nprop:this\n}}}\n\nEven though a component is not immutable, the value of //this// does not ever change,\nand this binding is also invariant.\n\n!Null literal\n\n{{{\nprop:null\n}}}\n\nThis value is always exactly null. This can be used to set a parameter who'se default value is non-null to the explicit value null.\n\n!Property paths\n\nMulti-step property paths are extremely important.\n\n{{{\nprop:poll.title\n\nprop:identity.user.name\n}}}\n\nThe initial terms need to be readable, they are never updated. Only the final property name must be read/write, and in fact, it is valid to be read-only or write-only.\n\nThe prop: binding fa
 ctory builds a Java expression to read and update properties. It does not use reflection at runtime. Therefore, the properties of the //declared// type are used. By contrast, [[OGNL]] uses the //actual// type, which is reflection-intensive. Also, unlike OGNL, errors (such as missing properties in the property path) are identified when the page is loaded, rather than when the expression is evaluated.\n'\n</div>
 <div tiddler="SideBarTabs" modifier="HowardLewisShip" modified="200609210652" created="200609210651" tags="">&lt;&lt;tabs txtMainTab Timeline Timeline TabTimeline All 'All tiddlers' TabAll Tags 'All tags' TabTags More 'More lists' TabMore&gt;&gt;\n</div>
 <div tiddler="SiteSubtitle" modifier="HowardLewisShip" modified="200609202249" created="200609202155" tags="">\nThe quick and dirty one-stop shopping of random ideas for Tapestry 5.</div>
 <div tiddler="SiteTitle" modifier="HowardLewisShip" modified="200609202249" created="200609202155" tags="">Tapestry 5 Brain Dump</div>

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/app1/index.html
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/app1/index.html?view=diff&rev=451817&r1=451816&r2=451817
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/app1/index.html (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/app1/index.html Sun Oct  1 14:44:07 2006
@@ -11,7 +11,7 @@
                     <a href="Start.html">Start Page</a>
                 </li>
                 <li>
-                    <a href="MerryChristmas.html">Loop Page</a>
+                    <a href="MerryChristmas.html">Count Page</a>
                 </li>
                 <li>
                     <a href="InjectPage.html">Inject Page</a>
@@ -27,6 +27,9 @@
                 </li>
                 <li>
                     <a href="Expansion.html">Expansion Page</a>
+                </li>
+                <li>
+                <a href="MissingPage.html">Missing Page</a> -- Used to test exception reporting
                 </li>
             </ul>
         </p>

Added: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/corelib/components/LoopTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/corelib/components/LoopTest.java?view=auto&rev=451817
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/corelib/components/LoopTest.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/corelib/components/LoopTest.java Sun Oct  1 14:44:07 2006
@@ -0,0 +1,61 @@
+package org.apache.tapestry.corelib.components;
+
+import java.util.Arrays;
+import java.util.Collections;
+
+import junit.framework.Assert;
+
+import org.testng.annotations.Test;
+
+/**
+ * @author Howard M. Lewis Ship
+ */
+public class LoopTest extends Assert
+{
+    @Test
+    public void non_empty_iterator()
+    {
+        Loop loop = new Loop();
+
+        loop.setSource(Arrays.asList("alpha", "beta", "gamma"));
+
+        assertTrue(loop.setup());
+        assertEquals(loop.getIndex(), 0);
+
+        loop.begin();
+        assertEquals(loop.getValue(), "alpha");
+        assertEquals(loop.getIndex(), 0);
+
+        assertTrue(loop.after());
+        loop.begin();
+        assertEquals(loop.getValue(), "beta");
+        assertEquals(loop.getIndex(), 1);
+
+        assertTrue(loop.after());
+        loop.begin();
+        assertEquals(loop.getValue(), "gamma");
+        assertEquals(loop.getIndex(), 2);
+
+        assertFalse(loop.after());
+    }
+
+    @Test
+    public void iterator_is_null()
+    {
+        Loop loop = new Loop();
+
+        loop.setSource(null);
+
+        assertFalse(loop.setup());
+    }
+
+    @Test
+    public void iterator_is_empty()
+    {
+        Loop loop = new Loop();
+
+        loop.setSource(Collections.EMPTY_LIST);
+
+        assertFalse(loop.setup());
+    }
+}

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=451817&r1=451816&r2=451817
==============================================================================
--- 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 Sun Oct  1 14:44:07 2006
@@ -111,7 +111,7 @@
 
         _selenium.open(BASE_URL);
 
-        clickAndWait("link=Loop Page");
+        clickAndWait("link=Count Page");
 
         String body = _selenium.getBodyText();
 
@@ -157,7 +157,7 @@
         assertTrue(body.contains("5 4 3 2 1"));
 
         assertTrue(body
-                .contains("Brought to you by the org.apache.tapestry.integration.app1.components.Loop"));
+                .contains("Brought to you by the org.apache.tapestry.integration.app1.components.Count"));
     }
 
     @Test

Copied: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/components/Count.java (from r450680, tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/components/Loop.java)
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/components/Count.java?view=diff&rev=451817&p1=tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/components/Loop.java&r1=450680&p2=tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/components/Count.java&r2=451817
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/components/Loop.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/components/Count.java Sun Oct  1 14:44:07 2006
@@ -19,8 +19,13 @@
 import org.apache.tapestry.annotations.Parameter;
 import org.apache.tapestry.annotations.SetupRender;
 
+/**
+ * A component that can count up or count down.
+ * 
+ * @author Howard M. Lewis Ship
+ */ 
 @ComponentClass
-public class Loop
+public class Count
 {
     @Parameter
     private int _start = 1;

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/pages/Countdown.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/pages/Countdown.java?view=diff&rev=451817&r1=451816&r2=451817
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/pages/Countdown.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/pages/Countdown.java Sun Oct  1 14:44:07 2006
@@ -16,7 +16,7 @@
 
 import org.apache.tapestry.annotations.Component;
 import org.apache.tapestry.annotations.ComponentClass;
-import org.apache.tapestry.integration.app1.components.Loop;
+import org.apache.tapestry.integration.app1.components.Count;
 
 /**
  * @author Howard M. Lewis Ship
@@ -25,25 +25,25 @@
 public class Countdown
 {
     @Component(parameters =
-    { "start=5", "end=1", "value=count" })
-    private Loop _loop;
+    { "start=5", "end=1", "value=countValue" })
+    private Count _count;
 
-    private int _count;
+    private int _countValue;
 
-    public int getCount()
+    public int getCountValue()
     {
-        return _count;
+        return _countValue;
     }
 
-    public void setCount(int count)
+    public void setCountValue(int countValue)
     {
-        _count = count;
+        _countValue = countValue;
     }
 
     // Just needed until component: binding prefix is added.
 
-    public Loop getLoop()
+    public Count getComponent()
     {
-        return _loop;
+        return _count;
     }
 }

Added: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/services/AppModule.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/services/AppModule.java?view=auto&rev=451817
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/services/AppModule.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/services/AppModule.java Sun Oct  1 14:44:07 2006
@@ -0,0 +1,54 @@
+package org.apache.tapestry.integration.app1.services;
+
+import java.io.IOException;
+
+import org.apache.commons.logging.Log;
+import org.apache.tapestry.ioc.OrderedConfiguration;
+import org.apache.tapestry.ioc.annotations.Contribute;
+import org.apache.tapestry.ioc.annotations.Id;
+import org.apache.tapestry.ioc.annotations.InjectService;
+import org.apache.tapestry.services.WebRequest;
+import org.apache.tapestry.services.WebRequestFilter;
+import org.apache.tapestry.services.WebRequestHandler;
+import org.apache.tapestry.services.WebResponse;
+
+/**
+ * I was just dying to see how fast requests are!
+ * 
+ * @author Howard M. Lewis Ship
+ */
+@Id("app")
+public class AppModule
+{
+    public WebRequestFilter buildTimingFilter(final Log log)
+    {
+        return new WebRequestFilter()
+        {
+            public boolean service(WebRequest request, WebResponse response,
+                    WebRequestHandler handler) throws IOException
+            {
+                long startTime = System.currentTimeMillis();
+
+                try
+                {
+                    return handler.service(request, response);
+                }
+                finally
+                {
+                    long elapsed = System.currentTimeMillis() - startTime;
+
+                    log.info(String.format("Request time: %d ms", elapsed));
+                }
+            }
+        };
+    }
+
+    @Contribute("tapestry.WebRequestHandler")
+    public void contributeWebRequestFilters(OrderedConfiguration<WebRequestFilter> configuration,
+            @InjectService("TimingFilter")
+            WebRequestFilter filter)
+    {
+        configuration.add("Timing", filter);
+    }
+
+}

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/bindings/PropBindingFactoryTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/bindings/PropBindingFactoryTest.java?view=diff&rev=451817&r1=451816&r2=451817
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/bindings/PropBindingFactoryTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/bindings/PropBindingFactoryTest.java Sun Oct  1 14:44:07 2006
@@ -17,12 +17,13 @@
 import org.apache.tapestry.Binding;
 import org.apache.tapestry.ComponentResources;
 import org.apache.tapestry.Location;
-import org.apache.tapestry.events.InvalidationEvent;
+import org.apache.tapestry.internal.TapestryException;
 import org.apache.tapestry.internal.annotations.SuppressNullCheck;
 import org.apache.tapestry.internal.ioc.IOCUtilities;
-import org.apache.tapestry.internal.ioc.services.ClassFactoryImpl;
-import org.apache.tapestry.internal.ioc.services.PropertyAccessImpl;
 import org.apache.tapestry.internal.test.InternalBaseTestCase;
+import org.apache.tapestry.ioc.StringHolder;
+import org.apache.tapestry.ioc.services.ClassFactory;
+import org.apache.tapestry.ioc.services.PropertyAccess;
 import org.apache.tapestry.runtime.ComponentLifecycle;
 import org.apache.tapestry.services.BindingFactory;
 import org.testng.annotations.AfterClass;
@@ -35,9 +36,20 @@
  */
 public class PropBindingFactoryTest extends InternalBaseTestCase
 {
-    private PropBindingFactory newPropBindingFactory()
+    private static final String BEAN_CLASS = TargetBean.class.getName();
+
+    private BindingFactory _factory;
+
+    @BeforeClass
+    public void setup_factory()
     {
-        return new PropBindingFactory(new PropertyAccessImpl(), new ClassFactoryImpl());
+        _factory = getService("tapestry.internal.PropBindingFactory", BindingFactory.class);
+    }
+
+    @AfterClass
+    public void cleanup_factory()
+    {
+        _factory = null;
     }
 
     private ComponentResources newComponentResources(ComponentLifecycle component)
@@ -65,14 +77,13 @@
     @Test
     public void object_property()
     {
-        PropBindingFactory factory = newPropBindingFactory();
         TargetBean bean = new TargetBean();
         ComponentResources resources = newComponentResources(bean);
         Location l = newLocation();
 
         replay();
 
-        Binding binding = factory.newBinding("test binding", resources, "objectValue", l);
+        Binding binding = _factory.newBinding("test binding", resources, "objectValue", l);
 
         assertSame(binding.getBindingType(), String.class);
 
@@ -91,16 +102,105 @@
     }
 
     @Test
+    public void property_path()
+    {
+        TargetBean bean = new TargetBean();
+        ComponentResources resources = newComponentResources(bean);
+        Location l = newLocation();
+
+        replay();
+
+        Binding binding = _factory.newBinding("test binding", resources, "stringHolder.value", l);
+
+        assertSame(binding.getBindingType(), String.class);
+
+        bean.getStringHolder().setValue("first");
+
+        assertEquals(binding.get(), "first");
+
+        binding.set("second");
+
+        assertEquals(bean.getStringHolder().getValue(), "second");
+
+        assertEquals(
+                binding.toString(),
+                "PropBinding[test binding foo.Bar:baz(stringHolder.value)]");
+
+        verify();
+
+    }
+
+    @Test
+    public void property_path_through_missing_property()
+    {
+        TargetBean bean = new TargetBean();
+        ComponentResources resources = newComponentResources();
+        Location l = newLocation();
+
+        train_getComponent(resources, bean);
+
+        replay();
+
+        String propertyPath = "stringHolder.missingProperty.terminalProperty";
+
+        try
+        {
+            _factory.newBinding("test binding", resources, propertyPath, l);
+            unreachable();
+        }
+        catch (TapestryException ex)
+        {
+            assertEquals(ex.getMessage(), BindingsMessages.noSuchProperty(
+                    StringHolder.class,
+                    "missingProperty",
+                    propertyPath));
+            assertSame(ex.getLocation(), l);
+        }
+
+        verify();
+    }
+
+    @Test
+    public void property_path_through_write_only_property()
+    {
+        TargetBean bean = new TargetBean();
+        ComponentResources resources = newComponentResources();
+        Location l = newLocation();
+
+        train_getComponent(resources, bean);
+
+        replay();
+
+        String propertyPath = "writeOnly.terminalProperty";
+
+        try
+        {
+            _factory.newBinding("test binding", resources, propertyPath, l);
+            unreachable();
+        }
+        catch (TapestryException ex)
+        {
+            assertEquals(ex.getMessage(), BindingsMessages.writeOnlyProperty(
+                    "writeOnly",
+                    TargetBean.class,
+                    propertyPath));
+            assertSame(ex.getLocation(), l);
+        }
+
+        verify();
+
+    }
+
+    @Test
     public void primitive_property()
     {
-        PropBindingFactory factory = newPropBindingFactory();
         TargetBean bean = new TargetBean();
         ComponentResources resources = newComponentResources(bean);
         Location l = newLocation();
 
         replay();
 
-        Binding binding = factory.newBinding("test binding", resources, "intValue", l);
+        Binding binding = _factory.newBinding("test binding", resources, "intValue", l);
 
         assertSame(binding.getBindingType(), int.class);
 
@@ -118,14 +218,13 @@
     @Test
     public void read_only_property()
     {
-        PropBindingFactory factory = newPropBindingFactory();
         TargetBean bean = new TargetBean();
         ComponentResources resources = newComponentResources(bean);
         Location l = newLocation();
 
         replay();
 
-        Binding binding = factory.newBinding("test binding", resources, "readOnly", l);
+        Binding binding = _factory.newBinding("test binding", resources, "readOnly", l);
 
         assertEquals(binding.get(), "ReadOnly");
 
@@ -134,12 +233,12 @@
             binding.set("fail");
             unreachable();
         }
-        catch (RuntimeException ex)
+        catch (TapestryException ex)
         {
             assertEquals(
                     "Binding PropBinding[test binding foo.Bar:baz(readOnly)] is read-only.",
                     ex.getMessage());
-            assertEquals(IOCUtilities.locationOf(ex), l);
+            assertEquals(ex.getLocation(), l);
         }
 
         verify();
@@ -148,14 +247,13 @@
     @Test
     public void write_only_property()
     {
-        PropBindingFactory factory = newPropBindingFactory();
         TargetBean bean = new TargetBean();
         ComponentResources resources = newComponentResources(bean);
         Location l = newLocation();
 
         replay();
 
-        Binding binding = factory.newBinding("test binding", resources, "writeOnly", l);
+        Binding binding = _factory.newBinding("test binding", resources, "writeOnly", l);
 
         binding.set("updated");
 
@@ -166,12 +264,12 @@
             assertEquals(binding.get(), "ReadOnly");
             unreachable();
         }
-        catch (RuntimeException ex)
+        catch (TapestryException ex)
         {
             assertEquals(
                     "Binding PropBinding[test binding foo.Bar:baz(writeOnly)] is write-only.",
                     ex.getMessage());
-            assertEquals(IOCUtilities.locationOf(ex), l);
+            assertEquals(ex.getLocation(), l);
         }
 
         verify();
@@ -180,7 +278,11 @@
     @Test
     public void caching()
     {
-        PropBindingFactory factory = newPropBindingFactory();
+        PropertyAccess access = getService("tapestry.ioc.PropertyAccess", PropertyAccess.class);
+        ClassFactory classFactory = getService("tapestry.ioc.ClassFactory", ClassFactory.class);
+
+        PropBindingFactory factory = new PropBindingFactory(access, classFactory);
+
         TargetBean bean1 = new TargetBean();
         ComponentResources resources1 = newComponentResources(bean1);
         TargetBean bean2 = new TargetBean();
@@ -205,7 +307,7 @@
 
         // Now, clear the cache.
 
-        factory.objectWasInvalidated(new InvalidationEvent(this));
+        factory.objectWasInvalidated();
 
         Binding binding3 = factory.newBinding("test binding 3", resources3, "objectValue", l);
 
@@ -219,7 +321,6 @@
     @Test
     public void unknown_property()
     {
-        PropBindingFactory factory = newPropBindingFactory();
         TargetBean bean = new TargetBean();
         ComponentResources resources = newComponentResources();
         Location l = newLocation();
@@ -230,34 +331,21 @@
 
         try
         {
-            factory.newBinding("test binding", resources, "missingProperty", l);
+            _factory.newBinding("test binding", resources, "missingProperty", l);
             unreachable();
         }
-        catch (RuntimeException ex)
+        catch (TapestryException ex)
         {
-            assertEquals(ex.getMessage(), String.format(
-                    "Class %s does not contain a property named 'missingProperty'.",
-                    bean.getClass().getName()));
-            assertSame(IOCUtilities.locationOf(ex), l);
+            assertEquals(ex.getMessage(), BindingsMessages.noSuchProperty(
+                    TargetBean.class,
+                    "missingProperty",
+                    "missingProperty"));
+            assertSame(ex.getLocation(), l);
         }
 
         verify();
     }
 
-    private BindingFactory _propFactory;
-
-    @BeforeClass
-    public void setup_factory()
-    {
-        _propFactory = getService("tapestry.internal.PropBindingFactory", BindingFactory.class);
-    }
-
-    @AfterClass
-    public void cleanup_factory()
-    {
-        _propFactory = null;
-    }
-
     @Test
     public void special_prop_binding_value_null()
     {
@@ -270,7 +358,7 @@
 
         replay();
 
-        Binding binding = _propFactory.newBinding(description, resources, "this", l);
+        Binding binding = _factory.newBinding(description, resources, "this", l);
 
         assertSame(binding.get(), component);
 
@@ -287,7 +375,7 @@
 
         replay();
 
-        Binding binding = _propFactory.newBinding(description, resources, expression, l);
+        Binding binding = _factory.newBinding(description, resources, expression, l);
 
         assertEquals(binding.get(), expected);
 

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/bindings/TargetBean.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/bindings/TargetBean.java?view=diff&rev=451817&r1=451816&r2=451817
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/bindings/TargetBean.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/bindings/TargetBean.java Sun Oct  1 14:44:07 2006
@@ -14,6 +14,9 @@
 
 package org.apache.tapestry.internal.bindings;
 
+import org.apache.tapestry.ioc.StringHolder;
+import org.apache.tapestry.ioc.StringHolderImpl;
+
 public class TargetBean extends DefaultComponentLifecyle
 {
     private String _objectValue;
@@ -21,6 +24,13 @@
     private int _intValue;
 
     String _writeOnly;
+
+    private StringHolder _stringHolder = new StringHolderImpl();
+
+    public StringHolder getStringHolder()
+    {
+        return _stringHolder;
+    }
 
     public int getIntValue()
     {

Added: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/ExceptionAnalyzerImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/ExceptionAnalyzerImplTest.java?view=auto&rev=451817
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/ExceptionAnalyzerImplTest.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/ExceptionAnalyzerImplTest.java Sun Oct  1 14:44:07 2006
@@ -0,0 +1,97 @@
+package org.apache.tapestry.internal.ioc.services;
+
+import java.util.Arrays;
+
+import org.apache.tapestry.Location;
+import org.apache.tapestry.internal.TapestryException;
+import org.apache.tapestry.internal.test.InternalBaseTestCase;
+import org.apache.tapestry.ioc.services.ExceptionAnalysis;
+import org.apache.tapestry.ioc.services.ExceptionAnalyzer;
+import org.apache.tapestry.ioc.services.ExceptionInfo;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+/**
+ * @author Howard M. Lewis Ship
+ */
+public class ExceptionAnalyzerImplTest extends InternalBaseTestCase
+{
+    private ExceptionAnalyzer _analyzer;
+
+    @BeforeClass
+    public void setup_analyzer()
+    {
+        _analyzer = getService("tapestry.ioc.ExceptionAnalyzer", ExceptionAnalyzer.class);
+    }
+
+    @AfterClass
+    public void cleanup_analyzer()
+    {
+        _analyzer = null;
+    }
+
+    @Test
+    public void basic_exception()
+    {
+        String message = "Hey! We've Got Not Tomatoes!";
+
+        Throwable t = new RuntimeException(message);
+
+        ExceptionAnalysis ea = _analyzer.analyze(t);
+
+        assertEquals(ea.getExceptionInfos().size(), 1);
+
+        ExceptionInfo ei = ea.getExceptionInfos().get(0);
+
+        assertEquals(ei.getClassName(), RuntimeException.class.getName());
+        assertEquals(ei.getMessage(), message);
+
+        assertTrue(ei.getPropertyNames().isEmpty());
+        assertFalse(ei.getStackTrace().isEmpty());
+    }
+
+    @Test
+    public void exception_properties()
+    {
+        Location l = newLocation();
+
+        replay();
+
+        Throwable t = new TapestryException("Message", l, null);
+
+        ExceptionAnalysis ea = _analyzer.analyze(t);
+
+        assertEquals(ea.getExceptionInfos().size(), 1);
+
+        ExceptionInfo ei = ea.getExceptionInfos().get(0);
+
+        assertEquals(ei.getPropertyNames(), Arrays.asList("location"));
+
+        assertEquals(ei.getProperty("location"), l);
+
+        verify();
+    }
+
+    @Test
+    public void nested_exceptions()
+    {
+        Throwable inner = new RuntimeException("Inner");
+        Throwable outer = new RuntimeException("Outer", inner);
+
+        ExceptionAnalysis ea = _analyzer.analyze(outer);
+
+        assertEquals(ea.getExceptionInfos().size(), 2);
+
+        ExceptionInfo ei = ea.getExceptionInfos().get(0);
+
+        assertEquals(ei.getMessage(), "Outer");
+        assertTrue(ei.getStackTrace().isEmpty());
+
+        ei = ea.getExceptionInfos().get(1);
+
+        assertEquals(ei.getMessage(), "Inner");
+        assertFalse(ei.getStackTrace().isEmpty());
+    }
+
+}

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/PropertyAccessImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/PropertyAccessImplTest.java?view=diff&rev=451817&r1=451816&r2=451817
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/PropertyAccessImplTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/PropertyAccessImplTest.java Sun Oct  1 14:44:07 2006
@@ -20,6 +20,7 @@
 import java.beans.EventSetDescriptor;
 import java.beans.MethodDescriptor;
 import java.beans.PropertyDescriptor;
+import java.util.Arrays;
 import java.util.Random;
 
 import org.apache.tapestry.internal.test.InternalBaseTestCase;
@@ -353,6 +354,14 @@
     }
 
     @Test
+    public void property_names()
+    {
+        ClassPropertyAdapter cpa = _access.getAdapter(Bean.class);
+
+        assertEquals(cpa.getPropertyNames(), Arrays.asList("class", "readOnly", "value", "writeOnly"));
+    }
+
+    @Test
     public void integration()
     {
         Registry registry = buildRegistry();
@@ -368,4 +377,5 @@
 
         assertEquals(b.getValue(), value);
     }
+
 }

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/model/MutableComponentModelImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/model/MutableComponentModelImplTest.java?view=diff&rev=451817&r1=451816&r2=451817
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/model/MutableComponentModelImplTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/model/MutableComponentModelImplTest.java Sun Oct  1 14:44:07 2006
@@ -32,6 +32,8 @@
  */
 public class MutableComponentModelImplTest extends InternalBaseTestCase
 {
+    private static final String COMPONENT_CLASS_NAME = "org.example.components.Fred";
+
     private static final String CLASS_NAME = "org.example.components.Foo";
 
     @Test
@@ -128,19 +130,28 @@
 
         assertTrue(model.getEmbeddedComponentIds().isEmpty());
 
-        MutableEmbeddedComponentModel fred = model.addEmbeddedComponent("fred", "Fred");
+        MutableEmbeddedComponentModel fred = model.addEmbeddedComponent(
+                "fred",
+                "Fred",
+                COMPONENT_CLASS_NAME);
 
         assertEquals(fred.getId(), "fred");
         assertEquals(fred.getComponentType(), "Fred");
 
-        MutableEmbeddedComponentModel barney = model.addEmbeddedComponent("barney", "Barney");
+        MutableEmbeddedComponentModel barney = model.addEmbeddedComponent(
+                "barney",
+                "Barney",
+                COMPONENT_CLASS_NAME);
 
         assertEquals(model.getEmbeddedComponentIds(), Arrays.asList("barney", "fred"));
 
         assertSame(model.getEmbeddedComponentModel("fred"), fred);
         assertSame(model.getEmbeddedComponentModel("barney"), barney);
 
-        assertEquals(fred.toString(), "EmbeddedComponentModel[id=fred type=Fred]");
+        assertEquals(
+                fred.toString(),
+                "EmbeddedComponentModel[id=fred type=Fred class=org.example.components.Fred]");
+        
         verify();
     }
 
@@ -154,11 +165,11 @@
 
         MutableComponentModel model = new MutableComponentModelImpl(CLASS_NAME, log, r);
 
-        model.addEmbeddedComponent("fred", "Fred1");
+        model.addEmbeddedComponent("fred", "Fred1", COMPONENT_CLASS_NAME);
 
         try
         {
-            model.addEmbeddedComponent("fred", "Fred2");
+            model.addEmbeddedComponent("fred", "Fred2", COMPONENT_CLASS_NAME);
             unreachable();
         }
         catch (IllegalArgumentException ex)
@@ -182,7 +193,10 @@
 
         MutableComponentModel model = new MutableComponentModelImpl(CLASS_NAME, log, r);
 
-        MutableEmbeddedComponentModel fred = model.addEmbeddedComponent("fred", "Fred");
+        MutableEmbeddedComponentModel fred = model.addEmbeddedComponent(
+                "fred",
+                "Fred",
+                COMPONENT_CLASS_NAME);
 
         assertTrue(fred.getParameterNames().isEmpty());
 
@@ -206,7 +220,10 @@
 
         MutableComponentModel model = new MutableComponentModelImpl(CLASS_NAME, log, r);
 
-        MutableEmbeddedComponentModel fred = model.addEmbeddedComponent("fred", "Fred");
+        MutableEmbeddedComponentModel fred = model.addEmbeddedComponent(
+                "fred",
+                "Fred",
+                COMPONENT_CLASS_NAME);
 
         fred.addParameter("city", "bedrock");