You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tapestry.apache.org by hl...@apache.org on 2008/01/08 01:08:26 UTC

svn commit: r609814 - in /tapestry/tapestry5/trunk/tapestry-core/src: main/java/org/apache/tapestry/ main/java/org/apache/tapestry/internal/ main/java/org/apache/tapestry/internal/services/ main/java/org/apache/tapestry/internal/structure/ test/java/or...

Author: hlship
Date: Mon Jan  7 16:08:25 2008
New Revision: 609814

URL: http://svn.apache.org/viewvc?rev=609814&view=rev
Log:
TAPESTRY-2014: ComponentResources should expose the page's lifecycle to interested listeners

Modified:
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/ComponentResources.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/ComponentResourcesCommon.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/InternalComponentResources.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/InternalComponentResourcesCommon.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/ComponentActionDispatcher.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/LinkFactory.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/LinkFactoryImpl.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/structure/ComponentPageElement.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/structure/ComponentPageElementImpl.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/structure/InternalComponentResourcesImpl.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/structure/Page.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/structure/PageImpl.java
    tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/LinkFactoryImplTest.java
    tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/structure/InternalComponentResourcesImplTest.java

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/ComponentResources.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/ComponentResources.java?rev=609814&r1=609813&r2=609814&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/ComponentResources.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/ComponentResources.java Mon Jan  7 16:08:25 2008
@@ -1,4 +1,4 @@
-// Copyright 2006, 2007 The Apache Software Foundation
+// Copyright 2006, 2007, 2008 The Apache Software Foundation
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -19,6 +19,7 @@
 import org.apache.tapestry.ioc.Resource;
 import org.apache.tapestry.model.ComponentModel;
 import org.apache.tapestry.runtime.Component;
+import org.apache.tapestry.runtime.PageLifecycleListener;
 
 /**
  * Provides a component instance with the resources provided by the framework. In many
@@ -144,4 +145,36 @@
      * @throws IllegalStateException if the component is not currently rendering
      */
     void storeRenderVariable(String name, Object value);
+
+    /**
+     * Adds a listener object that will be notified about page lifecycle events.
+     */
+    void addPageLifecycleListener(PageLifecycleListener listener);
+
+
+    /**
+     * Creates a component action request link as a callback for this component. The event type
+     * and context (as well as the page name and nested component id) will be encoded into a URL. A request for the
+     * URL will {@linkplain #triggerEvent(String, Object[], ComponentEventHandler)}  trigger} the named event
+     * on the component.
+     *
+     * @param eventType the type of event to be triggered.  Event types should be Java identifiers (contain only letters, numbers and the underscore).
+     * @param forForm   if true, the link will be used as the eventType for an HTML form submission, which
+     *                  may affect what information is encoded into the link
+     * @param context   additional objects to be encoded into the path portion of the link; each is
+     *                  converted to a string and URI encoded
+     * @return link object for the callback
+     */
+    Link createActionLink(String eventType, boolean forForm, Object... context);
+
+    /**
+     * Creates a render request link to a specific page.
+     *
+     * @param pageName the logical name of the page to link to
+     * @param override if true, the context is used even if empty (normally, the target page is allowed
+     *                 to passivate, providing a context, when the provided context is empty)
+     * @param context  the activation context for the page. If omitted, the activation context is
+     *                 obtained from the target paget
+     */
+    Link createPageLink(String pageName, boolean override, Object... context);
 }

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/ComponentResourcesCommon.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/ComponentResourcesCommon.java?rev=609814&r1=609813&r2=609814&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/ComponentResourcesCommon.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/ComponentResourcesCommon.java Mon Jan  7 16:08:25 2008
@@ -1,4 +1,4 @@
-// Copyright 2006, 2007 The Apache Software Foundation
+// Copyright 2006, 2007, 2008 The Apache Software Foundation
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -43,31 +43,6 @@
      */
     String getNestedId();
 
