You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tapestry.apache.org by fr...@apache.org on 2006/12/21 10:24:01 UTC

svn commit: r489299 - in /tapestry/tapestry5/tapestry-core/trunk/src: main/java/org/apache/tapestry/ main/java/org/apache/tapestry/corelib/components/ main/java/org/apache/tapestry/internal/services/ main/java/org/apache/tapestry/internal/structure/ te...

Author: freemant
Date: Thu Dec 21 01:24:00 2006
New Revision: 489299

URL: http://svn.apache.org/viewvc?view=rev&rev=489299
Log:
Instead of letting Form and ActionLink to worry about the invocation map, let the LinkFactory do it.

Modified:
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ComponentResourcesCommon.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/ActionLink.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/Form.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ActionLinkHandlerImpl.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/LinkFactory.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/LinkFactoryImpl.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/ComponentPageElementImpl.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/InternalComponentResourcesImpl.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/Page.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/PageImpl.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/LinkFactoryImplTest.java

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ComponentResourcesCommon.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ComponentResourcesCommon.java?view=diff&rev=489299&r1=489298&r2=489299
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ComponentResourcesCommon.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ComponentResourcesCommon.java Thu Dec 21 01:24:00 2006
@@ -17,6 +17,7 @@
 import java.util.Locale;
 
 import org.apache.commons.logging.Log;
+import org.apache.tapestry.dom.Element;
 import org.apache.tapestry.internal.structure.ComponentPageElement;
 import org.apache.tapestry.model.ComponentModel;
 import org.apache.tapestry.services.ComponentSource;
@@ -42,6 +43,9 @@
     /**
      * Creates a link that will trigger an action for this component.
      * 
+     * @param linkElement
+     *            The element where the link is used (usually an <a&gt or an <form&gt). Pass
+     *            null if the link is not to be used in an element.
      * @param action
      *            a name for the action associated with the link
      * @param forForm
@@ -51,7 +55,7 @@
      *            additional objects to be encoded into the path portion of the link; each is
      *            converted to a string an URI encoded
      */
