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 2014/03/04 03:08:17 UTC

git commit: TAP5-1802: Avoid an NPE when no Request object is known

Repository: tapestry-5
Updated Branches:
  refs/heads/master 0046b167a -> c33c963d1


TAP5-1802: Avoid an NPE when no Request object is known

Re-organize code to move logic out of ComponentPageElementImpl and into Page and ComponentElementResources.


Project: http://git-wip-us.apache.org/repos/asf/tapestry-5/repo
Commit: http://git-wip-us.apache.org/repos/asf/tapestry-5/commit/c33c963d
Tree: http://git-wip-us.apache.org/repos/asf/tapestry-5/tree/c33c963d
Diff: http://git-wip-us.apache.org/repos/asf/tapestry-5/diff/c33c963d

Branch: refs/heads/master
Commit: c33c963d1d457dfa35a5b4586298a7df5275d41d
Parents: 0046b16
Author: Howard M. Lewis Ship <hl...@apache.org>
Authored: Mon Mar 3 18:08:06 2014 -0800
Committer: Howard M. Lewis Ship <hl...@apache.org>
Committed: Mon Mar 3 18:08:06 2014 -0800

----------------------------------------------------------------------
 .../pageload/ComponentAssemblerImpl.java        | 21 ++----
 .../internal/pageload/PageLoaderImpl.java       | 20 +++---
 .../structure/ComponentPageElementImpl.java     | 37 ++--------
 .../ComponentPageElementResources.java          | 66 ++++++++++--------
 .../ComponentPageElementResourcesImpl.java      | 35 +++++++++-
 ...ComponentPageElementResourcesSourceImpl.java | 23 +++++--
 .../tapestry5/internal/structure/Page.java      | 12 +++-
 .../tapestry5/internal/structure/PageImpl.java  | 17 ++++-
 ...ComponentPageElementResourcesImplTest.groovy | 67 ++++++++++++++++++
 .../structure/ComponentPageElementImplTest.java | 72 --------------------
 .../InternalComponentResourcesImplTest.java     |  4 +-
 .../internal/structure/PageImplTest.java        | 37 ++++++++--
 12 files changed, 230 insertions(+), 181 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c33c963d/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/ComponentAssemblerImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/ComponentAssemblerImpl.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/ComponentAssemblerImpl.java
index 91d42b9..5e952cd 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/ComponentAssemblerImpl.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/ComponentAssemblerImpl.java
@@ -1,4 +1,4 @@
-// Copyright 2009-2013 The Apache Software Foundation
+// Copyright 2009-2014 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.
@@ -25,15 +25,12 @@ import org.apache.tapestry5.ioc.Resource;
 import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
 import org.apache.tapestry5.ioc.internal.util.InternalUtils;
 import org.apache.tapestry5.ioc.internal.util.TapestryException;
-import org.apache.tapestry5.ioc.services.SymbolSource;
 import org.apache.tapestry5.ioc.util.ExceptionUtils;
 import org.apache.tapestry5.ioc.util.IdAllocator;
 import org.apache.tapestry5.model.ComponentModel;
 import org.apache.tapestry5.model.EmbeddedComponentModel;
 import org.apache.tapestry5.runtime.RenderCommand;
 import org.apache.tapestry5.services.ComponentClassResolver;
-import org.apache.tapestry5.services.MetaDataLocator;
-import org.apache.tapestry5.services.Request;
 import org.apache.tapestry5.services.pageload.ComponentResourceSelector;
 
 import java.util.List;
@@ -57,20 +54,13 @@ class ComponentAssemblerImpl implements ComponentAssembler
 
     private final OperationTracker tracker;
 
-    private final Request request;
-
-    private final SymbolSource symbolSource;
-
-    private final MetaDataLocator metaDataLocator;
-
     private Map<String, String> publishedParameterToEmbeddedId;
 
     private Map<String, EmbeddedComponentAssembler> embeddedIdToAssembler;
 
     public ComponentAssemblerImpl(ComponentAssemblerSource assemblerSource,
                                   ComponentInstantiatorSource instantiatorSource, ComponentClassResolver componentClassResolver,
-                                  Instantiator instantiator, ComponentPageElementResources resources, OperationTracker tracker,
-                                  Request request, SymbolSource symbolSource, MetaDataLocator metaDataLocator)
+                                  Instantiator instantiator, ComponentPageElementResources resources, OperationTracker tracker)
     {
         this.assemblerSource = assemblerSource;
         this.instantiatorSource = instantiatorSource;
@@ -78,9 +68,6 @@ class ComponentAssemblerImpl implements ComponentAssembler
         this.instantiator = instantiator;
         this.resources = resources;
         this.tracker = tracker;
-        this.request = request;
-        this.symbolSource = symbolSource;
-        this.metaDataLocator = metaDataLocator;
     }
 
     public ComponentPageElement assembleRootComponent(final Page page)
@@ -106,8 +93,8 @@ class ComponentAssemblerImpl implements ComponentAssembler
             pageAssembly.componentCount++;
             pageAssembly.weight++;
 
-            ComponentPageElement newElement = new ComponentPageElementImpl(pageAssembly.page, instantiator, resources,
-                    request, symbolSource, metaDataLocator);
+            ComponentPageElement newElement = new ComponentPageElementImpl(pageAssembly.page, instantiator, resources
+            );
 
             pageAssembly.componentName.push(new ComponentName(pageAssembly.page.getName()));
 

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c33c963d/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/PageLoaderImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/PageLoaderImpl.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/PageLoaderImpl.java
index 995f43d..b7a0723 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/PageLoaderImpl.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/PageLoaderImpl.java
@@ -1,4 +1,4 @@
-// Copyright 2009, 2010, 2011, 2012 The Apache Software Foundation
+// Copyright 2009-2014 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.
@@ -32,7 +32,6 @@ import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
 import org.apache.tapestry5.ioc.internal.util.InternalUtils;
 import org.apache.tapestry5.ioc.internal.util.TapestryException;
 import org.apache.tapestry5.ioc.services.PerthreadManager;