-    /**
-     * Creates a component action request link as a callback for this component. The event type
-     * and context (as well as the page name and nested component id) will be encoded into a URL. A request for the
-     * URL will {@linkplain #triggerEvent(String, Object[], ComponentEventHandler)}  trigger} the named event
-     * on the component.
-     *
-     * @param eventType the type of event to be triggered.  Event types should be Java identifiers (contain only letters, numbers and the underscore).
-     * @param forForm   if true, the link will be used as the eventType for an HTML form submission, which
-     *                  may affect what information is encoded into the link
-     * @param context   additional objects to be encoded into the path portion of the link; each is
-     *                  converted to a string and URI encoded
-     * @return link object for the callback
-     */
-    Link createActionLink(String eventType, boolean forForm, Object... context);
-
-    /**
-     * Creates a render request link to a specific page.
-     *
-     * @param pageName the logical name of the page to link to
-     * @param override if true, the context is used even if empty (normally, the target page is allowed
-     *                 to passivate, providing a context, when the provided context is empty)
-     * @param context  the activation context for the page. If omitted, the activation context is
-     *                 obtained from the target paget
-     */
-    Link createPageLink(String pageName, boolean override, Object... context);
 
     /**
      * Returns a string consisting of the logical name of the containing page, and the
@@ -85,7 +60,7 @@
      * Triggers a component event. A search for an event handling method will occur, first in the
      * component, then its container, and so on. When a matching event handler method is located, it
      * is invoked. If the method returns a value, the value is passed to the handler (if handler is
-     * null, then it is an error for a method to return a non-null vavlue).
+     * null, then it is an error for a method to return a non-null value).
      * <p/>
      * Resolution of event type to event handler methods is case insensitive.
      *

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/InternalComponentResources.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/InternalComponentResources.java?rev=609814&r1=609813&r2=609814&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/InternalComponentResources.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/InternalComponentResources.java Mon Jan  7 16:08:25 2008
@@ -16,16 +16,37 @@
 
 import org.apache.tapestry.ComponentResources;
 import org.apache.tapestry.internal.structure.Page;
+import org.apache.tapestry.runtime.RenderQueue;
 import org.apache.tapestry.services.PersistentFieldManager;
 
 /**
  * An extension of {@link org.apache.tapestry.ComponentResources} that represents additional methods
- * that are private to the framework and not exposed in any public APIs. Ideally, there will not be
- * any need for this interface (we'll see as we go).
+ * that are private to the framework and not exposed in any public APIs.
  */
 public interface InternalComponentResources extends ComponentResources, InternalComponentResourcesCommon
 {
     /**
+     * Get the current persisted value of the field.
+     *
+     * @param fieldName the name of the field to access
+     * @return the value stored for the field, or null if no value is currently stored
+     */
+    Object getFieldChange(String fieldName);
+
+    /**
+     * Checks to see if there is a value stored for the indicated field.
+     */
+    boolean hasFieldChange(String fieldName);
+
+    /**
+     * Posts a change to a persistent field. If the component is still loading, then this change is
+     * ignored. Otherwise, it is propagated, via the
+     * {@link Page#persistFieldChange(org.apache.tapestry.ComponentResources, String, Object) page}
+     * to the {@link PersistentFieldManager}.
+     */
+    void persistFieldChange(String fieldName, Object newValue);
+
+    /**
      * Reads the value of a parameter, via the parameter's {@link org.apache.tapestry.Binding}.
      *
      * @param <T>
@@ -61,20 +82,17 @@
      * aggressively than variant bindings.
      *
      * @param parameterName the name of parameter to check for invariance
-     * @return
+     * @return true if the binding is an invariant, false if the binding has no fixed value
      */
     boolean isInvariant(String parameterName);
 
     /**
-     * Posts a change to a persistent field. If the component is still loading, then this change is
-     * ignored. Otherwise, it is propagated, via the
-     * {@link Page#persistFieldChange(org.apache.tapestry.ComponentResources, String, Object) page}
-     * to the {@link PersistentFieldManager}.
+     * Allows the resources to cleanup any render-time only data.
      */
-    void persistFieldChange(String fieldName, Object newValue);
+    void postRenderCleanup();
 
     /**
-     * Allows the resources to cleanup any render-time only data.
+     * Invoked to make the receiver queue itself to be rendered.
      */
-    void postRenderCleanup();
+    void queueRender(RenderQueue queue);
 }

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/InternalComponentResourcesCommon.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/InternalComponentResourcesCommon.java?rev=609814&r1=609813&r2=609814&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/InternalComponentResourcesCommon.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/InternalComponentResourcesCommon.java Mon Jan  7 16:08:25 2008
@@ -17,7 +17,6 @@
 import org.apache.tapestry.Binding;
 import org.apache.tapestry.internal.structure.ComponentPageElement;
 import org.apache.tapestry.runtime.Component;
-import org.apache.tapestry.runtime.RenderQueue;
 
 import java.util.Map;
 
