Clover coverage report - Code Coverage for tapestry release 4.0.1
Coverage timestamp: Fri Mar 31 2006 09:12:14 EST
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  216 public void initializeService()
 83    {
 84  216 _applicationNamespace = getSpecificationSource().getApplicationNamespace();
 85  216 _frameworkNamespace = getSpecificationSource().getFrameworkNamespace();
 86   
 87  216 super.initializeService();
 88    }
 89   
 90  274 protected void reset()
 91    {
 92  274 _simpleName = null;
 93   
 94  274 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  274 public void resolve(IRequestCycle cycle, String prefixedName)
 106    {
 107  274 reset();
 108   
 109  274 INamespace namespace = null;
 110   
 111  274 int colonx = prefixedName.indexOf(':');
 112   
 113  274 if (colonx > 0)
 114    {
 115  10 _simpleName = prefixedName.substring(colonx + 1);
 116  10 String namespaceId = prefixedName.substring(0, colonx);
 117   
 118  10 namespace = findNamespaceForId(_applicationNamespace, namespaceId);
 119    }
 120    else
 121    {
 122  264 _simpleName = prefixedName;
 123   
 124  264 namespace = _applicationNamespace;
 125    }
 126   
 127  274 setNamespace(namespace);
 128   
 129  274 if (namespace.containsPage(_simpleName))
 130    {
 131  86 setSpecification(namespace.getPageSpecification(_simpleName));
 132  86 return;
 133    }
 134   
 135    // Not defined in the specification, so it's time to hunt it down.
 136   
 137  188 searchForPage(cycle);
 138   
 139  184 if (getSpecification() == null)
 140  4 throw new PageNotFoundException(ResolverMessages.noSuchPage(_simpleName, namespace));
 141    }
 142   
 143  266 public String getSimplePageName()
 144    {
 145  266 return _simpleName;
 146    }
 147   
 148  188 private void searchForPage(IRequestCycle cycle)
 149    {
 150  188 INamespace namespace = getNamespace();
 151   
 152  188 if (_log.isDebugEnabled())
 153  16 _log.debug(ResolverMessages.resolvingPage(_simpleName, namespace));
 154   
 155    // Check with and without the leading slash
 156   
 157  188 if (_simpleName.regionMatches(true, 0, WEB_INF, 0, WEB_INF.length())
 158    || _simpleName.regionMatches(true, 0, WEB_INF, 1, WEB_INF.length() - 1))
 159  4 throw new ApplicationRuntimeException(ResolverMessages.webInfNotAllowed(_simpleName));
 160   
 161  184 String expectedName = _simpleName + ".page";
 162   
 163  184 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  184 if (found(namespaceLocation, expectedName))
 170  86 return;
 171   
 172  98 if (namespace.isApplicationNamespace())
 173    {
 174   
 175    // The application namespace gets some extra searching.
 176   
 177  94 if (found(getWebInfAppLocation(), expectedName))
 178  2 return;
 179   
 180  92 if (found(getWebInfLocation(), expectedName))
 181  2 return;
 182   
 183  90 if (found(getContextRoot(), expectedName))
 184  2 return;
 185   
 186    // The wierd one ... where we see if there's a template in the application root
 187    // location.
 188   
 189  88 String templateName = _simpleName + "." + getTemplateExtension();
 190   
 191  88 Resource templateResource = getContextRoot().getRelativeResource(templateName);
 192   
 193  88 if (_log.isDebugEnabled())
 194  4 _log.debug(ResolverMessages.checkingResource(templateResource));
 195   
 196  88 if (templateResource.getResourceURL() != null)
 197    {
 198  36 setupImplicitPage(templateResource, namespaceLocation);
 199  36 return;
 200    }
 201   
 202    // Not found in application namespace, so maybe its a framework page.
 203   
 204  52 if (_frameworkNamespace.containsPage(_simpleName))
 205    {
 206  50 if (_log.isDebugEnabled())
 207  2 _log.debug(ResolverMessages.foundFrameworkPage(_simpleName));
 208   
 209  50 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  50 setSpecification(_frameworkNamespace.getPageSpecification(_simpleName));
 216  50 return;
 217    }
 218    }
 219   
 220    // Not found by any normal rule, so its time to
 221    // consult the delegate.
 222   
 223  6 IComponentSpecification specification = getDelegate().findPageSpecification(
 224    cycle,
 225    namespace,
 226    _simpleName);
 227   
 228  6 if (specification != null)
 229    {
 230  2 setSpecification(specification);
 231  2 install();
 232    }
 233    }
 234   
 235  36 private void setupImplicitPage(Resource resource, Resource namespaceLocation)
 236    {
 237  36 if (_log.isDebugEnabled())
 238  2 _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  36 Resource pageResource = namespaceLocation.getRelativeResource(_simpleName + ".page");
 248   
 249  36 IComponentSpecification specification = new ComponentSpecification();
 250  36 specification.setPageSpecification(true);
 251  36 specification.setSpecificationLocation(pageResource);
 252  36 specification.setLocation(new LocationImpl(resource));
 253   
 254  36 setSpecification(specification);
 255   
 256  36 install();
 257    }
 258   
 259  460 private boolean found(Resource baseResource, String expectedName)
 260    {
 261  460 Resource resource = baseResource.getRelativeResource(expectedName);
 262   
 263  460 if (_log.isDebugEnabled())
 264  40 _log.debug(ResolverMessages.checkingResource(resource));
 265   
 266  460 if (resource.getResourceURL() == null)
 267  368 return false;
 268   
 269  92 setSpecification(getSpecificationSource().getPageSpecification(resource));
 270   
 271  92 install();
 272   
 273  92 return true;
 274    }
 275   
 276  130 private void install()
 277    {
 278  130 INamespace namespace = getNamespace();
 279  130 IComponentSpecification specification = getSpecification();
 280   
 281  130 if (_log.isDebugEnabled())
 282  8 _log.debug(ResolverMessages.installingPage(_simpleName, namespace, specification));
 283   
 284  130 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  88 private String getTemplateExtension()
 294    {
 295  88 return _componentPropertySource.getNamespaceProperty(
 296    getNamespace(),
 297    Tapestry.TEMPLATE_EXTENSION_PROPERTY);
 298    }
 299   
 300    /** @since 4.0 */
 301   
 302  208 public void setLog(Log log)
 303    {
 304  208 _log = log;
 305    }
 306   
 307    /** @since 4.0 */
 308  194 public void setComponentPropertySource(ComponentPropertySource componentPropertySource)
 309    {
 310  194 _componentPropertySource = componentPropertySource;
 311    }
 312    }