-import org.apache.tapestry5.ioc.services.SymbolSource;
 import org.apache.tapestry5.ioc.util.AvailableValues;
 import org.apache.tapestry5.ioc.util.Stack;
 import org.apache.tapestry5.ioc.util.UnknownValueException;
@@ -142,19 +141,17 @@ public class PageLoaderImpl implements PageLoader, ComponentAssemblerSource
 
     private final PerthreadManager perThreadManager;
 
-    private final Request request;
-
-    private final SymbolSource symbolSource;
-
     private final Logger logger;
 
     private final MetaDataLocator metaDataLocator;
 
+    private final RequestGlobals requestGlobals;
+
     public PageLoaderImpl(ComponentInstantiatorSource instantiatorSource, ComponentTemplateSource templateSource,
                           PageElementFactory elementFactory, ComponentPageElementResourcesSource resourcesSource,
                           ComponentClassResolver componentClassResolver, PersistentFieldManager persistentFieldManager,
-                          StringInterner interner, OperationTracker tracker, PerthreadManager perThreadManager, Request request,
-                          SymbolSource symbolSource, Logger logger, MetaDataLocator metaDataLocator)
+                          StringInterner interner, OperationTracker tracker, PerthreadManager perThreadManager,
+                          Logger logger, MetaDataLocator metaDataLocator, RequestGlobals requestGlobals)
     {
         this.instantiatorSource = instantiatorSource;
         this.templateSource = templateSource;
@@ -165,10 +162,9 @@ public class PageLoaderImpl implements PageLoader, ComponentAssemblerSource
         this.interner = interner;
         this.tracker = tracker;
         this.perThreadManager = perThreadManager;
-        this.request = request;
-        this.symbolSource = symbolSource;
         this.logger = logger;
         this.metaDataLocator = metaDataLocator;
+        this.requestGlobals = requestGlobals;
     }
 
     @PostInjection
@@ -196,7 +192,7 @@ public class PageLoaderImpl implements PageLoader, ComponentAssemblerSource
         {
             public Page invoke()
             {
-                Page page = new PageImpl(logicalPageName, selector, persistentFieldManager, perThreadManager);
+                Page page = new PageImpl(logicalPageName, selector, persistentFieldManager, perThreadManager, metaDataLocator);
 
                 ComponentAssembler assembler = getAssembler(pageClassName, selector);
 
@@ -266,7 +262,7 @@ public class PageLoaderImpl implements PageLoader, ComponentAssemblerSource
                 ComponentPageElementResources resources = resourcesSource.get(selector);
 
                 ComponentAssembler assembler = new ComponentAssemblerImpl(PageLoaderImpl.this, instantiatorSource,
-                        componentClassResolver, instantiator, resources, tracker, request, symbolSource, metaDataLocator);
+                        componentClassResolver, instantiator, resources, tracker);
 
                 // "Program" the assembler by adding actions to it. The actions interact with a
                 // PageAssembly object (a fresh one for each new page being created).

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c33c963d/tapestry-core/src/main/java/org/apache/tapestry5/internal/structure/ComponentPageElementImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/structure/ComponentPageElementImpl.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/structure/ComponentPageElementImpl.java
index 73e38c4..b0d6fe6 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/structure/ComponentPageElementImpl.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/structure/ComponentPageElementImpl.java
@@ -1,4 +1,4 @@
-// Copyright 2006, 2007, 2008, 2009, 2010, 2011, 2012 The Apache Software Foundation
+// Copyright 2006-2014  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.
@@ -32,15 +32,12 @@ import org.apache.tapestry5.ioc.internal.util.InternalUtils;
 import org.apache.tapestry5.ioc.internal.util.Orderer;
 import org.apache.tapestry5.ioc.internal.util.TapestryException;
 import org.apache.tapestry5.ioc.services.PerThreadValue;
-import org.apache.tapestry5.ioc.services.SymbolSource;
 import org.apache.tapestry5.ioc.util.AvailableValues;
 import org.apache.tapestry5.ioc.util.UnknownValueException;
 import org.apache.tapestry5.model.ComponentModel;
 import org.apache.tapestry5.model.ParameterModel;
 import org.apache.tapestry5.runtime.Component;
 import org.apache.tapestry5.runtime.*;
-import org.apache.tapestry5.services.MetaDataLocator;
-import org.apache.tapestry5.services.Request;
 import org.apache.tapestry5.services.pageload.ComponentResourceSelector;
 import org.slf4j.Logger;
 
@@ -506,13 +503,6 @@ public class ComponentPageElementImpl extends BaseLocatable implements Component
 
     private final PerThreadValue<Boolean> renderingValue;
 
-    // should be okay since it's a shadow service object
-    private final Request request;
-    private final SymbolSource symbolSource;
-    private final MetaDataLocator metaDataLocator;
-
-    private final boolean productionMode;
-    private final boolean componentTracingEnabled;
     private final boolean exactParameterCountMatch;
 
     // We know that, at the very least, there will be an element to force the component to render
@@ -543,12 +533,10 @@ public class ComponentPageElementImpl extends BaseLocatable implements Component
      * @param location
      *         location of the element (within a template), used as part of exception reporting
      * @param elementResources
-     *         Provides access to common methods of various services
      */
     ComponentPageElementImpl(Page page, ComponentPageElement container, String id, String nestedId, String completeId,
                              String elementName, Instantiator instantiator, Location location,
-                             ComponentPageElementResources elementResources, Request request,
-                             SymbolSource symbolSource, MetaDataLocator metaDataLocator)
+                             ComponentPageElementResources elementResources)
     {
         super(location);
 
@@ -559,17 +547,8 @@ public class ComponentPageElementImpl extends BaseLocatable implements Component
         this.completeId = completeId;
         this.elementName = elementName;
         this.elementResources = elementResources;
-        this.request = request;
-        this.symbolSource = symbolSource;
-        this.metaDataLocator = metaDataLocator;
-
-        // evaluate this once because it gets referenced a lot during rendering
-        this.productionMode = "true".equals(symbolSource.valueForSymbol(SymbolConstants.PRODUCTION_MODE));
-        this.componentTracingEnabled = "true".equals(symbolSource
-                .valueForSymbol(SymbolConstants.COMPONENT_RENDER_TRACING_ENABLED));
 
-        this.exactParameterCountMatch = metaDataLocator.findMeta(MetaDataConstants.UNKNOWN_ACTIVATION_CONTEXT_CHECK,
-                                                                page.getName(), Boolean.class);
+        this.exactParameterCountMatch = page.isExactParameterCountMatch();
 
         ComponentResources containerResources = container == null ? null : container.getComponentResources();
 
@@ -595,11 +574,9 @@ public class ComponentPageElementImpl extends BaseLocatable implements Component
      * Constructor for the root component of a page.
      */
     public ComponentPageElementImpl(Page page, Instantiator instantiator,
-                                    ComponentPageElementResources elementResources, Request request,
-                                    SymbolSource symbolSource, MetaDataLocator metaDataLocator)
+                                    ComponentPageElementResources elementResources)
     {
-        this(page, null, null, null, page.getName(), null, instantiator, null, elementResources,
-                request, symbolSource, metaDataLocator);
+        this(page, null, null, null, page.getName(), null, instantiator, null, elementResources);
     }
 
     private void initializeRenderPhases()