-    Link createActionLink(String action, boolean forForm, Object... context);
+    Link createActionLink(Element linkElement, String action, boolean forForm, Object... context);
 
     /**
      * Returns a string consisting of the fully qualified class name of the containing page, and the

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/ActionLink.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/ActionLink.java?view=diff&rev=489299&r1=489298&r2=489299
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/ActionLink.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/ActionLink.java Thu Dec 21 01:24:00 2006
@@ -30,8 +30,6 @@
 import org.apache.tapestry.annotations.Parameter;
 import org.apache.tapestry.corelib.mixins.RenderInformals;
 import org.apache.tapestry.dom.Element;
-import org.apache.tapestry.internal.services.InAppInvocationMap;
-import org.apache.tapestry.internal.services.LinkImpl;
 import org.apache.tapestry.services.PageRenderSupport;
 
 /**
@@ -58,9 +56,6 @@
     @Environmental
     private PageRenderSupport _support;
 
-    @Inject("service:tapestry.internal.InAppInvocationMap")
-    private InAppInvocationMap _invocationMap;
-
     @BeginRender
     void begin(MarkupWriter writer)
     {
@@ -68,12 +63,11 @@
 
         Object[] contextArray = _context == null ? new Object[0] : _context.toArray();
 
-        Link link = _resources.createActionLink(DEFAULT_EVENT, false, contextArray);
+        Element element = writer.element("a");
 
-        Element element = writer.element("a", "href", link.toURI(), "id", clientId);
+        Link link = _resources.createActionLink(element, DEFAULT_EVENT, false, contextArray);
 
-        // Allow the PageTester to extract the invocation object to invoke it later.
-        _invocationMap.put(element, ((LinkImpl) link).getInvocation());
+        element.attributes("href", link.toURI(), "id", clientId);
 
         // TODO: Support for informal parameters, etc.
     }

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/Form.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/Form.java?view=diff&rev=489299&r1=489298&r2=489299
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/Form.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/Form.java Thu Dec 21 01:24:00 2006
@@ -37,8 +37,6 @@
 import org.apache.tapestry.corelib.mixins.RenderInformals;
 import org.apache.tapestry.dom.Element;
 import org.apache.tapestry.internal.services.FormParameterLookup;
-import org.apache.tapestry.internal.services.InAppInvocationMap;
-import org.apache.tapestry.internal.services.LinkImpl;
 import org.apache.tapestry.internal.util.Base64ObjectInputStream;
 import org.apache.tapestry.internal.util.Base64ObjectOutputStream;
 import org.apache.tapestry.runtime.Component;
@@ -103,9 +101,6 @@
     @Inject("infrastructure:ComponentSource")
     private ComponentSource _source;
 
-    @Inject("service:tapestry.internal.InAppInvocationMap")
-    private InAppInvocationMap _invocationMap;
-
     // Collects a stream of component actions. Each action goes in as a UTF string (the component
     // component id),
     // followed by a ComponentAction
@@ -152,22 +147,14 @@
 
         String name = _pageRenderSupport.allocateClientId(_resources.getId());
 
-        Link link = _resources
-                .createActionLink(TapestryConstants.DEFAULT_EVENT, true, contextArray);
-
-        Element element = writer.element(
-                "form",
-                "name",
-                name,
-                "id",
-                name,
-                "method",
-                "post",
-                "action",
-                link.toFormURI());
+        Element element = writer.element("form");
 
-        // Allow the PageTester to extract the invocation object to invoke it later.
-        _invocationMap.put(element, ((LinkImpl) link).getInvocation());
+        Link link = _resources.createActionLink(
+                element,
+                TapestryConstants.DEFAULT_EVENT,
+                true,
+                contextArray);
+        element.attributes("name", name, "id", name, "method", "post", "action", link.toFormURI());
 
         // TODO: Informal parameters
 

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ActionLinkHandlerImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ActionLinkHandlerImpl.java?view=diff&rev=489299&r1=489298&r2=489299
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ActionLinkHandlerImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ActionLinkHandlerImpl.java Thu Dec 21 01:24:00 2006
@@ -60,7 +60,7 @@
 
         page = _cache.getActive();
 
-        return _linkFactory.createPageLink(page);
+        return _linkFactory.createPageLink(null, page);
     }
 
 }

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=489299&r1=489298&r2=489299
==============================================================================
--- 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 Thu Dec 21 01:24:00 2006
@@ -57,15 +57,15 @@
 import org.apache.tapestry.services.ComponentClassResolver;
 import org.apache.tapestry.services.ComponentClassTransformWorker;
 import org.apache.tapestry.services.ComponentMessagesSource;
+import org.apache.tapestry.services.Context;
 import org.apache.tapestry.services.MarkupWriterFactory;
 import org.apache.tapestry.services.PageRenderInitializer;
 import org.apache.tapestry.services.PersistentFieldManager;
+import org.apache.tapestry.services.Request;
 import org.apache.tapestry.services.RequestExceptionHandler;
+import org.apache.tapestry.services.RequestFilter;
 import org.apache.tapestry.services.RequestGlobals;
 import org.apache.tapestry.services.ResourceDigestGenerator;
-import org.apache.tapestry.services.Context;
-import org.apache.tapestry.services.Request;
-import org.apache.tapestry.services.RequestFilter;
 import org.apache.tapestry.services.Response;
 
 @Id("tapestry.internal")
@@ -510,9 +510,11 @@
     /** Service used to create links for components and pages. */
     public LinkFactory buildLinkFactory(@InjectService("ContextPathSource")
     ContextPathSource contextPathSource, @InjectService("URLEncoder")
-    URLEncoder encoder)
+    URLEncoder encoder, @InjectService("InAppInvocationMap")
+    InAppInvocationMap inAppInvocationMap)
     {
-        return new LinkFactoryImpl(contextPathSource, encoder, _componentClassResolver);
+        return new LinkFactoryImpl(contextPathSource, encoder, _componentClassResolver,
+                inAppInvocationMap);
     }
 
     public ContextPathSource buildContextPathSource()

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/LinkFactory.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/LinkFactory.java?view=diff&rev=489299&r1=489298&r2=489299
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/LinkFactory.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/LinkFactory.java Thu Dec 21 01:24:00 2006
@@ -15,6 +15,7 @@
 package org.apache.tapestry.internal.services;
 
 import org.apache.tapestry.Link;