@@ -29,19 +28,6 @@
 public interface InternalComponentResourcesCommon
 {
     /**
-     * Get the current persisted value of the field.
-     *
-     * @param fieldName the name of the field to access
-     * @return the value stored for the field, or null if no value is currently stored
-     */
-    Object getFieldChange(String fieldName);
-
-    /**
-     * Checks to see if there is a value stored for the indicated field.
-     */
-    boolean hasFieldChange(String fieldName);
-
-    /**
      * Returns true if the component has finished loading. Initially, this value will be false.
      *
      * @see org.apache.tapestry.runtime.PageLifecycleListener#containingPageDidLoad()
@@ -61,11 +47,6 @@
      * @return IllegalArgumentException if no such mixin is associated with the core component
      */
     Component getMixinByClassName(String mixinClassName);
-
-    /**
-     * Invoked to make the receiver queue itself to be rendered.
-     */
-    void queueRender(RenderQueue queue);
 
     /**
      * Constructs a map linking informal parameters to the corresponding bindings.

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/ComponentActionDispatcher.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/ComponentActionDispatcher.java?rev=609814&r1=609813&r2=609814&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/ComponentActionDispatcher.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/ComponentActionDispatcher.java Mon Jan  7 16:08:25 2008
@@ -45,7 +45,7 @@
  * <p/>
  * <p/>
  *
- * @see org.apache.tapestry.internal.services.LinkFactory#createActionLink(org.apache.tapestry.internal.structure.ComponentPageElement, String, boolean, Object[])
+ * @see LinkFactory#createActionLink(org.apache.tapestry.internal.structure.Page, String, String,boolean, Object...)
  */
 public class ComponentActionDispatcher implements Dispatcher
 {

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/LinkFactory.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/LinkFactory.java?rev=609814&r1=609813&r2=609814&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/LinkFactory.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/LinkFactory.java Mon Jan  7 16:08:25 2008
@@ -1,4 +1,4 @@
-// Copyright 2006, 2007 The Apache Software Foundation
+// Copyright 2006, 2007, 2008 The Apache Software Foundation
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -15,7 +15,6 @@
 package org.apache.tapestry.internal.services;
 
 import org.apache.tapestry.Link;
-import org.apache.tapestry.internal.structure.ComponentPageElement;
 import org.apache.tapestry.internal.structure.Page;
 
 /**
@@ -29,15 +28,15 @@
      * 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 component the component for which an action link is to be generated
+     * @param page
+     * @param nestedId
      * @param eventType the type of event to trigger
      * @param forForm   true if the link is for a form, false otherwise
      * @param context   Additional path data, each value will be converted to a string and appended to the
-     *                  URI
-     * @return a link
-     * @see org.apache.tapestry.ComponentResourcesCommon#createActionLink(String, boolean, Object[])
+     *                  URI @return a link
+     * @see org.apache.tapestry.ComponentResources#createActionLink(String, boolean, Object[])
      */
-    Link createActionLink(ComponentPageElement component, String eventType, boolean forForm, Object... context);
+    Link createActionLink(Page page, String nestedId, String eventType, boolean forForm, Object... context);
 
     /**
      * Creates a render link for the page. If an activation context is supplied then that context is
@@ -53,7 +52,7 @@
      * @param override          if true, then the provided activation context is always used even if empty
      * @param activationContext the activation context for the page
      * @return a link
-     * @see org.apache.tapestry.ComponentResourcesCommon#createPageLink(String, boolean, Object[])
+     * @see org.apache.tapestry.ComponentResources#createPageLink(String, boolean, Object[])
      */
     Link createPageLink(Page page, boolean override, Object... activationContext);
 
@@ -72,7 +71,7 @@
      * Adds a listener, to be notified any time an action or render link is created; this allows the
      * listener to modify the link (by adding additional query parameters to the link).
      *
-     * @param listener
+     * @param listener to add
      */
     void addListener(LinkFactoryListener listener);
 }

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/LinkFactoryImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/LinkFactoryImpl.java?rev=609814&r1=609813&r2=609814&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/LinkFactoryImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/LinkFactoryImpl.java Mon Jan  7 16:08:25 2008
@@ -1,4 +1,4 @@
-// Copyright 2006, 2007 The Apache Software Foundation
+// Copyright 2006, 2007, 2008 The Apache Software Foundation
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -103,20 +103,18 @@
         _listeners.add(listener);
     }
 