@@ -657,7 +634,7 @@ public class ComponentPageElementImpl extends BaseLocatable implements Component
                                          Instantiator instantiator, Location location)
     {
         ComponentPageElementImpl child = new ComponentPageElementImpl(page, this, id, nestedId, completeId,
-                elementName, instantiator, location, elementResources, request, symbolSource, metaDataLocator);
+                elementName, instantiator, location, elementResources);
 
         addEmbeddedElement(child);
 
@@ -1293,7 +1270,7 @@ public class ComponentPageElementImpl extends BaseLocatable implements Component
 
     boolean isRenderTracingEnabled()
     {
-        return !productionMode && (componentTracingEnabled || "true".equals(request.getParameter("t:component-trace")));
+        return elementResources.isRenderTracingEnabled();
     }
 
     public ComponentResourceSelector getResourceSelector()

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c33c963d/tapestry-core/src/main/java/org/apache/tapestry5/internal/structure/ComponentPageElementResources.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/structure/ComponentPageElementResources.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/structure/ComponentPageElementResources.java
index 5d644e4..6a32e86 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/structure/ComponentPageElementResources.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/structure/ComponentPageElementResources.java
@@ -1,4 +1,4 @@
-// Copyright 2008, 2010, 2011 The Apache Software Foundation
+// Copyright 2008-2014 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.
@@ -33,7 +33,7 @@ public interface ComponentPageElementResources extends ContextValueEncoder, Oper
 {
     /**
      * Returns the selector associated with this resources.
-     * 
+     *
      * @since 5.3
      */
     ComponentResourceSelector getSelector();
@@ -42,7 +42,7 @@ public interface ComponentPageElementResources extends ContextValueEncoder, Oper
      * Used to obtain a {@link org.apache.tapestry5.ioc.Messages} instance for a particular component. If the component
      * extends from another component, then its localized properties will merge with its parent's properties (with the
      * subclass overriding the super class on any conflicts).
-     * 
+     *
      * @param componentModel
      * @return the message catalog for the component, in the indicated locale
      * @see org.apache.tapestry5.services.messages.ComponentMessagesSource
@@ -54,14 +54,14 @@ public interface ComponentPageElementResources extends ContextValueEncoder, Oper
      * conversion will be to the equivalent wrapper type. In some cases, the TypeCoercer will need to search for an
      * appropriate coercion, and may even combine existing coercions to form new ones; in those cases, the results of
      * the search are cached.
-     * 
+     *
      * @param <S>
-     *            source type (input)
+     *         source type (input)
      * @param <T>
-     *            target type (output)
+     *         target type (output)
      * @param input
      * @param targetType
-     *            defines the target type
+     *         defines the target type
      * @return the coerced value
      * @see org.apache.tapestry5.ioc.services.TypeCoercer
      */
@@ -69,9 +69,9 @@ public interface ComponentPageElementResources extends ContextValueEncoder, Oper
 
     /**
      * Gets the Class instance for then give name.
-     * 
+     *
      * @param className
-     *            fully qualified class name
+     *         fully qualified class name
      * @return the class instance
      * @see org.apache.tapestry5.internal.services.ComponentClassCache
      */
@@ -79,15 +79,15 @@ public interface ComponentPageElementResources extends ContextValueEncoder, Oper
 
     /**
      * Creates a link on behalf of a component.
-     * 
+     *
      * @param resources
-     *            resources for the component
+     *         resources for the component
      * @param eventType
-     *            type of event to create
+     *         type of event to create
      * @param forForm
-     *            true if generating for a form submission
+     *         true if generating for a form submission
      * @param context
-     *            additional event context associated with the link
+     *         additional event context associated with the link
      * @return the link
      * @since 5.1.0.0
      */