+import org.apache.tapestry.dom.Element;
 import org.apache.tapestry.internal.structure.ComponentPageElement;
 import org.apache.tapestry.internal.structure.Page;
 
@@ -29,6 +30,9 @@
      * Creates a stateful action link. Action links are built for components. Action links are
      * encoded by the current request (that is, bound to the current request's session, if any).
      * 
+     * @param linkElement
+     *            The element for the link (most usually a <a> or <form>). Pass null if
+     *            the link is not to be used as an element.
      * @param component
      *            the component for which an action link is to be generated
      * @param action
@@ -40,16 +44,19 @@
      *            URI
      * @return a link
      */
-    Link createActionLink(ComponentPageElement component, String action, boolean forForm,
-            Object... context);
+    Link createActionLink(Element linkElement, ComponentPageElement component, String action,
+            boolean forForm, Object... context);
 
     /**
      * Creates a link to a page. TODO: What about context? Additional query parameters?
      * 
+     * @param linkElement
+     *            The element for the link (most usually a <a>). Pass null if the link is not
+     *            to be used as an element.
      * @param page
      * @return
      */
-    Link createPageLink(Page page);
+    Link createPageLink(Element linkElement, Page page);
 
     void addListener(LinkFactoryListener listener);
 }

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/LinkFactoryImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/LinkFactoryImpl.java?view=diff&rev=489299&r1=489298&r2=489299
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/LinkFactoryImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/LinkFactoryImpl.java Thu Dec 21 01:24:00 2006
@@ -25,6 +25,7 @@
 import org.apache.tapestry.ComponentEventHandler;
 import org.apache.tapestry.Link;
 import org.apache.tapestry.TapestryConstants;
+import org.apache.tapestry.dom.Element;
 import org.apache.tapestry.internal.structure.ComponentPageElement;
 import org.apache.tapestry.internal.structure.Page;
 import org.apache.tapestry.ioc.internal.util.Defense;
@@ -44,17 +45,20 @@
 
     private final StrategyRegistry<PassivateContextHandler> _registry;
 
+    private final InAppInvocationMap _invocationMap;
+
     private interface PassivateContextHandler<T>
     {
         void handle(T result, List context);
     }
 
     public LinkFactoryImpl(ContextPathSource contextPathSource, URLEncoder encoder,
-            ComponentClassResolver componentClassResolver)
+            ComponentClassResolver componentClassResolver, InAppInvocationMap invocationMap)
     {
         _contextPathSource = contextPathSource;
         _encoder = encoder;
         _componentClassResolver = componentClassResolver;
+        _invocationMap = invocationMap;
 
         Map<Class, PassivateContextHandler> registrations = newMap();
 
@@ -95,8 +99,8 @@
         _listeners.add(listener);
     }
 
-    public Link createActionLink(ComponentPageElement component, String action, boolean forForm,
-            Object... context)
+    public Link createActionLink(Element linkElement, ComponentPageElement component,
+            String action, boolean forForm, Object... context)
     {
         Defense.notBlank(action, "action");
 
@@ -116,10 +120,19 @@
         // TODO: Much more: query parameter for case where active page != component page.
         // Letting listeners add extra parameters.
 
+        mapElementToInvocation(linkElement, invocation);
+
         return link;
     }
 
-    public Link createPageLink(final Page page)
+    private void mapElementToInvocation(Element linkElement, InAppInvocation invocation)
+    {
+        // Allow the PageTester to extract the invocation object to invoke it later.
+        if (linkElement != null)
+            _invocationMap.put(linkElement, invocation);
+    }
+
+    public Link createPageLink(Element linkElement, final Page page)
     {
         Defense.notNull(page, "page");
 
@@ -153,6 +166,8 @@
 
         // TODO: Much more: query parameter for case where active page != component page.
         // Letting listeners add extra parameters.
+
+        mapElementToInvocation(linkElement, invocation);
 
         return link;
     }

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/ComponentPageElementImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/ComponentPageElementImpl.java?view=diff&rev=489299&r1=489298&r2=489299
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/ComponentPageElementImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/ComponentPageElementImpl.java Thu Dec 21 01:24:00 2006
@@ -26,6 +26,7 @@
 import org.apache.tapestry.ComponentEventHandler;
 import org.apache.tapestry.Link;
 import org.apache.tapestry.MarkupWriter;
