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