@@ -95,15 +95,15 @@ public interface ComponentPageElementResources extends ContextValueEncoder, Oper
 
     /**
      * Creates a page render request link to render a specific page.
-     * 
+     *
      * @param pageName
-     *            the logical name of the page to link to
+     *         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)
+     *         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 page
+     *         the activation context for the page. If omitted, the activation context is obtained from the
+     *         target page
      * @return link for a render request to the targetted page
      * @since 5.1.0.0
      */
@@ -112,15 +112,15 @@ public interface ComponentPageElementResources extends ContextValueEncoder, Oper
     /**
      * Creates a page render request link to render a specific page. Using a page class, rather than a page name, is
      * more refactoring safe (in the even the page is renamed or moved).
-     * 
+     *
      * @param pageClass
-     *            identifies the page to link to
+     *         identifies 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)
+     *         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 page
+     *         the activation context for the page. If omitted, the activation context is obtained from the
+     *         target page
      * @return link for a render request to the targetted page
      * @since 5.1
      */
@@ -129,17 +129,25 @@ public interface ComponentPageElementResources extends ContextValueEncoder, Oper
     /**
      * Returns the event logger for the provided component logger. The event logger is based on the component logger's
      * name (which matches the component class name) with a "tapestry..events." prefix.
-     * 
+     *
      * @param componentLogger
-     *            provides base name for logger
+     *         provides base name for logger
      * @return the logger
      */
     Logger getEventLogger(Logger componentLogger);
 
     /**
      * Wrapper around {@link PerthreadManager#createValue()}.
-     * 
+     *
      * @since 5.2.0
      */
     <T> PerThreadValue<T> createPerThreadValue();
+
+    /**
+     * Returns true if component element tracing is enabled. When enabled, rendering of the component produces
+     * additional comments to identify what component and stage is rendering.
+     *
+     * @since 5.4
+     */
+    boolean isRenderTracingEnabled();
 }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c33c963d/tapestry-core/src/main/java/org/apache/tapestry5/internal/structure/ComponentPageElementResourcesImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/structure/ComponentPageElementResourcesImpl.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/structure/ComponentPageElementResourcesImpl.java
index 58adf4f..6c180b9 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/structure/ComponentPageElementResourcesImpl.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/structure/ComponentPageElementResourcesImpl.java
@@ -1,4 +1,4 @@
-// Copyright 2008-2013 The Apache Software Foundation
+// Copyright 2008-2014 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.
@@ -27,6 +27,8 @@ import org.apache.tapestry5.ioc.services.TypeCoercer;
 import org.apache.tapestry5.model.ComponentModel;
 import org.apache.tapestry5.services.ComponentClassResolver;
 import org.apache.tapestry5.services.ContextValueEncoder;
+import org.apache.tapestry5.services.Request;
+import org.apache.tapestry5.services.RequestGlobals;
 import org.apache.tapestry5.services.messages.ComponentMessagesSource;
 import org.apache.tapestry5.services.pageload.ComponentResourceSelector;
 import org.slf4j.Logger;
@@ -57,11 +59,15 @@ public class ComponentPageElementResourcesImpl implements ComponentPageElementRe
 
     private final PerthreadManager perThreadManager;
 
+    private final boolean productionMode, componentTracingEnabled;
+
+    private final RequestGlobals requestGlobals;
+
     public ComponentPageElementResourcesImpl(ComponentResourceSelector selector,
                                              ComponentMessagesSource componentMessagesSource, TypeCoercer typeCoercer,
                                              ComponentClassCache componentClassCache, ContextValueEncoder contextValueEncoder, LinkSource linkSource,
                                              RequestPageCache requestPageCache, ComponentClassResolver componentClassResolver,
-                                             LoggerSource loggerSource, OperationTracker tracker, PerthreadManager perThreadManager)
+                                             LoggerSource loggerSource, OperationTracker tracker, PerthreadManager perThreadManager, boolean productionMode, boolean componentTracingEnabled, RequestGlobals requestGlobals)
     {
         this.selector = selector;
         this.componentMessagesSource = componentMessagesSource;
@@ -74,6 +80,9 @@ public class ComponentPageElementResourcesImpl implements ComponentPageElementRe
         this.loggerSource = loggerSource;
         this.tracker = tracker;
         this.perThreadManager = perThreadManager;
+        this.productionMode = productionMode;
+        this.componentTracingEnabled = componentTracingEnabled;
+        this.requestGlobals = requestGlobals;
     }
 
     public ComponentResourceSelector getSelector()
@@ -160,4 +169,26 @@ public class ComponentPageElementResourcesImpl implements ComponentPageElementRe
         return perThreadManager.createValue();
     }
 