+import org.apache.tapestry.dom.Element;
 import org.apache.tapestry.internal.InternalComponentResources;
 import org.apache.tapestry.internal.services.ComponentEventImpl;
 import org.apache.tapestry.internal.services.Instantiator;
@@ -665,12 +666,13 @@
 
     /**
      * Delegates to the
-     * {@link Page#createActionLink(ComponentPageElement, String, boolean, Object[]) the containing page}.
+     * {@link Page#createActionLink(Element, ComponentPageElement, String, boolean, Object[]) the containing page}.
      * Why the extra layer? Because
      */
-    public Link createActionLink(String action, boolean forForm, Object... context)
+    public Link createActionLink(Element linkElement, String action, boolean forForm,
+            Object... context)
     {
-        return _page.createActionLink(this, action, forForm, context);
+        return _page.createActionLink(linkElement, this, action, forForm, context);
     }
 
     public void enqueueBeforeRenderBody(RenderQueue queue)

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/InternalComponentResourcesImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/InternalComponentResourcesImpl.java?view=diff&rev=489299&r1=489298&r2=489299
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/InternalComponentResourcesImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/InternalComponentResourcesImpl.java Thu Dec 21 01:24:00 2006
@@ -23,6 +23,7 @@
 import org.apache.tapestry.ComponentEventHandler;
 import org.apache.tapestry.Link;
 import org.apache.tapestry.MarkupWriter;
+import org.apache.tapestry.dom.Element;
 import org.apache.tapestry.internal.InternalComponentResources;
 import org.apache.tapestry.internal.services.Instantiator;
 import org.apache.tapestry.ioc.Messages;
@@ -97,9 +98,10 @@
         return _element.hasFieldChange(fieldName);
     }
 
-    public Link createActionLink(String action, boolean forForm, Object... context)
+    public Link createActionLink(Element linkElement, String action, boolean forForm,
+            Object... context)
     {
-        return _element.createActionLink(action, forForm, context);
+        return _element.createActionLink(linkElement, action, forForm, context);
     }
 
     public String getCompleteId()

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/Page.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/Page.java?view=diff&rev=489299&r1=489298&r2=489299
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/Page.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/Page.java Thu Dec 21 01:24:00 2006
@@ -12,147 +12,151 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package org.apache.tapestry.internal.structure;
-
+package org.apache.tapestry.internal.structure;
+
 import java.util.Locale;
 
 import org.apache.commons.logging.Log;
 import org.apache.tapestry.Link;
+import org.apache.tapestry.dom.Element;
 import org.apache.tapestry.runtime.Component;
 import org.apache.tapestry.runtime.PageLifecycleListener;
