Clover coverage report - Code Coverage for tapestry release 4.0.3
Coverage timestamp: Fri May 5 2006 21:17:42 CDT
file stats: LOC: 312   Methods: 11
NCLOC: 155   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
PageSpecificationResolverImpl.java 100% 100% 100% 100%
coverage
 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.resolver;
 16   
 17    import org.apache.commons.logging.Log;
 18    import org.apache.hivemind.ApplicationRuntimeException;
 19    import org.apache.hivemind.Resource;
 20    import org.apache.hivemind.impl.LocationImpl;
 21    import org.apache.tapestry.INamespace;
 22    import org.apache.tapestry.IRequestCycle;
 23    import org.apache.tapestry.PageNotFoundException;
 24    import org.apache.tapestry.Tapestry;
 25    import org.apache.tapestry.services.ComponentPropertySource;
 26    import org.apache.tapestry.spec.ComponentSpecification;
 27    import org.apache.tapestry.spec.IComponentSpecification;
 28   
 29    /**
 30    * Performs the tricky work of resolving a page name to a page specification. The search for pages
 31    * in the application namespace is the most complicated, since Tapestry searches for pages that
 32    * aren't explicitly defined in the application specification. The search, based on the
 33    * <i>simple-name </i> of the page, goes as follows:
 34    * <ul>
 35    * <li>As declared in the application specification
 36    * <li><i>simple-name </i>.page in the same folder as the application specification
 37    * <li><i>simple-name </i> page in the WEB-INF/ <i>servlet-name </i> directory of the context root
 38    * <li><i>simple-name </i>.page in WEB-INF
 39    * <li><i>simple-name </i>.page in the application root (within the context root)
 40    * <li><i>simple-name </i>.html as a template in the application root, for which an implicit
 41    * specification is generated
 42    * <li>By searching the framework namespace
 43    * <li>By invoking
 44    * {@link org.apache.tapestry.resolver.ISpecificationResolverDelegate#findPageSpecification(IRequestCycle, INamespace, String)}
 45    * </ul>
 46    * <p>
 47    * Pages in a component library are searched for in a more abbreviated fashion:
 48    * <ul>
 49    * <li>As declared in the library specification
 50    * <li><i>simple-name </i>.page in the same folder as the library specification
 51    * <li>By searching the framework namespace
 52    * <li>By invoking
 53    * {@link org.apache.tapestry.resolver.ISpecificationResolverDelegate#findPageSpecification(IRequestCycle, INamespace, String)}
 54    * </ul>
 55    *
 56    * @see org.apache.tapestry.engine.IPageSource
 57    * @author Howard Lewis Ship
 58    * @since 3.0
 59    */
 60   
 61    public class PageSpecificationResolverImpl extends AbstractSpecificationResolver implements
 62    PageSpecificationResolver
 63    {
 64    private static final String WEB_INF = "/WEB-INF/";
 65   
 66    /** set by container */
 67    private Log _log;
 68   
 69    /** Set by resolve() */
 70    private String _simpleName;
 71   
 72    /** @since 4.0 * */
 73    private INamespace _applicationNamespace;
 74   
 75    /** @since 4.0 * */
 76    private INamespace _frameworkNamespace;
 77   
 78    /** @since 4.0 */
 79   
 80    private ComponentPropertySource _componentPropertySource;
 81   
 82  324 public void initializeService()
 83    {
 84  324 _applicationNamespace = getSpecificationSource().getApplicationNamespace();
 85  324 _frameworkNamespace = getSpecificationSource().getFrameworkNamespace();
 86   
 87  324 super.initializeService();
 88    }
 89   
 90  411 protected void reset()
 91    {
 92  411 _simpleName = null;
 93   
 94  411 super.reset();
 95    }
 96   
 97    /**
 98    * Resolve the name (which may have a library id prefix) to a namespace (see
 99    * {@link #getNamespace()}) and a specification (see {@link #getSpecification()}).
 100    *
 101    * @throws ApplicationRuntimeException
 102    * if the name cannot be resolved
 103    */
 104   
 105  411 public void resolve(IRequestCycle cycle, String prefixedName)
 106    {
 107  411 reset();
 108   
 109  411 INamespace namespace = null;
 110   
 111  411 int colonx = prefixedName.indexOf(':');
 112   
 113  411 if (colonx > 0)
 114    {
 115  15 _simpleName = prefixedName.substring(colonx + 1);
 116  15 String namespaceId = prefixedName.substring(0, colonx);
 117   
 118  15 namespace = findNamespaceForId(_applicationNamespace, namespaceId);
 119    }
 120    else
 121    {
 122  396 _simpleName = prefixedName;
 123   
 124  396 namespace = _applicationNamespace;
 125    }
 126   
 127  411 setNamespace(namespace);
 128   
 129  411 if (namespace.containsPage(_simpleName))
 130    {
 131  129 setSpecification(namespace.getPageSpecification(_simpleName));
 132  129 return;
 133    }
 134   
 135    // Not defined in the specification, so it's time to hunt it down.
 136   
 137  282 searchForPage(cycle);
 138   
 139  276 if (getSpecification() == null)
 140  6 throw new PageNotFoundException(ResolverMessages.noSuchPage(_simpleName, namespace));
 141    }
 142   
 143  399 public String getSimplePageName()
 144    {
 145  399 return _simpleName;
 146    }
 147   
 148  282 private void searchForPage(IRequestCycle cycle)
 149    {
 150  282 INamespace namespace = getNamespace();
 151   
 152  282 if (_log.isDebugEnabled())
 153  24 _log.debug(ResolverMessages.resolvingPage(_simpleName, namespace));
 154   
 155    // Check with and without the leading slash
 156   
 157  282 if (_simpleName.regionMatches(true, 0, WEB_INF, 0, WEB_INF.length())
 158    || _simpleName.regionMatches(true, 0, WEB_INF, 1, WEB_INF.length() - 1))
 159  6 throw new ApplicationRuntimeException(ResolverMessages.webInfNotAllowed(_simpleName));
 160   
 161  276 String expectedName = _simpleName + ".page";
 162   
 163  276 Resource namespaceLocation = namespace.getSpecificationLocation();
 164   
 165    // See if there's a specification file in the same folder
 166    // as the library or application specification that's
 167    // supposed to contain the page.
 168   
 169  276 if (found(namespaceLocation, expectedName))
 170  129 return;
 171   
 172  147 if (namespace.isApplicationNamespace())
 173    {
 174   
 175    // The application namespace gets some extra searching.
 176   
 177  141 if (found(getWebInfAppLocation(), expectedName))
 178  3 return;
 179   
 180  138 if (found(getWebInfLocation(), expectedName))
 181  3 return;
 182   
 183  135 if (found(getContextRoot(), expectedName))
 184  3 return;
 185   
 186    // The wierd one ... where we see if there's a template in the application root
 187    // location.
 188   
 189  132 String templateName = _simpleName + "." + getTemplateExtension();
 190   
 191  132 Resource templateResource = getContextRoot().getRelativeResource(templateName);
 192   
 193  132 if (_log.isDebugEnabled())
 194  6 _log.debug(ResolverMessages.checkingResource(templateResource));
 195   
 196  132 if (templateResource.getResourceURL() != null)
 197    {
 198  54 setupImplicitPage(templateResource, namespaceLocation);
 199  54 return;
 200    }
 201   
 202    // Not found in application namespace, so maybe its a framework page.
 203   
 204  78 if (_frameworkNamespace.containsPage(_simpleName))
 205    {
 206  75 if (_log.isDebugEnabled())
 207  3 _log.debug(ResolverMessages.foundFrameworkPage(_simpleName));
 208   
 209  75 setNamespace(_frameworkNamespace);
 210   
 211    // Note: This implies that normal lookup rules don't work
 212    // for the framework! Framework pages must be
 213    // defined in the framework library specification.
 214   
 215  75 setSpecification(_frameworkNamespace.getPageSpecification(_simpleName));
 216  75 return;
 217    }
 218    }
 219   
 220    // Not found by any normal rule, so its time to
 221    // consult the delegate.
 222   
 223  9 IComponentSpecification specification = getDelegate().findPageSpecification(
 224    cycle,
 225    namespace,
 226    _simpleName);
 227   
 228  9 if (specification != null)
 229    {
 230  3 setSpecification(specification);
 231  3 install();
 232    }
 233    }
 234   
 235  54 private void setupImplicitPage(Resource resource, Resource namespaceLocation)
 236    {
 237  54 if (_log.isDebugEnabled())
 238  3 _log.debug(ResolverMessages.foundHTMLTemplate(resource));
 239   
 240    // TODO The SpecFactory in Specification parser should be used in some way to
 241    // create an IComponentSpecification!
 242   
 243    // The virtual location of the page specification is relative to the
 244    // namespace (typically, the application specification). This will be used when
 245    // searching for the page's message catalog or other related assets.
 246   
 247  54 Resource pageResource = namespaceLocation.getRelativeResource(_simpleName + ".page");
 248   
 249  54 IComponentSpecification specification = new ComponentSpecification();
 250  54 specification.setPageSpecification(true);
 251  54 specification.setSpecificationLocation(pageResource);
 252  54 specification.setLocation(new LocationImpl(resource));
 253   
 254  54 setSpecification(specification);
 255   
 256  54 install();
 257    }
 258   
 259  690 private boolean found(Resource baseResource, String expectedName)
 260    {
 261  690 Resource resource = baseResource.getRelativeResource(expectedName);
 262   
 263  690 if (_log.isDebugEnabled())
 264  60 _log.debug(ResolverMessages.checkingResource(resource));
 265   
 266  690 if (resource.getResourceURL() == null)
 267  552 return false;
 268   
 269  138 setSpecification(getSpecificationSource().getPageSpecification(resource));
 270   
 271  138 install();
 272   
 273  138 return true;
 274    }
 275   
 276  195 private void install()
 277    {
 278  195 INamespace namespace = getNamespace();
 279  195 IComponentSpecification specification = getSpecification();
 280   
 281  195 if (_log.isDebugEnabled())
 282  12 _log.debug(ResolverMessages.installingPage(_simpleName, namespace, specification));
 283   
 284  195 namespace.installPageSpecification(_simpleName, specification);
 285    }
 286   
 287    /**
 288    * If the namespace defines the template extension (as property
 289    * {@link Tapestry#TEMPLATE_EXTENSION_PROPERTY}, then that is used, otherwise the default is
 290    * used.
 291    */
 292   
 293  132 private String getTemplateExtension()
 294    {
 295  132 return _componentPropertySource.getNamespaceProperty(
 296    getNamespace(),
 297    Tapestry.TEMPLATE_EXTENSION_PROPERTY);
 298    }
 299   
 300    /** @since 4.0 */
 301   
 302  312 public void setLog(Log log)
 303    {
 304  312 _log = log;
 305    }
 306   
 307    /** @since 4.0 */
 308  291 public void setComponentPropertySource(ComponentPropertySource componentPropertySource)
 309    {
 310  291 _componentPropertySource = componentPropertySource;
 311    }
 312    }