-    public Link createActionLink(ComponentPageElement component, String eventType, boolean forForm, Object... context)
+    public Link createActionLink(Page page, String nestedId, String eventType, boolean forForm, Object... context)
     {
+        notNull(page, "page");
         notBlank(eventType, "action");
 
-        Page containingPage = component.getContainingPage();
+        String logicalPageName = page.getLogicalName();
 
-        String logicalPageName = containingPage.getLogicalName();
-
-        ActionLinkTarget target = new ActionLinkTarget(eventType, logicalPageName, component
-                .getNestedId());
+        ActionLinkTarget target = new ActionLinkTarget(eventType, logicalPageName, nestedId);
 
         String[] contextStrings = toContextStrings(context);
 
-        String[] activationContext = collectActivationContextForPage(containingPage);
+        String[] activationContext = collectActivationContextForPage(page);
 
         ComponentInvocation invocation = new ComponentInvocationImpl(target, contextStrings, activationContext);
 
@@ -153,7 +151,7 @@
 
     }
 
-    public Link createPageLink(final Page page, boolean override, Object... activationContext)
+    public Link createPageLink(Page page, boolean override, Object... activationContext)
     {
         notNull(page, "page");
 

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/structure/ComponentPageElement.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/structure/ComponentPageElement.java?rev=609814&r1=609813&r2=609814&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/structure/ComponentPageElement.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/structure/ComponentPageElement.java Mon Jan  7 16:08:25 2008
@@ -1,21 +1,20 @@
-// Copyright 2006, 2007 The Apache Software Foundation
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
+// Copyright 2006, 2007, 2008 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
 package org.apache.tapestry.internal.structure;
 
 import org.apache.tapestry.Block;
-import org.apache.tapestry.ComponentResources;
 import org.apache.tapestry.ComponentResourcesCommon;
 import org.apache.tapestry.internal.InternalComponentResources;
 import org.apache.tapestry.internal.InternalComponentResourcesCommon;
@@ -24,7 +23,6 @@
 import org.apache.tapestry.runtime.Component;
 import org.apache.tapestry.runtime.ComponentEvent;
 import org.apache.tapestry.runtime.RenderQueue;
-import org.apache.tapestry.services.PersistentFieldManager;
 
 /**
  * Extended version of {@link org.apache.tapestry.internal.structure.PageElement} for elements that
@@ -114,12 +112,4 @@
      * @return the default binding prefix, or null
      */
     String getDefaultBindingPrefix(String parameterName);
-
-    /**
-     * Posts a change to a persistent field. If the component is still loading, then this change is
-     * ignored. Otherwise, it is propogated, via the
-     * {@link Page#persistFieldChange(ComponentResources, String, Object) page} to the
-     * {@link PersistentFieldManager#postChange(String, ComponentResources, String, Object) PersistentFieldManager}.
-     */
-    void persistFieldChange(ComponentResources resources, String fieldName, Object newValue);
 }

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/structure/ComponentPageElementImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/structure/ComponentPageElementImpl.java?rev=609814&r1=609813&r2=609814&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/structure/ComponentPageElementImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/structure/ComponentPageElementImpl.java Mon Jan  7 16:08:25 2008
@@ -529,11 +529,6 @@
         ComponentResources containerResources = container == null ? null : container
                 .getComponentResources();
 
-        _coreResources = new InternalComponentResourcesImpl(this, containerResources, instantiator, _typeCoercer,
-                                                            _messagesSource, _componentClassCache);
-
-        _coreComponent = _coreResources.getComponent();
-
         String pageName = _page.getLogicalName();
 
         // A page (really, the root component of a page) does not have a container.
@@ -563,6 +558,11 @@
                 _completeId = container.getCompleteId() + "." + caselessId;
             }
         }