-
-/**
- * Represents a unique page within the application. Pages are part of the <em>internal</em>
- * structure of a Tapestry application; end developers who refer to "page" are really referring to
- * the {@link #getRootComponent() root component} of the actual page.
- * <p>
- * One of the most important aspects of a Page is that it <em>does not</em> have to be coded in a
- * thread-safe manner. Pages are always accessed within a single thread, associated with a single
- * incoming request.
- * <p>
- * The Page object is never visible to end-user code. The page also exists to provide a kind of
- * service to components embedded (directly or indirectly) within the page.
- */
-public interface Page
-{
-    /**
-     * Returns the name of the page, which is the fully qualifed class name of the page's
-     * <em>root component</em>. The name is unique within the application, though it is combined
-     * with the locale to select and pool page instances.
-     */
-    String getName();
-
-    /**
-     * The locale for which the page is localized. This is set when the page is created and does not
-     * change.
-     */
-    Locale getLocale();
-
-    /**
-     * Invoked during page construction time to connect the page's root component to the page
-     * instance.
-     */
-    void setRootElement(ComponentPageElement component);
-
-    /**
-     * The root component of the page. This is the wrapper around the end developer's view of the
-     * page.
-     */
+
+/**
+ * Represents a unique page within the application. Pages are part of the <em>internal</em>
+ * structure of a Tapestry application; end developers who refer to "page" are really referring to
+ * the {@link #getRootComponent() root component} of the actual page.
+ * <p>
+ * One of the most important aspects of a Page is that it <em>does not</em> have to be coded in a
+ * thread-safe manner. Pages are always accessed within a single thread, associated with a single
+ * incoming request.
+ * <p>
+ * The Page object is never visible to end-user code. The page also exists to provide a kind of
+ * service to components embedded (directly or indirectly) within the page.
+ */
+public interface Page
+{
+    /**
+     * Returns the name of the page, which is the fully qualifed class name of the page's
+     * <em>root component</em>. The name is unique within the application, though it is combined
+     * with the locale to select and pool page instances.
+     */
+    String getName();
+
+    /**
+     * The locale for which the page is localized. This is set when the page is created and does not
+     * change.
+     */
+    Locale getLocale();
+
+    /**
+     * Invoked during page construction time to connect the page's root component to the page
+     * instance.
+     */
+    void setRootElement(ComponentPageElement component);
+
+    /**
+     * The root component of the page. This is the wrapper around the end developer's view of the
+     * page.
+     */
     ComponentPageElement getRootElement();
-    
+
     /** The root component of the page. A convienience over ivoking getRootElement().getComponent(). */
-    
-    Component getRootComponent();
-
-    /**
-     * Invoked to inform the page that it is being detached from the current request. This occurs
-     * just before the page is returned to the page pool.
-     * <p>
-     * A page may be clean or dirty. A page is dirty if its dirty count is greater than zero
-     * (meaning that, during the render of the page, some components did not fully render), or if
-     * any of its listeners throw an exception from containingPageDidDetech().
-     * <p>
-     * The page pool should discard pages that are dirty, rather than store them into the pool.
-     * 
-     * @return true if the page is "clean", false otherwise
-     * @see org.apache.tapestry.runtime.PageLifecycleListener#containingPageDidDetach()
-     */
-    boolean detached();
-
-    /**
-     * Invoked to inform the page that it is attached to the current request. This occurs when a
-     * page is first referenced within a request. If the page was created from scratch for this
-     * request, the call to {@link #loaded()} will preceded the call to {@link #attached()}.
-     */
-
-    void attached();
-
-    /**
-     * Inform the page that it is now completely loaded.
-     * 
-     * @see org.apache.tapestry.runtime.PageLifecycleListener#containingPageDidLoad()
-     */
-
-    void loaded();
-
-    /**
-     * Adds a listener that is notified of large scale page events.
-     */
-    void addLifecycleListener(PageLifecycleListener listener);
-
-    /** Returns the log of the root component element. */
-    Log getLog();
-
-    /**
-     * Retrieves a component element by its nested id (a sequence of simple ids, separated by dots).
-     * 
-     * @throws IllegalArgumentException
-     *             if the nestedId does not correspond to a component
-     */
-    ComponentPageElement getComponentElementByNestedId(String nestedId);
-
-    /**
-     * Creates a link that will trigger behavior in a component within the page.
-     * 
-     * @param element
-     * @param action
-     * @param forForm
-     * @param context
-     * @return
-     */
-    Link createActionLink(ComponentPageElement element, String action, boolean forForm,
-            Object... context);
-
-    /**
-     * Posts a change to a persistent field.
-     * 
-     * @param element
-     *            the component element containing the field
-     * @param fieldName
-     *            the name of the field
-     * @param newValue
-     *            the new value for the field
-     */
-    void persistFieldChange(ComponentPageElement element, String fieldName, Object newValue);
-
-    /**
-     * Gets a change for a field within the component.
-     * 
-     * @param element
-     *            the element for which a persistent field value is required
-     * @param fieldName
-     *            the name of the persistent field
-     * @return the value, or null if no value is stored
-     */
-    Object getFieldChange(ComponentPageElement element, String fieldName);
-
-    /**
-     * Called as a component initially starts to render itself. This is used to check for the cases
-     * where a component causes a runtime exception that aborts the render early, leaving the page
-     * in an invalid state.
-     */
-    void incrementDirtyCount();
-
-    /** Called as a component finishes rendering itself. */
-    void decrementDirtyCount();
-}
+
+    Component getRootComponent();
+
+    /**
+     * Invoked to inform the page that it is being detached from the current request. This occurs
+     * just before the page is returned to the page pool.
+     * <p>
+     * A page may be clean or dirty. A page is dirty if its dirty count is greater than zero
+     * (meaning that, during the render of the page, some components did not fully render), or if
+     * any of its listeners throw an exception from containingPageDidDetech().
+     * <p>
+     * The page pool should discard pages that are dirty, rather than store them into the pool.
+     * 
+     * @return true if the page is "clean", false otherwise
+     * @see org.apache.tapestry.runtime.PageLifecycleListener#containingPageDidDetach()
+     */
+    boolean detached();
+
+    /**
+     * Invoked to inform the page that it is attached to the current request. This occurs when a
+     * page is first referenced within a request. If the page was created from scratch for this
+     * request, the call to {@link #loaded()} will preceded the call to {@link #attached()}.
+     */
+
+    void attached();
+
+    /**
+     * Inform the page that it is now completely loaded.
+     * 
+     * @see org.apache.tapestry.runtime.PageLifecycleListener#containingPageDidLoad()
+     */
+
+    void loaded();
+
+    /**
+     * Adds a listener that is notified of large scale page events.
+     */
+    void addLifecycleListener(PageLifecycleListener listener);
+
+    /** Returns the log of the root component element. */
+    Log getLog();
+
+    /**
+     * Retrieves a component element by its nested id (a sequence of simple ids, separated by dots).
+     * 
+     * @throws IllegalArgumentException
+     *             if the nestedId does not correspond to a component
+     */
+    ComponentPageElement getComponentElementByNestedId(String nestedId);
+
+    /**
+     * Creates a link that will trigger behavior in a component within the page.
+     * 
+     * @param linkElement
+     *            The element where the link is used (usually an &lt;a&gt). Pass null if the link is
+     *            not to be used in an element.
+     * @param element
+     * @param action
+     * @param forForm
+     * @param context
+     * @return
+     */
+    Link createActionLink(Element linkElement, ComponentPageElement element, String action,
+            boolean forForm, Object... context);
+
+    /**
+     * Posts a change to a persistent field.
+     * 
+     * @param element
+     *            the component element containing the field
+     * @param fieldName
+     *            the name of the field
+     * @param newValue
+     *            the new value for the field
+     */
+    void persistFieldChange(ComponentPageElement element, String fieldName, Object newValue);
+
+    /**
+     * Gets a change for a field within the component.
+     * 
+     * @param element
+     *            the element for which a persistent field value is required
+     * @param fieldName
+     *            the name of the persistent field
+     * @return the value, or null if no value is stored
+     */
+    Object getFieldChange(ComponentPageElement element, String fieldName);
+
+    /**
+     * Called as a component initially starts to render itself. This is used to check for the cases
+     * where a component causes a runtime exception that aborts the render early, leaving the page
+     * in an invalid state.
+     */
+    void incrementDirtyCount();
+
+    /** Called as a component finishes rendering itself. */
+    void decrementDirtyCount();
+}

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/PageImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/PageImpl.java?view=diff&rev=489299&r1=489298&r2=489299
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/PageImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/PageImpl.java Thu Dec 21 01:24:00 2006
@@ -12,173 +12,173 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package org.apache.tapestry.internal.structure;
-
+package org.apache.tapestry.internal.structure;
+
 import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newList;
