Coverage Report - org.apache.tapestry.pageload.PageLoader
 
Classes in this File Line Coverage Branch Coverage Complexity
PageLoader
0%
0/203
0%
0/64
2.393
 
 1  
 // Copyright 2004, 2005 The Apache Software Foundation
 2  
 //
 3  
 // Licensed under the Apache License, Version 2.0 (the "License");
 4  
 // you may not use this file except in compliance with the License.
 5  
 // You may obtain a copy of the License at
 6  
 //
 7  
 //     http://www.apache.org/licenses/LICENSE-2.0
 8  
 //
 9  
 // Unless required by applicable law or agreed to in writing, software
 10  
 // distributed under the License is distributed on an "AS IS" BASIS,
 11  
 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 12  
 // See the License for the specific language governing permissions and
 13  
 // limitations under the License.
 14  
 
 15  
 package org.apache.tapestry.pageload;
 16  
 
 17  
 import org.apache.commons.logging.Log;
 18  
 import org.apache.hivemind.ApplicationRuntimeException;
 19  
 import org.apache.hivemind.ClassResolver;
 20  
 import org.apache.hivemind.HiveMind;
 21  
 import org.apache.hivemind.Location;
 22  
 import org.apache.hivemind.service.ThreadLocale;
 23  
 import org.apache.tapestry.*;
 24  
 import org.apache.tapestry.asset.AssetSource;
 25  
 import org.apache.tapestry.binding.BindingSource;
 26  
 import org.apache.tapestry.engine.IPageLoader;
 27  
 import org.apache.tapestry.resolver.ComponentSpecificationResolver;
 28  
 import org.apache.tapestry.services.ComponentConstructor;
 29  
 import org.apache.tapestry.services.ComponentConstructorFactory;
 30  
 import org.apache.tapestry.services.ComponentPropertySource;
 31  
 import org.apache.tapestry.services.ComponentTemplateLoader;
 32  
 import org.apache.tapestry.spec.*;
 33  
 
 34  
 import java.util.*;
 35  
 
 36  
 /**
 37  
  * Implementation of tapestry.page.PageLoader. Runs the process of building the
 38  
  * component hierarchy for an entire page.
 39  
  * <p>
 40  
  * This implementation is not threadsafe, therefore the pooled service model
 41  
  * must be used.
 42  
  * </p>
 43  
  *
 44  
  * @author Howard Lewis Ship
 45  
  */
 46  
 
 47  0
 public class PageLoader implements IPageLoader {
 48  
 
 49  
     private Log _log;
 50  
 
 51  
     /** @since 4.0 */
 52  
 
 53  
     private ComponentSpecificationResolver _componentResolver;
 54  
 
 55  
     /** @since 4.0 */
 56  
 
 57  
     private BindingSource _bindingSource;
 58  
 
 59  
     /** @since 4.0 */
 60  
 
 61  
     private ComponentTemplateLoader _componentTemplateLoader;
 62  
 
 63  0
     private List _inheritedBindingQueue = new ArrayList();
 64  
 
 65  
     /** @since 4.0 */
 66  
     private IComponentVisitor _establishDefaultParameterValuesVisitor;
 67  
 
 68  
     private ComponentTreeWalker _establishDefaultParameterValuesWalker;
 69  
 
 70  
     private ComponentTreeWalker _verifyRequiredParametersWalker;
 71  
 
 72  
     private IComponentVisitor _eventConnectionVisitor;
 73  
 
 74  
     private ComponentTreeWalker _eventConnectionWalker;
 75  
 
 76  
     private IComponentVisitor _componentTypeVisitor;
 77  
 
 78  
     /** @since 4.0 */
 79  
 
 80  
     private ComponentConstructorFactory _componentConstructorFactory;
 81  
 
 82  
     /** @since 4.0 */
 83  
 
 84  
     private AssetSource _assetSource;
 85  
 
 86  
     /**
 87  
      * Used to find the correct Java component class for a page.
 88  
      *
 89  
      * @since 4.0
 90  
      */
 91  
 
 92  
     private ComponentClassProvider _pageClassProvider;
 93  
 
 94  
     /**
 95  
      * Used to find the correct Java component class for a component (a similar
 96  
      * process to resolving a page, but with slightly differen steps and
 97  
      * defaults).
 98  
      *
 99  
      * @since 4.0
 100  
      */
 101  
 
 102  
     private ComponentClassProvider _componentClassProvider;
 103  
 
 104  
     /**
 105  
      * Used to resolve meta-data properties related to a component.
 106  
      *
 107  
      * @since 4.0
 108  
      */
 109  
 
 110  
     private ComponentPropertySource _componentPropertySource;
 111  
 
 112  
     /**
 113  
      * Tracks the current locale into which pages are loaded.
 114  
      *
 115  
      * @since 4.0
 116  
      */
 117  
 
 118  
     private ThreadLocale _threadLocale;
 119  
 
 120  
     /**
 121  
      * The locale of the application, which is also the locale of the page being
 122  
      * loaded.
 123  
      */
 124  
 
 125  
     private Locale _locale;
 126  
 
 127  
     /**
 128  
      * Number of components instantiated, excluding the page itself.
 129  
      */
 130  
 
 131  
     private int _count;
 132  
 
 133  
     /**
 134  
      * The recursion depth. A page with no components is zero. A component on a
 135  
      * page is one.
 136  
      */
 137  
 
 138  
     private int _depth;
 139  
 
 140  
     /**
 141  
      * The maximum depth reached while building the page.
 142  
      */
 143  
 
 144  
     private int _maxDepth;
 145  
 
 146  
     /** @since 4.0 */
 147  
 
 148  
     private ClassResolver _classResolver;
 149  
 
 150  
     /**
 151  
      * As each component is constructed it is placed on to the component stack,  when construction is finished it is pushed
 152  
      * back off the stack.  This helps in detecting component nesting and properly reporting errors.
 153  
      */
 154  0
     private Stack _componentStack = new Stack();
 155  
 
 156  
     public void initializeService()
 157  
     {
 158  
 
 159  
         // Create the mechanisms for walking the component tree when it is
 160  
         // complete
 161  0
         IComponentVisitor verifyRequiredParametersVisitor = new VerifyRequiredParametersVisitor();
 162  
 
 163  0
         _verifyRequiredParametersWalker =
 164  
           new ComponentTreeWalker( new IComponentVisitor[] { verifyRequiredParametersVisitor });
 165  
 
 166  0
         _establishDefaultParameterValuesWalker =
 167  
           new ComponentTreeWalker( new IComponentVisitor[] { _establishDefaultParameterValuesVisitor });
 168  
 
 169  0
         _eventConnectionWalker =
 170  
           new ComponentTreeWalker( new IComponentVisitor[] { _eventConnectionVisitor, _componentTypeVisitor });
 171  0
     }
 172  
 
 173  
     /**
 174  
      * Binds properties of the component as defined by the container's
 175  
      * specification.
 176  
      * <p>
 177  
      * This implementation is very simple, we will need a lot more sanity
 178  
      * checking and eror checking in the final version.
 179  
      *
 180  
      * @param container
 181  
      *            The containing component. For a dynamic binding ({@link org.apache.tapestry.binding.ExpressionBinding})
 182  
      *            the property name is evaluated with the container as the root.
 183  
      * @param component
 184  
      *            The contained component being bound.
 185  
      * @param contained
 186  
      *            The contained component specification (from the container's
 187  
      *            {@link IComponentSpecification}).
 188  
      * @param defaultBindingPrefix
 189  
      *            The default binding prefix to be used with the component.
 190  
      */
 191  
 
 192  
     void bind(IComponent container, IComponent component,
 193  
               IContainedComponent contained, String defaultBindingPrefix)
 194  
     {
 195  0
         IComponentSpecification spec = component.getSpecification();
 196  0
         boolean formalOnly = !spec.getAllowInformalParameters();
 197  
 
 198  0
         if (contained.getInheritInformalParameters())
 199  
         {
 200  0
             if (formalOnly)
 201  0
                 throw new ApplicationRuntimeException(PageloadMessages.inheritInformalInvalidComponentFormalOnly(component),
 202  
                                                       component, contained.getLocation(), null);
 203  
 
 204  0
             IComponentSpecification containerSpec = container.getSpecification();
 205  
 
 206  0
             if (!containerSpec.getAllowInformalParameters())
 207  0
                 throw new ApplicationRuntimeException(PageloadMessages.inheritInformalInvalidContainerFormalOnly(container, component),
 208  
                                                       component, contained.getLocation(), null);
 209  
 
 210  0
             IQueuedInheritedBinding queued = new QueuedInheritInformalBindings(component);
 211  0
             _inheritedBindingQueue.add(queued);
 212  
         }
 213  
 
 214  0
         Iterator i = contained.getBindingNames().iterator();
 215  
 
 216  0
         while(i.hasNext())
 217  
         {
 218  0
             String name = (String) i.next();
 219  
 
 220  0
             IParameterSpecification pspec = spec.getParameter(name);
 221  
 
 222  0
             boolean isFormal = pspec != null;
 223  
 
 224  0
             String parameterName = isFormal ? pspec.getParameterName() : name;
 225  
 
 226  0
             IBindingSpecification bspec = contained.getBinding(name);
 227  
 
 228  
             // If not allowing informal parameters, check that each binding
 229  
             // matches
 230  
             // a formal parameter.
 231  
 
 232  0
             if (formalOnly && !isFormal)
 233  0
                 throw new ApplicationRuntimeException(PageloadMessages.formalParametersOnly(component, name),
 234  
                                                       component, bspec.getLocation(), null);
 235  
 
 236  
             // If an informal parameter that conflicts with a reserved name,
 237  
             // then skip it.
 238  
 
 239  0
             if (!isFormal && spec.isReservedParameterName(name))
 240  0
                 continue;
 241  
 
 242  0
             if (isFormal)
 243  
             {
 244  0
                 if (!name.equals(parameterName))
 245  
                 {
 246  0
                     _log.warn(PageloadMessages.usedParameterAlias(contained, name, parameterName, bspec.getLocation()));
 247  
                 }
 248  0
                 else if (pspec.isDeprecated())
 249  0
                     _log.warn(PageloadMessages.deprecatedParameter(name, bspec.getLocation(), contained.getType()));
 250  
             }
 251  
 
 252  
             // The type determines how to interpret the value:
 253  
             // As a simple static String
 254  
             // As a nested property name (relative to the component)
 255  
             // As the name of a binding inherited from the containing component.
 256  
             // As the name of a public field
 257  
             // As a script for a listener
 258  
 
 259  0
             BindingType type = bspec.getType();
 260  
 
 261  
             // For inherited bindings, defer until later. This gives components
 262  
             // a chance to setup bindings from static values and expressions in
 263  
             // the template. The order of operations is tricky, template
 264  
             // bindings
 265  
             // come later. Note that this is a hold over from the Tapestry 3.0
 266  
             // DTD
 267  
             // and will some day no longer be supported.
 268  
 
 269  0
             if (type == BindingType.INHERITED)
 270  
             {
 271  0
                 QueuedInheritedBinding queued = new QueuedInheritedBinding(component, bspec.getValue(), parameterName);
 272  0
                 _inheritedBindingQueue.add(queued);
 273  0
                 continue;
 274  
             }
 275  
 
 276  0
             String description = PageloadMessages.parameterName(name);
 277  
 
 278  0
             IBinding binding = convert(container, description, pspec, defaultBindingPrefix, bspec);
 279  
 
 280  0
             addBindingToComponent(component, parameterName, binding);
 281  0
         }
 282  0
     }
 283  
 
 284  
     /**
 285  
      * Adds a binding to the component, checking to see if there's a name
 286  
      * conflict (an existing binding for the same parameter ... possibly because
 287  
      * parameter names can be aliased).
 288  
      *
 289  
      * @param component
 290  
      *            to which the binding should be added
 291  
      * @param parameterName
 292  
      *            the name of the parameter to bind, which should be a true
 293  
      *            name, not an alias
 294  
      * @param binding
 295  
      *            the binding to add
 296  
      * @throws ApplicationRuntimeException
 297  
      *             if a binding already exists
 298  
      * @since 4.0
 299  
      */
 300  
 
 301  
     static void addBindingToComponent(IComponent component, String parameterName, IBinding binding)
 302  
     {
 303  0
         IBinding existing = component.getBinding(parameterName);
 304  
 
 305  0
         if (existing != null)
 306  0
             throw new ApplicationRuntimeException(PageloadMessages.duplicateParameter(parameterName, existing),
 307  
                                                   component, binding.getLocation(), null);
 308  
 
 309  0
         component.setBinding(parameterName, binding);
 310  0
     }
 311  
 
 312  
     private IBinding convert(IComponent container, String description, IParameterSpecification param,
 313  
                              String defaultBindingType, IBindingSpecification spec)
 314  
     {
 315  0
         Location location = spec.getLocation();
 316  0
         String bindingReference = spec.getValue();
 317  
 
 318  0
         return _bindingSource.createBinding(container, param, description,
 319  
                                             bindingReference, defaultBindingType, location);
 320  
     }
 321  
 
 322  
     /**
 323  
      * Sets up a component. This involves:
 324  
      * <ul>
 325  
      * <li>Instantiating any contained components.
 326  
      * <li>Add the contained components to the container.
 327  
      * <li>Setting up bindings between container and containees.
 328  
      * <li>Construct the containees recursively.
 329  
      * <li>Invoking
 330  
      * {@link IComponent#finishLoad(IRequestCycle, IPageLoader, IComponentSpecification)}
 331  
      * </ul>
 332  
      *
 333  
      * @param cycle
 334  
      *            the request cycle for which the page is being (initially)
 335  
      *            constructed
 336  
      * @param page
 337  
      *            The page on which the container exists.
 338  
      * @param container
 339  
      *            The component to be set up.
 340  
      * @param containerSpec
 341  
      *            The specification for the container.
 342  
      * @param namespace
 343  
      *            The namespace of the container
 344  
      */
 345  
 
 346  
     private void constructComponent(IRequestCycle cycle, IPage page,
 347  
                                     IComponent container, IComponentSpecification containerSpec,
 348  
                                     INamespace namespace)
 349  
     {
 350  0
         _depth++;
 351  0
         if (_depth > _maxDepth)
 352  0
             _maxDepth = _depth;
 353  
 
 354  0
         beginConstructComponent(container, containerSpec);
 355  
 
 356  0
         String defaultBindingPrefix = _componentPropertySource.getComponentProperty(container, TapestryConstants.DEFAULT_BINDING_PREFIX_NAME);
 357  
 
 358  0
         List ids = new ArrayList(containerSpec.getComponentIds());
 359  0
         int count = ids.size();
 360  
 
 361  
         try
 362  
         {
 363  0
             for(int i = 0; i < count; i++)
 364  
             {
 365  0
                 String id = (String) ids.get(i);
 366  
 
 367  
                 // Get the sub-component specification from the
 368  
                 // container's specification.
 369  
 
 370  0
                 IContainedComponent contained = containerSpec.getComponent(id);
 371  
 
 372  0
                 String type = contained.getType();
 373  0
                 Location location = contained.getLocation();
 374  
 
 375  0
                 _componentResolver.resolve(cycle, namespace, type, location);
 376  
 
 377  0
                 IComponentSpecification componentSpecification = _componentResolver.getSpecification();
 378  0
                 INamespace componentNamespace = _componentResolver.getNamespace();
 379  
 
 380  
                 // Instantiate the contained component.
 381  
 
 382  0
                 IComponent component = instantiateComponent(page, container,
 383  
                                                             id, componentSpecification, _componentResolver.getType(), componentNamespace, contained);
 384  
 
 385  
                 // Add it, by name, to the container.
 386  
 
 387  0
                 container.addComponent(component);
 388  
 
 389  
                 // Set up any bindings in the IContainedComponent specification
 390  
 
 391  0
                 bind(container, component, contained, defaultBindingPrefix);
 392  
 
 393  
                 // Now construct the component recusively; it gets its chance
 394  
                 // to create its subcomponents and set their bindings.
 395  
 
 396  0
                 constructComponent(cycle, page, component, componentSpecification, componentNamespace);
 397  
             }
 398  
 
 399  0
             addAssets(container, containerSpec);
 400  
 
 401  
             // Finish the load of the component; most components (which
 402  
             // subclass BaseComponent) load their templates here.
 403  
             // Properties with initial values will be set here (or the
 404  
             // initial value will be recorded for later use in pageDetach().
 405  
             // That may cause yet more components to be created, and more
 406  
             // bindings to be set, so we defer some checking until later.
 407  
 
 408  0
             container.finishLoad(cycle, this, containerSpec);
 409  
 
 410  
             // Have the component switch over to its active state.
 411  
 
 412  0
             container.enterActiveState();
 413  
         }
 414  0
         catch (ApplicationRuntimeException ex)
 415  
         {
 416  0
             throw ex;
 417  
         }
 418  0
         catch (RuntimeException ex)
 419  
         {
 420  0
             throw new ApplicationRuntimeException(PageloadMessages.unableToInstantiateComponent(container, ex),
 421  
                                                   container, null, ex);
 422  
         } finally {
 423  
 
 424  0
             endConstructComponent(container);
 425  0
         }
 426  
 
 427  0
         _depth--;
 428  0
     }
 429  
 
 430  
     /**
 431  
      * Checks the component stack to ensure that the specified component hasn't been improperly nested
 432  
      * and referenced recursively within itself.
 433  
      *
 434  
      * @param component
 435  
      *          The component to add to the current component stack and check for recursion.
 436  
      * @param specification
 437  
      *          The specification of the specified component.
 438  
      */
 439  
     void beginConstructComponent(IComponent component, IComponentSpecification specification)
 440  
     {
 441  
         // check recursion
 442  
 
 443  0
         int position = _componentStack.search(component);
 444  0
         if (position > -1)
 445  
         {
 446  0
             Location location = specification.getLocation();
 447  
 
 448  
             // try to get the more precise container position location that was referenced
 449  
             // in the template to properly report the precise position of the recursive reference
 450  
 
 451  0
             IContainedComponent container = component.getContainedComponent();
 452  0
             if (container != null)
 453  0
                 location = container.getLocation();
 454  
 
 455  0
             throw new ApplicationRuntimeException(PageloadMessages.recursiveComponent(component), location, null);
 456  
         }
 457  
 
 458  0
         _componentStack.push(component);
 459  0
     }
 460  
 
 461  
     /**
 462  
      * Pops the current component off the stack.
 463  
      *
 464  
      * @param component
 465  
      *          The component that has just been constructed.
 466  
      */
 467  
     void endConstructComponent(IComponent component)
 468  
     {
 469  0
         _componentStack.pop();
 470  0
     }
 471  
 
 472  
     /**
 473  
      * Invoked to create an implicit component (one which is defined in the
 474  
      * containing component's template, rather that in the containing
 475  
      * component's specification).
 476  
      *
 477  
      * @see org.apache.tapestry.services.impl.ComponentTemplateLoaderImpl
 478  
      * @since 3.0
 479  
      */
 480  
 
 481  
     public IComponent createImplicitComponent(IRequestCycle cycle,
 482  
                                               IComponent container, String componentId, String componentType,
 483  
                                               Location location)
 484  
     {
 485  0
         IPage page = container.getPage();
 486  
 
 487  0
         _componentResolver.resolve(cycle, container.getNamespace(), componentType, location);
 488  
 
 489  0
         INamespace componentNamespace = _componentResolver.getNamespace();
 490  0
         IComponentSpecification spec = _componentResolver.getSpecification();
 491  
 
 492  0
         IContainedComponent contained = new ContainedComponent();
 493  0
         contained.setLocation(location);
 494  0
         contained.setType(componentType);
 495  
 
 496  0
         IComponent result = instantiateComponent(page, container, componentId,
 497  
                                                  spec, _componentResolver.getType(), componentNamespace,
 498  
                                                  contained);
 499  
 
 500  0
         container.addComponent(result);
 501  
 
 502  
         // Recusively build the component.
 503  
 
 504  0
         constructComponent(cycle, page, result, spec, componentNamespace);
 505  
 
 506  0
         return result;
 507  
     }
 508  
 
 509  
     /**
 510  
      * Instantiates a component from its specification. We instantiate the
 511  
      * component object, then set its specification, page, container and id.
 512  
      *
 513  
      * @param page
 514  
      *          The page component is to be attached to.
 515  
      * @param container
 516  
      *          The containing component.
 517  
      * @param id
 518  
      *          The components unique id
 519  
      * @param spec
 520  
      *          The specification for the component
 521  
      * @param type
 522  
      *          The type (ie Any / For / DirectLink)
 523  
      * @param namespace
 524  
      *          Which namespace / library
 525  
      * @param containedComponent
 526  
      *          Possible contained component.
 527  
      *
 528  
      * @return The instantiated component instance.
 529  
      *
 530  
      * @see org.apache.tapestry.AbstractComponent
 531  
      */
 532  
 
 533  
     private IComponent instantiateComponent(IPage page, IComponent container,
 534  
                                             String id, IComponentSpecification spec, String type,
 535  
                                             INamespace namespace, IContainedComponent containedComponent)
 536  
     {
 537  0
         ComponentClassProviderContext context = new ComponentClassProviderContext(type, spec, namespace);
 538  
 
 539  0
         String className = _componentClassProvider.provideComponentClassName(context);
 540  
 
 541  0
         if (HiveMind.isBlank(className))
 542  0
             className = BaseComponent.class.getName();
 543  
         else
 544  
         {
 545  0
             Class componentClass = _classResolver.findClass(className);
 546  
 
 547  0
             if (!IComponent.class.isAssignableFrom(componentClass))
 548  0
                 throw new ApplicationRuntimeException(PageloadMessages.classNotComponent(componentClass),
 549  
                                                       container, spec.getLocation(), null);
 550  
 
 551  0
             if (IPage.class.isAssignableFrom(componentClass))
 552  0
                 throw new ApplicationRuntimeException(PageloadMessages.pageNotAllowed(id),
 553  
                                                       container, spec.getLocation(), null);
 554  
         }
 555  
 
 556  0
         ComponentConstructor cc = _componentConstructorFactory.getComponentConstructor(spec, className);
 557  
 
 558  0
         IComponent result = (IComponent) cc.newInstance();
 559  
 
 560  0
         result.setNamespace(namespace);
 561  0
         result.setPage(page);
 562  0
         result.setContainer(container);
 563  0
         result.setId(id);
 564  0
         result.setContainedComponent(containedComponent);
 565  0
         result.setLocation(containedComponent.getLocation());
 566  
 
 567  0
         _count++;
 568  
 
 569  0
         return result;
 570  
     }
 571  
 
 572  
     /**
 573  
      * Instantitates a page from its specification.
 574  
      *
 575  
      * @param name
 576  
      *            the unqualified, simple, name for the page
 577  
      * @param namespace
 578  
      *            the namespace containing the page's specification
 579  
      * @param spec
 580  
      *            the page's specification We instantiate the page object, then
 581  
      *            set its specification, names and locale.
 582  
      *
 583  
      * @return The instantiated page instance.
 584  
      *
 585  
      * @see org.apache.tapestry.IEngine
 586  
      * @see org.apache.tapestry.event.ChangeObserver
 587  
      */
 588  
 
 589  
     private IPage instantiatePage(String name, INamespace namespace, IComponentSpecification spec)
 590  
     {
 591  0
         Location location = spec.getLocation();
 592  0
         ComponentClassProviderContext context = new ComponentClassProviderContext(name, spec, namespace);
 593  
 
 594  0
         String className = _pageClassProvider.provideComponentClassName(context);
 595  
 
 596  0
         Class pageClass = _classResolver.findClass(className);
 597  
 
 598  0
         if (!IPage.class.isAssignableFrom(pageClass))
 599  0
             throw new ApplicationRuntimeException(PageloadMessages.classNotPage(pageClass), location, null);
 600  
 
 601  0
         String pageName = namespace.constructQualifiedName(name);
 602  
 
 603  0
         ComponentConstructor cc = _componentConstructorFactory.getComponentConstructor(spec, className);
 604  
 
 605  0
         IPage result = (IPage) cc.newInstance();
 606  
 
 607  0
         result.setNamespace(namespace);
 608  0
         result.setPageName(pageName);
 609  0
         result.setPage(result);
 610  0
         result.setLocale(_locale);
 611  0
         result.setLocation(location);
 612  
 
 613  0
         return result;
 614  
     }
 615  
 
 616  
     public IPage loadPage(String name, INamespace namespace,
 617  
                           IRequestCycle cycle, IComponentSpecification specification)
 618  
     {
 619  0
         IPage page = null;
 620  
 
 621  0
         _count = 0;
 622  0
         _depth = 0;
 623  0
         _maxDepth = 0;
 624  0
         _componentStack.clear();
 625  
 
 626  0
         _locale = _threadLocale.getLocale();
 627  
 
 628  
         try
 629  
         {
 630  0
             page = instantiatePage(name, namespace, specification);
 631  
 
 632  
             // The page is now attached to the engine and request cycle; some
 633  
             // code
 634  
             // inside the page's finishLoad() method may require this.
 635  
             // TAPESTRY-763
 636  
 
 637  0
             page.attach(cycle.getEngine(), cycle);
 638  
 
 639  0
             constructComponent(cycle, page, page, specification, namespace);
 640  
 
 641  
             // Walk through the complete component tree to set up the default
 642  
             // parameter values.
 643  
 
 644  0
             _establishDefaultParameterValuesWalker.walkComponentTree(page);
 645  
 
 646  0
             establishInheritedBindings();
 647  
 
 648  
             // Walk through the complete component tree to ensure that required
 649  
             // parameters are bound
 650  
 
 651  0
             _verifyRequiredParametersWalker.walkComponentTree(page);
 652  
 
 653  
             // connect @EventListener style client side events
 654  
 
 655  0
             _eventConnectionWalker.walkComponentTree(page);
 656  
         }
 657  
         finally
 658  
         {
 659  0
             _locale = null;
 660  0
             _inheritedBindingQueue.clear();
 661  0
         }
 662  
 
 663  0
         if (_log.isDebugEnabled())
 664  0
             _log.debug("Loaded page " + page + " with " + _count + " components (maximum depth " + _maxDepth + ")");
 665  
 
 666  0
         return page;
 667  
     }
 668  
 
 669  
     /** @since 4.0 */
 670  
 
 671  
     public void loadTemplateForComponent(IRequestCycle cycle, ITemplateComponent component)
 672  
     {
 673  0
         _componentTemplateLoader.loadTemplate(cycle, component);
 674  0
     }
 675  
 
 676  
     private void establishInheritedBindings()
 677  
     {
 678  0
         _log.debug("Establishing inherited bindings");
 679  
 
 680  0
         int count = _inheritedBindingQueue.size();
 681  
 
 682  0
         for(int i = 0; i < count; i++)
 683  
         {
 684  0
             IQueuedInheritedBinding queued = (IQueuedInheritedBinding) _inheritedBindingQueue.get(i);
 685  
 
 686  0
             queued.connect();
 687  
         }
 688  0
     }
 689  
 
 690  
     private void addAssets(IComponent component, IComponentSpecification specification)
 691  
     {
 692  0
         List names = specification.getAssetNames();
 693  
 
 694  0
         if (names.isEmpty()) return;
 695  
 
 696  0
         Iterator i = names.iterator();
 697  
 
 698  0
         while(i.hasNext())
 699  
         {
 700  0
             String name = (String) i.next();
 701  
 
 702  0
             IAssetSpecification assetSpec = specification.getAsset(name);
 703  
 
 704  0
             IAsset asset = _assetSource.findAsset(assetSpec.getLocation().getResource(), specification,
 705  
                                                   assetSpec.getPath(), _locale, assetSpec.getLocation());
 706  
 
 707  0
             component.addAsset(name, asset);
 708  0
         }
 709  0
     }
 710  
 
 711  
     public void setLog(Log log)
 712  
     {
 713  0
         _log = log;
 714  0
     }
 715  
 
 716  
     public void setComponentResolver(ComponentSpecificationResolver resolver)
 717  
     {
 718  0
         _componentResolver = resolver;
 719  0
     }
 720  
 
 721  
     public void setBindingSource(BindingSource bindingSource)
 722  
     {
 723  0
         _bindingSource = bindingSource;
 724  0
     }
 725  
 
 726  
     public void setComponentTemplateLoader(ComponentTemplateLoader componentTemplateLoader)
 727  
     {
 728  0
         _componentTemplateLoader = componentTemplateLoader;
 729  0
     }
 730  
 
 731  
     public void setEstablishDefaultParameterValuesVisitor(IComponentVisitor establishDefaultParameterValuesVisitor)
 732  
     {
 733  0
         _establishDefaultParameterValuesVisitor = establishDefaultParameterValuesVisitor;
 734  0
     }
 735  
 
 736  
     public void setEventConnectionVisitor(IComponentVisitor eventConnectionVisitor)
 737  
     {
 738  0
         _eventConnectionVisitor = eventConnectionVisitor;
 739  0
     }
 740  
 
 741  
     public void setComponentTypeVisitor(IComponentVisitor visitor)
 742  
     {
 743  0
         _componentTypeVisitor = visitor;
 744  0
     }
 745  
 
 746  
     public void setComponentConstructorFactory(ComponentConstructorFactory componentConstructorFactory)
 747  
     {
 748  0
         _componentConstructorFactory = componentConstructorFactory;
 749  0
     }
 750  
 
 751  
     public void setAssetSource(AssetSource assetSource)
 752  
     {
 753  0
         _assetSource = assetSource;
 754  0
     }
 755  
 
 756  
     public void setPageClassProvider(ComponentClassProvider pageClassProvider)
 757  
     {
 758  0
         _pageClassProvider = pageClassProvider;
 759  0
     }
 760  
 
 761  
     public void setClassResolver(ClassResolver classResolver)
 762  
     {
 763  0
         _classResolver = classResolver;
 764  0
     }
 765  
 
 766  
     public void setComponentClassProvider(ComponentClassProvider componentClassProvider)
 767  
     {
 768  0
         _componentClassProvider = componentClassProvider;
 769  0
     }
 770  
 
 771  
     public void setThreadLocale(ThreadLocale threadLocale)
 772  
     {
 773  0
         _threadLocale = threadLocale;
 774  0
     }
 775  
 
 776  
     public void setComponentPropertySource(ComponentPropertySource componentPropertySource)
 777  
     {
 778  0
         _componentPropertySource = componentPropertySource;
 779  0
     }
 780  
 }