+
+        _coreResources = new InternalComponentResourcesImpl(_page, this, containerResources, instantiator, _typeCoercer,
+                                                            _messagesSource, _componentClassCache);
+
+        _coreComponent = _coreResources.getComponent();
     }
 
     /**
@@ -598,7 +598,7 @@
         String mixinClassName = instantiator.getModel().getComponentClassName();
         String mixinName = TapestryInternalUtils.lastTerm(mixinClassName);
 
-        InternalComponentResourcesImpl resources = new InternalComponentResourcesImpl(this, _coreResources,
+        InternalComponentResourcesImpl resources = new InternalComponentResourcesImpl(_page, this, _coreResources,
                                                                                       instantiator, _typeCoercer,
                                                                                       _messagesSource,
                                                                                       _componentClassCache);
@@ -750,21 +750,6 @@
         verifyRequiredParametersAreBound();
     }
 
-    /**
-     * Delegates to the
-     * {@link Page#createActionLink(ComponentPageElement, String, boolean, Object[]) the containing page}.
-     * Why the extra layer? Trying to avoid some unwanted injection (of LinkFactory, into every
-     * component page element).
-     */
-    public Link createActionLink(String action, boolean forForm, Object... context)
-    {
-        return _page.createActionLink(this, action, forForm, context);
-    }
-
-    public Link createPageLink(String pageName, boolean override, Object... context)
-    {
-        return _page.createPageLink(pageName, override, context);
-    }
 
     public void enqueueBeforeRenderBody(RenderQueue queue)
     {
@@ -809,10 +794,6 @@
         return embeddedElement;
     }
 
-    public Object getFieldChange(String fieldName)
-    {
-        return _page.getFieldChange(this, fieldName);
-    }
 
     public String getId()
     {
@@ -871,11 +852,6 @@
         return result;
     }
 
-    public boolean hasFieldChange(String fieldName)
-    {
-        return getFieldChange(fieldName) != null;
-    }
-
     /**
      * Invokes a callback on the component instances (the core component plus any mixins).
      *
@@ -915,14 +891,6 @@
         return _rendering;
     }
 
-    public void persistFieldChange(ComponentResources resources, String fieldName, Object newValue)
-    {
-        // While loading the page (i.e., when setting field defaults), ignore these
-        // changes.
-
-        if (_loaded) _page.persistFieldChange(resources, fieldName, newValue);
-    }
-
     /**
      * Generate a toString() for the inner classes that represent render phases.
      */
@@ -1019,11 +987,6 @@
     public String getElementName()
     {
         return _elementName;
-    }
-
-    public void queueRender(RenderQueue queue)
-    {
-        queue.push(this);
     }
 
     public Block getBlock(String id)

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/structure/InternalComponentResourcesImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/structure/InternalComponentResourcesImpl.java?rev=609814&r1=609813&r2=609814&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/structure/InternalComponentResourcesImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/structure/InternalComponentResourcesImpl.java Mon Jan  7 16:08:25 2008
@@ -30,6 +30,7 @@
 import org.apache.tapestry.ioc.services.TypeCoercer;
 import org.apache.tapestry.model.ComponentModel;
 import org.apache.tapestry.runtime.Component;
+import org.apache.tapestry.runtime.PageLifecycleListener;
 import org.apache.tapestry.runtime.RenderQueue;
 import org.apache.tapestry.services.ComponentMessagesSource;
 import org.slf4j.Logger;