-
-import java.util.List;
-import java.util.Locale;
-
-import org.apache.commons.logging.Log;
-import org.apache.tapestry.Link;
-import org.apache.tapestry.internal.services.LinkFactory;
+
+import java.util.List;
+import java.util.Locale;
+
+import org.apache.commons.logging.Log;
+import org.apache.tapestry.Link;
+import org.apache.tapestry.dom.Element;
+import org.apache.tapestry.internal.services.LinkFactory;
 import org.apache.tapestry.runtime.Component;
-import org.apache.tapestry.runtime.PageLifecycleListener;
-import org.apache.tapestry.services.PersistentFieldBundle;
-import org.apache.tapestry.services.PersistentFieldManager;
-
-public class PageImpl implements Page
-{
-    private final String _name;
-
-    private final Locale _locale;
-
-    private final LinkFactory _linkFactory;
-
-    private final PersistentFieldManager _persistentFieldManager;
-
-    private ComponentPageElement _rootElement;
-
-    private final List<PageLifecycleListener> _listeners = newList();
-
-    private int _dirtyCount;
-
-    /**
-     * Obtained from the {@link PersistentFieldManager} when first needed, discarded at the end of
-     * the request.
-     */
-    private PersistentFieldBundle _fieldBundle;
-
-    public PageImpl(String name, Locale locale, LinkFactory linkFactory,
-            PersistentFieldManager persistentFieldManager)
-    {
-        _name = name;
-        _locale = locale;
-        _linkFactory = linkFactory;
-        _persistentFieldManager = persistentFieldManager;
-    }
-
-    @Override
-    public String toString()
-    {
-        return String.format("Page[%s %s]", _name, _locale);
-    }
-
-    public ComponentPageElement getComponentElementByNestedId(String nestedId)
-    {
-        ComponentPageElement element = _rootElement;
-
-        for (String id : nestedId.split("\\."))
-            element = element.getEmbeddedElement(id);
-
-        return element;
-    }
-
-    public String getName()
-    {
-        return _name;
-    }
-
-    public Locale getLocale()
-    {
-        return _locale;
-    }
-
-    public void setRootElement(ComponentPageElement component)
-    {
-        _rootElement = component;
-    }
-
-    public ComponentPageElement getRootElement()
-    {
-        return _rootElement;
-    }
+import org.apache.tapestry.runtime.PageLifecycleListener;
+import org.apache.tapestry.services.PersistentFieldBundle;
+import org.apache.tapestry.services.PersistentFieldManager;
+
+public class PageImpl implements Page
+{
+    private final String _name;
+
+    private final Locale _locale;
+
+    private final LinkFactory _linkFactory;
+
+    private final PersistentFieldManager _persistentFieldManager;
+
+    private ComponentPageElement _rootElement;
+
+    private final List<PageLifecycleListener> _listeners = newList();
+
+    private int _dirtyCount;
+
+    /**
+     * Obtained from the {@link PersistentFieldManager} when first needed, discarded at the end of
+     * the request.
+     */
+    private PersistentFieldBundle _fieldBundle;
+
+    public PageImpl(String name, Locale locale, LinkFactory linkFactory,
+            PersistentFieldManager persistentFieldManager)
+    {
+        _name = name;
+        _locale = locale;
+        _linkFactory = linkFactory;
+        _persistentFieldManager = persistentFieldManager;
+    }
+
+    @Override
+    public String toString()
+    {
+        return String.format("Page[%s %s]", _name, _locale);
+    }
+
+    public ComponentPageElement getComponentElementByNestedId(String nestedId)
+    {
+        ComponentPageElement element = _rootElement;
+
+        for (String id : nestedId.split("\\."))
+            element = element.getEmbeddedElement(id);
+
+        return element;
+    }
+
+    public String getName()
+    {
+        return _name;
+    }
+
+    public Locale getLocale()
+    {
+        return _locale;
+    }
+
+    public void setRootElement(ComponentPageElement component)
+    {
+        _rootElement = component;
+    }
+
+    public ComponentPageElement getRootElement()
+    {
+        return _rootElement;
+    }
 
-    
     public Component getRootComponent()
     {
         return _rootElement.getComponent();
     }
 
-    public void addLifecycleListener(PageLifecycleListener listener)
-    {
-        _listeners.add(listener);
-    }
-
-    public boolean detached()
-    {
-        boolean result = _dirtyCount > 0;
-
-        for (PageLifecycleListener listener : _listeners)
-        {
-            try
-            {
-                listener.containingPageDidDetach();
-            }
-            catch (RuntimeException ex)
-            {
-                getLog().error(StructureMessages.detachFailure(listener, ex), ex);
-                result = true;
-            }
-        }
-
-        _fieldBundle = null;
-
-        return result;
-    }
-
-    public void loaded()
-    {
-        for (PageLifecycleListener listener : _listeners)
-            listener.containingPageDidLoad();
-    }
-
-    public void attached()
-    {
-        if (_dirtyCount != 0)
-            throw new IllegalStateException("Page was stored into the page pool in a dirty state.");
-
-        for (PageLifecycleListener listener : _listeners)
-            listener.containingPageDidAttach();
-    }
-
-    public Log getLog()
-    {
-        return _rootElement.getLog();
-    }
-
-    public Link createActionLink(ComponentPageElement element, String action, boolean forForm,
-            Object... context)
-    {
-        return _linkFactory.createActionLink(element, action, forForm, context);
-    }
-
-    public void persistFieldChange(ComponentPageElement element, String fieldName, Object newValue)
-    {
-        String strategy = element.getComponentResources().getComponentModel()
-                .getFieldPersistenceStrategy(fieldName);
-
-        String componentId = element.getNestedId();
-
-        _persistentFieldManager.postChange(_name, componentId, fieldName, strategy, newValue);
-    }
-
-    public Object getFieldChange(ComponentPageElement element, String fieldName)
-    {
-        if (_fieldBundle == null)
-            _fieldBundle = _persistentFieldManager.gatherChanges(_name);
-
-        return _fieldBundle.getValue(element.getNestedId(), fieldName);
-    }
-
-    public void decrementDirtyCount()
-    {
-        _dirtyCount--;
-    }
-
-    public void incrementDirtyCount()
-    {
-        _dirtyCount++;
-    }
-
-}
+    public void addLifecycleListener(PageLifecycleListener listener)
+    {
+        _listeners.add(listener);
+    }
+
+    public boolean detached()
+    {
+        boolean result = _dirtyCount > 0;
+
+        for (PageLifecycleListener listener : _listeners)
+        {
+            try
+            {
+                listener.containingPageDidDetach();
+            }
+            catch (RuntimeException ex)
+            {
+                getLog().error(StructureMessages.detachFailure(listener, ex), ex);
+                result = true;
+            }
+        }
+
+        _fieldBundle = null;
+
+        return result;
+    }
+
+    public void loaded()
+    {
+        for (PageLifecycleListener listener : _listeners)
+            listener.containingPageDidLoad();
+    }
+
+    public void attached()
+    {
+        if (_dirtyCount != 0)
+            throw new IllegalStateException("Page was stored into the page pool in a dirty state.");
+
+        for (PageLifecycleListener listener : _listeners)
+            listener.containingPageDidAttach();
+    }
+
+    public Log getLog()
+    {
+        return _rootElement.getLog();
+    }
+
+    public Link createActionLink(Element linkElement, ComponentPageElement element, String action,
+            boolean forForm, Object... context)
+    {
+        return _linkFactory.createActionLink(linkElement, element, action, forForm, context);
+    }
+
+    public void persistFieldChange(ComponentPageElement element, String fieldName, Object newValue)
+    {
+        String strategy = element.getComponentResources().getComponentModel()
+                .getFieldPersistenceStrategy(fieldName);
+
+        String componentId = element.getNestedId();
+
+        _persistentFieldManager.postChange(_name, componentId, fieldName, strategy, newValue);
+    }
+
+    public Object getFieldChange(ComponentPageElement element, String fieldName)
+    {
+        if (_fieldBundle == null)
+            _fieldBundle = _persistentFieldManager.gatherChanges(_name);
+
+        return _fieldBundle.getValue(element.getNestedId(), fieldName);
+    }
+
+    public void decrementDirtyCount()
+    {
+        _dirtyCount--;
+    }
+
+    public void incrementDirtyCount()
+    {
+        _dirtyCount++;
+    }
+
+}

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/LinkFactoryImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/LinkFactoryImplTest.java?view=diff&rev=489299&r1=489298&r2=489299
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/LinkFactoryImplTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/LinkFactoryImplTest.java Thu Dec 21 01:24:00 2006
@@ -130,10 +130,10 @@
 
         replay();
 
-        LinkFactory factory = new LinkFactoryImpl(request, response, resolver);
+        LinkFactory factory = new LinkFactoryImpl(request, response, resolver, null);
         factory.addListener(listener);
 
-        Link link = factory.createPageLink(page);
+        Link link = factory.createPageLink(null, page);
 
         assertEquals(link.toRedirectURI(), "*encoded*");
 
@@ -187,10 +187,10 @@
 
         replay();
 
-        LinkFactory factory = new LinkFactoryImpl(request, response, resolver);
+        LinkFactory factory = new LinkFactoryImpl(request, response, resolver, null);
         factory.addListener(listener);
 
-        Link link = factory.createActionLink(element, "someaction", false, context);
+        Link link = factory.createActionLink(null, element, "someaction", false, context);
 
         assertEquals(link.toURI(), "*encoded*");
         assertSame(link, holder.get());