+    public boolean isRenderTracingEnabled()
+    {
+        if (productionMode)
+        {
+            return false;
+        }
+
+        if (componentTracingEnabled)
+        {
+            return true;
+        }
+
+        Request request = requestGlobals.getRequest();
+
+        if (request == null)
+        {
+            return false;
+        }
+
+        return "true".equals(request.getParameter("t:component-trace"));
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c33c963d/tapestry-core/src/main/java/org/apache/tapestry5/internal/structure/ComponentPageElementResourcesSourceImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/structure/ComponentPageElementResourcesSourceImpl.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/structure/ComponentPageElementResourcesSourceImpl.java
index 4dc478e..f4ee38b 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/structure/ComponentPageElementResourcesSourceImpl.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/structure/ComponentPageElementResourcesSourceImpl.java
@@ -1,4 +1,4 @@
-// Copyright 2008, 2009, 2010 The Apache Software Foundation
+// Copyright 2008-2014 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.
@@ -14,21 +14,24 @@
 
 package org.apache.tapestry5.internal.structure;
 
-import java.util.Map;
-
+import org.apache.tapestry5.SymbolConstants;
 import org.apache.tapestry5.internal.services.ComponentClassCache;
 import org.apache.tapestry5.internal.services.LinkSource;
 import org.apache.tapestry5.internal.services.RequestPageCache;
 import org.apache.tapestry5.ioc.LoggerSource;
 import org.apache.tapestry5.ioc.OperationTracker;
+import org.apache.tapestry5.ioc.annotations.Symbol;
 import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
 import org.apache.tapestry5.ioc.services.PerthreadManager;
 import org.apache.tapestry5.ioc.services.TypeCoercer;
 import org.apache.tapestry5.services.ComponentClassResolver;
 import org.apache.tapestry5.services.ContextValueEncoder;
+import org.apache.tapestry5.services.RequestGlobals;
 import org.apache.tapestry5.services.messages.ComponentMessagesSource;
 import org.apache.tapestry5.services.pageload.ComponentResourceSelector;
 
+import java.util.Map;
+
 public class ComponentPageElementResourcesSourceImpl implements ComponentPageElementResourcesSource
 {
     private final Map<ComponentResourceSelector, ComponentPageElementResources> cache = CollectionFactory
@@ -54,10 +57,17 @@ public class ComponentPageElementResourcesSourceImpl implements ComponentPageEle
 
     private final PerthreadManager perThreadManager;
 
+    private final boolean productionMode, componentTracingEnabled;
+
+    private final RequestGlobals requestGlobals;
+
     public ComponentPageElementResourcesSourceImpl(ComponentMessagesSource componentMessagesSource,
             TypeCoercer typeCoercer, ComponentClassCache componentClassCache, ContextValueEncoder contextValueEncoder,
             LinkSource linkSource, RequestPageCache requestPageCache, ComponentClassResolver componentClassResolver,
-            LoggerSource loggerSource, OperationTracker tracker, PerthreadManager perThreadManager)
+            LoggerSource loggerSource, OperationTracker tracker, PerthreadManager perThreadManager,
+            @Symbol(SymbolConstants.PRODUCTION_MODE) boolean productionMode,
+            @Symbol(SymbolConstants.COMPONENT_RENDER_TRACING_ENABLED) boolean componentTracingEnabled,
+            RequestGlobals requestGlobals)
     {
         this.componentMessagesSource = componentMessagesSource;
         this.typeCoercer = typeCoercer;
@@ -69,6 +79,9 @@ public class ComponentPageElementResourcesSourceImpl implements ComponentPageEle
         this.loggerSource = loggerSource;
         this.tracker = tracker;
         this.perThreadManager = perThreadManager;
+        this.productionMode = productionMode;
+        this.componentTracingEnabled = componentTracingEnabled;
+        this.requestGlobals = requestGlobals;
     }
 
     public ComponentPageElementResources get(ComponentResourceSelector selector)
@@ -81,7 +94,7 @@ public class ComponentPageElementResourcesSourceImpl implements ComponentPageEle
         {
             result = new ComponentPageElementResourcesImpl(selector, componentMessagesSource, typeCoercer,
                     componentClassCache, contextValueEncoder, linkSource, requestPageCache, componentClassResolver,
-                    loggerSource, tracker, perThreadManager);
+                    loggerSource, tracker, perThreadManager, productionMode, componentTracingEnabled, requestGlobals);
 
             // Small race condition here, where we may create two instances of the CPER for the same locale,
             // but that's not worth worrying about.

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c33c963d/tapestry-core/src/main/java/org/apache/tapestry5/internal/structure/Page.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/structure/Page.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/structure/Page.java
index c483849..9c8dd13 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/structure/Page.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/structure/Page.java
@@ -1,4 +1,4 @@
-// Copyright 2006, 2007, 2008, 2009, 2010, 2011, 2012 The Apache Software Foundation
+// Copyright 2006-2014 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.
@@ -145,7 +145,7 @@ public interface Page extends PageLifecycleCallbackHub
      * Adds a listener that is notified of large scale page events.
      *
      * @deprecated in 5.3.4; use {@link #addPageLoadedCallback(Runnable)}, {@link #addPageAttachedCallback(Runnable)}, or
-     *             {@link #addPageDetachedCallback(Runnable)}  instead
+     * {@link #addPageDetachedCallback(Runnable)}  instead
      */
     void addLifecycleListener(PageLifecycleListener listener);
 
@@ -250,5 +250,13 @@ public interface Page extends PageLifecycleCallbackHub
      */
     int getAttachCount();
 
+    /**
+     * Returns true if extract parameter count matching is enabled.
+     *
+     * @see org.apache.tapestry5.MetaDataConstants#UNKNOWN_ACTIVATION_CONTEXT_CHECK
+     * @since 5.4
+     */
+    boolean isExactParameterCountMatch();
+
 
 }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c33c963d/tapestry-core/src/main/java/org/apache/tapestry5/internal/structure/PageImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/structure/PageImpl.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/structure/PageImpl.java
index ced81a7..a967049 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/structure/PageImpl.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/structure/PageImpl.java
@@ -1,4 +1,4 @@
-// Copyright 2006-2013 The Apache Software Foundation
+// Copyright 2006-2014 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,6 +15,7 @@
 package org.apache.tapestry5.internal.structure;
 
 import org.apache.tapestry5.ComponentResources;
+import org.apache.tapestry5.MetaDataConstants;
 import org.apache.tapestry5.internal.services.PersistentFieldManager;
 import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
 import org.apache.tapestry5.ioc.internal.util.OneShotLock;
@@ -23,6 +24,7 @@ import org.apache.tapestry5.ioc.services.PerthreadManager;
 import org.apache.tapestry5.ioc.util.ExceptionUtils;
 import org.apache.tapestry5.runtime.Component;
 import org.apache.tapestry5.runtime.PageLifecycleListener;
+import org.apache.tapestry5.services.MetaDataLocator;
 import org.apache.tapestry5.services.PersistentFieldBundle;
 import org.apache.tapestry5.services.pageload.ComponentResourceSelector;
 import org.slf4j.Logger;
@@ -64,6 +66,8 @@ public class PageImpl implements Page
 
     private final AtomicInteger attachCount = new AtomicInteger();
 
+    private final boolean exactParameterCountMatch;
+
     private List<Runnable> pageVerifyCallbacks = CollectionFactory.newList();
 
     /**
@@ -83,16 +87,18 @@ public class PageImpl implements Page
      * @param persistentFieldManager
      *         for access to cross-request persistent values
      * @param perThreadManager
-     *         for managing per-request mutable state
+     * @param metaDataLocator
      */
     public PageImpl(String name, ComponentResourceSelector selector, PersistentFieldManager persistentFieldManager,
-                    PerthreadManager perThreadManager)
+                    PerthreadManager perThreadManager, MetaDataLocator metaDataLocator)
     {
         this.name = name;
         this.selector = selector;
         this.persistentFieldManager = persistentFieldManager;
 
         fieldBundle = perThreadManager.createValue();
+
+        exactParameterCountMatch = metaDataLocator.findMeta(MetaDataConstants.UNKNOWN_ACTIVATION_CONTEXT_CHECK, name, Boolean.class);
     }
 
     public void setStats(Stats stats)
@@ -320,6 +326,11 @@ public class PageImpl implements Page
         return attachCount.get();
     }
 
+    public boolean isExactParameterCountMatch()
+    {
+        return exactParameterCountMatch;
+    }
+
     public void addPageLoadedCallback(Runnable callback)
     {
         lifecycleListenersLock.check();

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c33c963d/tapestry-core/src/test/groovy/org/apache/tapestry5/internal/structure/ComponentPageElementResourcesImplTest.groovy
----------------------------------------------------------------------
diff --git a/tapestry-core/src/test/groovy/org/apache/tapestry5/internal/structure/ComponentPageElementResourcesImplTest.groovy b/tapestry-core/src/test/groovy/org/apache/tapestry5/internal/structure/ComponentPageElementResourcesImplTest.groovy
new file mode 100644
index 0000000..5acf1e6
--- /dev/null
+++ b/tapestry-core/src/test/groovy/org/apache/tapestry5/internal/structure/ComponentPageElementResourcesImplTest.groovy
@@ -0,0 +1,67 @@
+package org.apache.tapestry5.internal.structure
+
+import org.apache.tapestry5.internal.services.RequestGlobalsImpl
+import org.apache.tapestry5.ioc.test.TestBase
+import org.apache.tapestry5.services.Request
+import org.testng.annotations.Test
+
+class ComponentPageElementResourcesImplTest extends TestBase {
+
+    def create(productionMode, tracing, request) {
+        RequestGlobalsImpl rg = new RequestGlobalsImpl()
+
+        rg.storeRequestResponse(request, null)
+
+        new ComponentPageElementResourcesImpl(null, null, null, null, null, null, null, null, null, null, null, productionMode, tracing, rg)
+    }
+
+    @Test
+    void production_mode_prevents_render_tracing() {
+        def r = create true, true, null
+
+        assertFalse r.renderTracingEnabled
+    }
+
+    @Test
+    void request_not_checked_if_tracing_enabled() {
+        def r = create false, true, null
+
+        assertTrue r.renderTracingEnabled
+    }
+
+    @Test
+    void tracing_enabled_by_request_parameter() {
+
+        def request = newMock Request
+        def r = create false, false, request
+
+        expect(request.getParameter("t:component-trace")).andReturn("true")
+
+        replay()
+
+        assertTrue r.renderTracingEnabled
+
+        verify()
+    }
+
+    @Test
+    void tracing_not_enabled_by_request_parameter() {
+        def request = newMock Request
+        def r = create false, false, request
+
+        expect(request.getParameter("t:component-trace")).andReturn(null)
+
+        replay()
+
+        assertFalse r.renderTracingEnabled
+
+        verify()
+    }
+
+    @Test
+    void tracing_not_enabled_if_no_request() {
+        def r = create false, false, null
+
+        assertFalse r.renderTracingEnabled
+    }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c33c963d/tapestry-core/src/test/java/org/apache/tapestry5/internal/structure/ComponentPageElementImplTest.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/test/java/org/apache/tapestry5/internal/structure/ComponentPageElementImplTest.java b/tapestry-core/src/test/java/org/apache/tapestry5/internal/structure/ComponentPageElementImplTest.java
deleted file mode 100644
index cfd1494..0000000
--- a/tapestry-core/src/test/java/org/apache/tapestry5/internal/structure/ComponentPageElementImplTest.java
+++ /dev/null
@@ -1,72 +0,0 @@
-package org.apache.tapestry5.internal.structure;
-
-import static org.apache.tapestry5.SymbolConstants.COMPONENT_RENDER_TRACING_ENABLED;
-import static org.apache.tapestry5.SymbolConstants.PRODUCTION_MODE;
-
-import org.apache.tapestry5.MetaDataConstants;
-import org.apache.tapestry5.internal.services.Instantiator;
-import org.apache.tapestry5.ioc.Location;
-import org.apache.tapestry5.ioc.services.SymbolSource;
-import org.apache.tapestry5.ioc.test.TestBase;
-import org.apache.tapestry5.model.ComponentModel;
-import org.apache.tapestry5.services.MetaDataLocator;
-import org.apache.tapestry5.services.Request;
-import org.testng.annotations.Test;
-
-public class ComponentPageElementImplTest extends TestBase {
-    /** TAP5-742 */
-    @Test public void component_render_tracing() {
-        Request request = newMock(Request.class);
-        SymbolSource symbolSource = newMock(SymbolSource.class);
-        
-        Page page = getMocksControl().createMock(Page.class);
-        Instantiator instantiator = newMock(Instantiator.class);
-        Location location = newMock(Location.class);
-        ComponentPageElementResources elementResources = newMock(ComponentPageElementResources.class);
-        ComponentModel model = newMock(ComponentModel.class);
-        MetaDataLocator locator = newMock(MetaDataLocator.class);
-        
-        getMocksControl().resetToNice();
-
-        expect(instantiator.getModel()).andReturn(model).anyTimes();
-
-        // off by default
-        expect(symbolSource.valueForSymbol(PRODUCTION_MODE)).andReturn("false");
-        expect(symbolSource.valueForSymbol(COMPONENT_RENDER_TRACING_ENABLED)).andReturn("false");
-        expect(request.getParameter("t:component-trace")).andReturn("false");
-        
-        // enable by query parameter
-        expect(symbolSource.valueForSymbol(PRODUCTION_MODE)).andReturn("false");
-        expect(symbolSource.valueForSymbol(COMPONENT_RENDER_TRACING_ENABLED)).andReturn("false");
-        expect(request.getParameter("t:component-trace")).andReturn("true");
-        
-        // enable by symbol
-        expect(symbolSource.valueForSymbol(PRODUCTION_MODE)).andReturn("false");
-        expect(symbolSource.valueForSymbol(COMPONENT_RENDER_TRACING_ENABLED)).andReturn("true");
-        expect(request.getParameter("t:component-trace")).andReturn("false");
-        
-        // off no matter what in production mode
-        expect(symbolSource.valueForSymbol(PRODUCTION_MODE)).andReturn("true");
-        expect(symbolSource.valueForSymbol(COMPONENT_RENDER_TRACING_ENABLED)).andReturn("true");
-        expect(request.getParameter("t:component-trace")).andReturn("false");
-
-        expect(page.getName()).andReturn("pageName").anyTimes();
-        expect(locator.findMeta(MetaDataConstants.UNKNOWN_ACTIVATION_CONTEXT_CHECK, "pageName", Boolean.class))
-                .andReturn(false).anyTimes();
-
-        replay();
-        ComponentPageElementImpl c;    // need to create every time because of changing symbols
-        
-        c = new ComponentPageElementImpl(page, null, "id", "nestedId", "completeid", "elementname", instantiator, location, elementResources, request, symbolSource, locator);
-        assertFalse(c.isRenderTracingEnabled());
-        
-        c = new ComponentPageElementImpl(page, null, "id", "nestedId", "completeid", "elementname", instantiator, location, elementResources, request, symbolSource, locator);
-        assertTrue(c.isRenderTracingEnabled());
-
-        c = new ComponentPageElementImpl(page, null, "id", "nestedId", "completeid", "elementname", instantiator, location, elementResources, request, symbolSource, locator);
-        assertTrue(c.isRenderTracingEnabled());
-
-        c = new ComponentPageElementImpl(page, null, "id", "nestedId", "completeid", "elementname", instantiator, location, elementResources, request, symbolSource, locator);
-        assertFalse(c.isRenderTracingEnabled());
-    }
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c33c963d/tapestry-core/src/test/java/org/apache/tapestry5/internal/structure/InternalComponentResourcesImplTest.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/test/java/org/apache/tapestry5/internal/structure/InternalComponentResourcesImplTest.java b/tapestry-core/src/test/java/org/apache/tapestry5/internal/structure/InternalComponentResourcesImplTest.java
index dc97cbe..8d84df4 100644
--- a/tapestry-core/src/test/java/org/apache/tapestry5/internal/structure/InternalComponentResourcesImplTest.java
+++ b/tapestry-core/src/test/java/org/apache/tapestry5/internal/structure/InternalComponentResourcesImplTest.java
@@ -1,4 +1,4 @@
-// Copyright 2006, 2007, 2008, 2010, 2011 The Apache Software Foundation
+// Copyright 2006-2014 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.
@@ -44,7 +44,7 @@ public class InternalComponentResourcesImplTest extends InternalBaseTestCase
         TypeCoercer typeCoercer = getService(TypeCoercer.class);
 
         elementResources = new ComponentPageElementResourcesImpl(null, null, typeCoercer, null, null, null, null, null,
-                null, null, perThreadManager);
+                null, null, perThreadManager, false, false, null);
     }
 
     @AfterMethod

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c33c963d/tapestry-core/src/test/java/org/apache/tapestry5/internal/structure/PageImplTest.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/test/java/org/apache/tapestry5/internal/structure/PageImplTest.java b/tapestry-core/src/test/java/org/apache/tapestry5/internal/structure/PageImplTest.java
index 5cc9f9d..d8c01e6 100644
--- a/tapestry-core/src/test/java/org/apache/tapestry5/internal/structure/PageImplTest.java
+++ b/tapestry-core/src/test/java/org/apache/tapestry5/internal/structure/PageImplTest.java
@@ -1,4 +1,4 @@
-// Copyright 2006, 2007, 2008, 2009, 2010, 2011, 2012 The Apache Software Foundation
+// Copyright 2006-2014 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.
@@ -14,9 +14,11 @@
 
 package org.apache.tapestry5.internal.structure;
 
+import org.apache.tapestry5.MetaDataConstants;
 import org.apache.tapestry5.internal.test.InternalBaseTestCase;
 import org.apache.tapestry5.ioc.services.PerthreadManager;
 import org.apache.tapestry5.runtime.PageLifecycleListener;
+import org.apache.tapestry5.services.MetaDataLocator;
 import org.apache.tapestry5.services.pageload.ComponentResourceSelector;
 import org.slf4j.Logger;
 import org.testng.annotations.AfterMethod;
@@ -48,15 +50,26 @@ public class PageImplTest extends InternalBaseTestCase
         perThreadManager.cleanup();
     }
 
+    private MetaDataLocator newMetaDataLocator(String pageName, boolean enabled)
+    {
+
+        MetaDataLocator locator = newMock(MetaDataLocator.class);
+
+        expect(locator.findMeta(MetaDataConstants.UNKNOWN_ACTIVATION_CONTEXT_CHECK, pageName, Boolean.class)).andReturn(enabled);
+
+        return locator;
+    }
+
     @Test
     public void accessor_methods()
     {
         ComponentPageElement root = mockComponentPageElement();
         ComponentResourceSelector selector = new ComponentResourceSelector(Locale.ENGLISH);
+        MetaDataLocator locator = newMetaDataLocator(LOGICAL_PAGE_NAME, true);
 
         replay();
 
-        Page page = new PageImpl(LOGICAL_PAGE_NAME, selector, null, perThreadManager);
+        Page page = new PageImpl(LOGICAL_PAGE_NAME, selector, null, perThreadManager, locator);
 
         assertNull(page.getRootElement());
 
@@ -66,6 +79,8 @@ public class PageImplTest extends InternalBaseTestCase
         assertSame(page.getRootElement(), root);
         assertSame(page.getName(), LOGICAL_PAGE_NAME);
 
+        assertTrue(page.isExactParameterCountMatch());
+
         verify();
     }
 
@@ -78,9 +93,11 @@ public class PageImplTest extends InternalBaseTestCase
         listener1.containingPageDidDetach();
         listener2.containingPageDidDetach();
 
+        MetaDataLocator locator = newMetaDataLocator(LOGICAL_PAGE_NAME, true);
+
         replay();
 
-        Page page = new PageImpl(null, selector, null, perThreadManager);
+        Page page = new PageImpl(LOGICAL_PAGE_NAME, selector, null, perThreadManager, locator);
 
         page.addLifecycleListener(listener1);
         page.addLifecycleListener(listener2);
@@ -101,6 +118,7 @@ public class PageImplTest extends InternalBaseTestCase
         PageLifecycleListener listener1 = newPageLifecycle();
         PageLifecycleListener listener2 = newPageLifecycle();
         RuntimeException t = new RuntimeException("Listener detach exception.");
+        MetaDataLocator locator = newMetaDataLocator(LOGICAL_PAGE_NAME, true);
 
         train_getLogger(element, logger);
 
@@ -113,7 +131,7 @@ public class PageImplTest extends InternalBaseTestCase
 
         replay();
 
-        Page page = new PageImpl(null, selector, null, perThreadManager);
+        Page page = new PageImpl(LOGICAL_PAGE_NAME, selector, null, perThreadManager, locator);
         page.setRootElement(element);
 
         page.addLifecycleListener(listener1);
@@ -132,6 +150,8 @@ public class PageImplTest extends InternalBaseTestCase
     @Test
     public void attach_notification()
     {
+        MetaDataLocator locator = newMetaDataLocator(LOGICAL_PAGE_NAME, true);
+
         PageLifecycleListener listener1 = newPageLifecycle();
         PageLifecycleListener listener2 = newPageLifecycle();
 
@@ -140,7 +160,7 @@ public class PageImplTest extends InternalBaseTestCase
 
         replay();
 
-        Page page = new PageImpl(null, selector, null, perThreadManager);
+        Page page = new PageImpl(LOGICAL_PAGE_NAME, selector, null, perThreadManager, locator);
 
         page.addLifecycleListener(listener1);
         page.addLifecycleListener(listener2);
@@ -158,6 +178,8 @@ public class PageImplTest extends InternalBaseTestCase
     @Test
     public void load_notification()
     {
+        MetaDataLocator locator = newMetaDataLocator(LOGICAL_PAGE_NAME, true);
+
         PageLifecycleListener listener1 = newPageLifecycle();
         PageLifecycleListener listener2 = newPageLifecycle();
 
@@ -166,7 +188,7 @@ public class PageImplTest extends InternalBaseTestCase
 
         replay();
 
-        Page page = new PageImpl(LOGICAL_PAGE_NAME, selector, null, perThreadManager);
+        Page page = new PageImpl(LOGICAL_PAGE_NAME, selector, null, perThreadManager, locator);
 
         page.addLifecycleListener(listener1);
         page.addLifecycleListener(listener2);
@@ -180,10 +202,11 @@ public class PageImplTest extends InternalBaseTestCase
     public void get_by_nested_id_for_blank_value_returns_root_component()
     {
         ComponentPageElement root = mockComponentPageElement();
+        MetaDataLocator locator = newMetaDataLocator(LOGICAL_PAGE_NAME, true);
 
         replay();
 
-        Page page = new PageImpl(LOGICAL_PAGE_NAME, selector, null, perThreadManager);
+        Page page = new PageImpl(LOGICAL_PAGE_NAME, selector, null, perThreadManager, locator);
 
         page.setRootElement(root);