@@ -44,6 +45,10 @@
  */
 public class InternalComponentResourcesImpl implements InternalComponentResources
 {
+    private final Page _page;
+
+    private final String _nestedId;
+
     private final ComponentModel _componentModel;
 
     private final ComponentPageElement _element;
@@ -66,11 +71,12 @@
     // Case insensitive
     private Map<String, Object> _renderVariables;
 
-    public InternalComponentResourcesImpl(ComponentPageElement element, ComponentResources containerResources,
-                                          Instantiator componentInstantiator, TypeCoercer typeCoercer,
-                                          ComponentMessagesSource messagesSource,
+    public InternalComponentResourcesImpl(Page page, ComponentPageElement element,
+                                          ComponentResources containerResources, Instantiator componentInstantiator,
+                                          TypeCoercer typeCoercer, ComponentMessagesSource messagesSource,
                                           ComponentClassCache componentClassCache)
     {
+        _page = page;
         _element = element;
         _containerResources = containerResources;
         _componentClassCache = componentClassCache;
@@ -78,6 +84,8 @@
         _typeCoercer = typeCoercer;
         _messagesSource = messagesSource;
 
+        _nestedId = _element.getNestedId();
+
         _component = componentInstantiator.newInstance(this);
     }
 
@@ -104,7 +112,7 @@
 
     public Object getFieldChange(String fieldName)
     {
-        return _element.getFieldChange(fieldName);
+        return _page.getFieldChange(_nestedId, fieldName);
     }
 
     public String getId()
@@ -114,19 +122,26 @@
 
     public boolean hasFieldChange(String fieldName)
     {
-        return _element.hasFieldChange(fieldName);
+        return getFieldChange(fieldName) != null;
     }
 
+    /**
+     * Delegates to the
+     * {@link Page#createActionLink(String, String, boolean, Object[])} on the containing page.
+     * Why the extra layer? Trying to avoid some unwanted injection (of LinkFactory, into every
+     * component page element).
+     */
     public Link createActionLink(String action, boolean forForm, Object... context)
     {
-        return _element.createActionLink(action, forForm, context);
+        return _page.createActionLink(_nestedId, action, forForm, context);
     }
 
     public Link createPageLink(String pageName, boolean override, Object... context)
     {
-        return _element.createPageLink(pageName, override, context);
+        return _page.createPageLink(pageName, override, context);
     }
 
+
     public String getCompleteId()
     {
         return _element.getCompleteId();
@@ -178,7 +193,7 @@
     {
         try
         {
-            _element.persistFieldChange(this, fieldName, newValue);
+            _page.persistFieldChange(this, fieldName, newValue);
         }
         catch (Exception ex)
         {
@@ -332,7 +347,7 @@
 
     public void queueRender(RenderQueue queue)
     {
-        _element.queueRender(queue);
+        queue.push(_element);
     }
 
     public Block getBlock(String blockId)
@@ -410,5 +425,10 @@
     public void postRenderCleanup()
     {
         if (_renderVariables != null) _renderVariables.clear();
+    }
+
+    public void addPageLifecycleListener(PageLifecycleListener listener)
+    {
+        _page.addLifecycleListener(listener);
     }
 }

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/structure/Page.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/structure/Page.java?rev=609814&r1=609813&r2=609814&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/structure/Page.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/structure/Page.java Mon Jan  7 16:08:25 2008
@@ -1,4 +1,4 @@
-// Copyright 2006, 2007 The Apache Software Foundation
+// Copyright 2006, 2007, 2008 The Apache Software Foundation
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -118,14 +118,14 @@
     /**
      * Creates a link that will trigger behavior in a component within the page.
      *
-     * @see org.apache.tapestry.ComponentResourcesCommon#createActionLink(String, boolean, Object[])
+     * @see org.apache.tapestry.ComponentResources#createActionLink(String, boolean, Object[])
      */
-    Link createActionLink(ComponentPageElement element, String eventType, boolean forForm, Object... context);
+    Link createActionLink(String nestedId, String eventType, boolean forForm, Object... context);
 
     /**
      * Creates a link to the named page.
      *
-     * @see org.apache.tapestry.ComponentResourcesCommon#createPageLink(String, boolean, Object[])
+     * @see org.apache.tapestry.ComponentResources#createPageLink(String, boolean, Object[])
      */
     Link createPageLink(String pageName, boolean override, Object... context);
 
@@ -146,7 +146,7 @@
      * @param fieldName the name of the persistent field
      * @return the value, or null if no value is stored
      */
-    Object getFieldChange(ComponentPageElement element, String fieldName);
+    Object getFieldChange(String nestedId, String fieldName);
 
     /**
      * Called as a component initially starts to render itself. This is used to check for the cases

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/structure/PageImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/structure/PageImpl.java?rev=609814&r1=609813&r2=609814&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/structure/PageImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/structure/PageImpl.java Mon Jan  7 16:08:25 2008
@@ -1,4 +1,4 @@
-// Copyright 2006, 2007 The Apache Software Foundation
+// Copyright 2006, 2007, 2008 The Apache Software Foundation
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -151,9 +151,9 @@
         return _rootElement.getLogger();
     }
 
-    public Link createActionLink(ComponentPageElement element, String eventType, boolean forForm, Object... context)
+    public Link createActionLink(String nestedId, String eventType, boolean forForm, Object... context)
     {
-        return _linkFactory.createActionLink(element, eventType, forForm, context);
+        return _linkFactory.createActionLink(this, nestedId, eventType, forForm, context);
     }
 
     public Link createPageLink(String pageName, boolean override, Object... context)
@@ -166,11 +166,11 @@
         _persistentFieldManager.postChange(_logicalPageName, resources, fieldName, newValue);
     }
 
-    public Object getFieldChange(ComponentPageElement element, String fieldName)
+    public Object getFieldChange(String nestedId, String fieldName)
     {
         if (_fieldBundle == null) _fieldBundle = _persistentFieldManager.gatherChanges(_logicalPageName);
 
-        return _fieldBundle.getValue(element.getNestedId(), fieldName);
+        return _fieldBundle.getValue(nestedId, fieldName);
     }
 
     public void decrementDirtyCount()

Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/LinkFactoryImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/LinkFactoryImplTest.java?rev=609814&r1=609813&r2=609814&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/LinkFactoryImplTest.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/LinkFactoryImplTest.java Mon Jan  7 16:08:25 2008
@@ -1,4 +1,4 @@
-// Copyright 2006, 2007 The Apache Software Foundation
+// Copyright 2006, 2007, 2008 The Apache Software Foundation
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -329,7 +329,6 @@
     {
         Request request = mockRequest();
         Response response = mockResponse();
-        ComponentPageElement element = mockComponentPageElement();
         Page page = mockPage();
         ComponentPageElement rootElement = mockComponentPageElement();
         LinkFactoryListener listener = mockLinkFactoryListener();
@@ -338,10 +337,8 @@
 
         final Holder<Link> holder = new Holder<Link>();
 
-        train_getContainingPage(element, page);
         train_getLogicalName(page, "mypage");
         train_getContextPath(request, "");
-        train_getNestedId(element, null);
 
         train_getRootElement(page, rootElement);
         train_triggerPassivateEventForActionLink(rootElement, listener, holder);
@@ -357,7 +354,7 @@
         LinkFactory factory = new LinkFactoryImpl(request, response, map, cache, _typeCoercer);
         factory.addListener(listener);
 
-        Link link = factory.createActionLink(element, "myaction", false, "1.2.3", "4.5.6");
+        Link link = factory.createActionLink(page, null, "myaction", false, "1.2.3", "4.5.6");
 
         assertEquals(link.toURI(), ENCODED);
         assertSame(link, holder.get());
@@ -373,19 +370,16 @@
     {
         Request request = mockRequest();
         Response response = mockResponse();
-        ComponentPageElement element = mockComponentPageElement();
-        Page page = mockPage();
         ComponentPageElement rootElement = mockComponentPageElement();
+        Page page = mockPage();
         LinkFactoryListener listener = mockLinkFactoryListener();
         ComponentInvocationMap map = mockComponentInvocationMap();
         RequestPageCache cache = mockRequestPageCache();
 
         final Holder<Link> holder = new Holder<Link>();
 
-        train_getContainingPage(element, page);
         train_getLogicalName(page, logicalPageName);
         train_getContextPath(request, contextPath);
-        train_getNestedId(element, nestedId);
 
         train_getRootElement(page, rootElement);
         train_triggerPassivateEventForActionLink(rootElement, listener, holder);
@@ -402,7 +396,7 @@
         LinkFactory factory = new LinkFactoryImpl(request, response, map, cache, _typeCoercer);
         factory.addListener(listener);
 
-        Link link = factory.createActionLink(element, eventName, false, context);
+        Link link = factory.createActionLink(page, nestedId, eventName, false, context);
 
         assertEquals(link.toURI(), ENCODED);
         assertSame(link, holder.get());

Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/structure/InternalComponentResourcesImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/structure/InternalComponentResourcesImplTest.java?rev=609814&r1=609813&r2=609814&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/structure/InternalComponentResourcesImplTest.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/structure/InternalComponentResourcesImplTest.java Mon Jan  7 16:08:25 2008
@@ -24,6 +24,7 @@
 import org.apache.tapestry.model.ComponentModel;
 import org.apache.tapestry.model.ParameterModel;
 import org.apache.tapestry.runtime.Component;
+import org.apache.tapestry.runtime.PageLifecycleListener;
 import org.testng.annotations.Test;
 
 public class InternalComponentResourcesImplTest extends InternalBaseTestCase
@@ -38,12 +39,14 @@
         TypeCoercer coercer = mockTypeCoercer();
         ComponentModel model = mockComponentModel();
 
+        train_getNestedId(element, "foo.bar");
+
         train_getModel(ins, model);
 
         replay();
 
-        InternalComponentResources resources = new InternalComponentResourcesImpl(element, null, ins, coercer, null,
-                                                                                  null);
+        InternalComponentResources resources = new InternalComponentResourcesImpl(null, element, null, ins, coercer,
+                                                                                  null, null);
 
         resources.renderInformalParameters(writer);
 
@@ -62,14 +65,16 @@
         ParameterModel pmodel = mockParameterModel();
         Binding binding = mockBinding();
 
+        train_getNestedId(element, "foo.bar");
+
         train_getModel(ins, model);
 
         train_getParameterModel(model, "fred", pmodel);
 
         replay();
 
-        InternalComponentResources resources = new InternalComponentResourcesImpl(element, null, ins, coercer, null,
-                                                                                  null);
+        InternalComponentResources resources = new InternalComponentResourcesImpl(null, element, null, ins, coercer,
+                                                                                  null, null);
 
         resources.bindParameter("fred", binding);
 
@@ -91,6 +96,8 @@
         Object rawValue = new Object();
         String convertedValue = "*converted*";
 
+        train_getNestedId(element, "foo.bar");
+
         train_getModel(ins, model);
 
         train_getParameterModel(model, "fred", null);
@@ -103,8 +110,8 @@
 
         replay();
 
-        InternalComponentResources resources = new InternalComponentResourcesImpl(element, null, ins, coercer, null,
-                                                                                  null);
+        InternalComponentResources resources = new InternalComponentResourcesImpl(null, element, null, ins, coercer,
+                                                                                  null, null);
 
         resources.bindParameter("fred", binding);
 
@@ -123,13 +130,15 @@
 
         Object value = new Object();
 
+        train_getNestedId(element, "foo.bar");
+
         train_getModel(ins, model);
 
         train_isRendering(element, true);
 
         replay();
 
-        ComponentResources resources = new InternalComponentResourcesImpl(element, null, ins, null, null, null);
+        ComponentResources resources = new InternalComponentResourcesImpl(null, element, null, ins, null, null, null);
 
         resources.storeRenderVariable("myRenderVar", value);
 
@@ -151,6 +160,8 @@
         ComponentModel model = mockComponentModel();
         ComponentPageElement element = mockComponentPageElement();
 
+        train_getNestedId(element, "foo.bar");
+
         train_getModel(ins, model);
 
         train_isRendering(element, true);
@@ -160,7 +171,7 @@
 
         replay();
 
-        ComponentResources resources = new InternalComponentResourcesImpl(element, null, ins, null, null, null);
+        ComponentResources resources = new InternalComponentResourcesImpl(null, element, null, ins, null, null, null);
 
         resources.storeRenderVariable("fred", "FRED");
         resources.storeRenderVariable("barney", "BARNEY");
@@ -187,6 +198,8 @@
         ComponentModel model = mockComponentModel();
         ComponentPageElement element = mockComponentPageElement();
 
+        train_getNestedId(element, "bar");
+
         train_getModel(ins, model);
 
         train_isRendering(element, true);
@@ -196,7 +209,8 @@
 
         replay();
 
-        InternalComponentResources resources = new InternalComponentResourcesImpl(element, null, ins, null, null, null);
+        InternalComponentResources resources = new InternalComponentResourcesImpl(null, element, null, ins, null, null,
+                                                                                  null);
 
         resources.storeRenderVariable("fred", "FRED");
         resources.storeRenderVariable("barney", "BARNEY");
@@ -225,6 +239,8 @@
         ComponentModel model = mockComponentModel();
         ComponentPageElement element = mockComponentPageElement();
 
+        train_getNestedId(element, "foo.bar");
+
         train_getModel(ins, model);
 
         train_isRendering(element, false);
@@ -233,7 +249,8 @@
 
         replay();
 
-        InternalComponentResources resources = new InternalComponentResourcesImpl(element, null, ins, null, null, null);
+        InternalComponentResources resources = new InternalComponentResourcesImpl(null, element, null, ins, null, null,
+                                                                                  null);
 
 
         try
@@ -246,6 +263,32 @@
             assertEquals(ex.getMessage(),
                          "Component Foo.bar is not rendering, so render variable 'fred' may not be updated.");
         }
+
+        verify();
+    }
+
+    @Test
+    public void add_page_lifecycle_listener()
+    {
+        Component component = mockComponent();
+        Instantiator ins = mockInstantiator(component);
+        ComponentModel model = mockComponentModel();
+        ComponentPageElement element = mockComponentPageElement();
+        Page page = mockPage();
+        PageLifecycleListener listener = newMock(PageLifecycleListener.class);
+
+        train_getNestedId(element, "foo.bar");
+
+        train_getModel(ins, model);
+
+        page.addLifecycleListener(listener);
+
+        replay();
+
+        InternalComponentResources resources = new InternalComponentResourcesImpl(page, element, null, ins, null, null,
+                                                                                  null);
+
+        resources.addPageLifecycleListener(listener);
 
         verify();
     }