Coverage Report - org.apache.tapestry.resolver.ComponentSpecificationResolverImpl
 
Classes in this File Line Coverage Branch Coverage Complexity
ComponentSpecificationResolverImpl
95% 
100% 
3.636
 
 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.ClassResolver;
 20  
 import org.apache.hivemind.Location;
 21  
 import org.apache.hivemind.Resource;
 22  
 import org.apache.hivemind.impl.LocationImpl;
 23  
 import org.apache.hivemind.util.ClasspathResource;
 24  
 import org.apache.tapestry.INamespace;
 25  
 import org.apache.tapestry.IRequestCycle;
 26  
 import org.apache.tapestry.services.ClassFinder;
 27  
 import org.apache.tapestry.spec.ComponentSpecification;
 28  
 import org.apache.tapestry.spec.IComponentSpecification;
 29  
 
 30  
 /**
 31  
  * Utility class that understands the rules of component types (which may optionally have a library
 32  
  * prefix) and can resolve the type to a {@link org.apache.tapestry.INamespace}and a
 33  
  * {@link org.apache.tapestry.spec.IComponentSpecification}.
 34  
  * <p>
 35  
  * Like {@link org.apache.tapestry.resolver.PageSpecificationResolver}, if the component is not
 36  
  * defined explicitly in the namespace, a search may occur: Performs the tricky work of resolving a
 37  
  * page name to a page specification. The search for pages in the application namespace is the most
 38  
  * complicated, since Tapestry searches for pages that aren't explicitly defined in the application
 39  
  * specification. The search, based on the <i>simple-name </i> of the page, goes as follows:
 40  
  * <ul>
 41  
  * <li>As declared in the application specification
 42  
  * <li><i>type</i>.jwc in the same folder as the application specification
 43  
  * <li><i>type</i> jwc in the WEB-INF/ <i>servlet-name </i> directory of the context root
 44  
  * <li><i>type</i>.jwc in WEB-INF
 45  
  * <li><i>type</i>.jwc in the application root (within the context root)
 46  
  * <li>By searching the framework namespace
 47  
  * <li>By searching for a named class file within the org.apache.tapestry.component-class-packages
 48  
  * property (defined within the namespace)
 49  
  * </ul>
 50  
  * 
 51  
  * The search for components in library namespaces is more abbreviated:
 52  
  * <ul>
 53  
  * <li>As declared in the library specification
 54  
  * <li><i>type </i>.jwc in the same folder as the library specification
 55  
  * <li>By searching the framework namespace
 56  
  * </ul>
 57  
  * 
 58  
  * @since 3.0
 59  
  */
 60  
 
 61  12
 public class ComponentSpecificationResolverImpl extends AbstractSpecificationResolver implements
 62  
         ComponentSpecificationResolver
 63  
 {
 64  
     /** Set by container. */
 65  
     private Log _log;
 66  
 
 67  
     /** Set by resolve(). */
 68  
     private String _type;
 69  
 
 70  
     private ClassFinder _classFinder;
 71  
 
 72  
     private ClassResolver _classResolver;
 73  
 
 74  
     protected void reset()
 75  
     {
 76  11
         _type = null;
 77  
         
 78  11
         super.reset();
 79  11
     }
 80  
     
 81  
     /**
 82  
      * Passed the namespace of a container (to resolve the type in) and the type to resolve,
 83  
      * performs the processing. A "bare type" (without a library prefix) may be in the
 84  
      * containerNamespace, or the framework namespace (a search occurs in that order).
 85  
      * 
 86  
      * @param cycle
 87  
      *            current request cycle
 88  
      * @param containerNamespace
 89  
      *            namespace that may contain a library referenced in the type
 90  
      * @param type
 91  
      *            the component specification to find, either a simple name, or prefixed with a
 92  
      *            library id (defined for the container namespace)
 93  
      * @see #getNamespace()
 94  
      * @see #getSpecification()
 95  
      */
 96  
 
 97  
     public void resolve(IRequestCycle cycle, INamespace containerNamespace, String type, Location location)
 98  
     {
 99  11
         int colonx = type.indexOf(':');
 100  
 
 101  11
         if (colonx > 0)
 102  
         {
 103  2
             String libraryId = type.substring(0, colonx);
 104  2
             String simpleType = type.substring(colonx + 1);
 105  
 
 106  2
             resolve(cycle, containerNamespace, libraryId, simpleType, location);
 107  1
         }
 108  
         else
 109  9
             resolve(cycle, containerNamespace, null, type, location);
 110  
         
 111  9
         IComponentSpecification spec = getSpecification();
 112  
         
 113  9
         if (spec.isDeprecated())
 114  1
             _log.warn(ResolverMessages.componentIsDeprecated(type, location));
 115  9
     }
 116  
 
 117  
     /**
 118  
      * Like
 119  
      * {@link #resolve(org.apache.tapestry.IRequestCycle, org.apache.tapestry.INamespace, java.lang.String, Location)},
 120  
      * but used when the type has already been parsed into a library id and a simple type.
 121  
      * 
 122  
      * @param cycle
 123  
      *            current request cycle
 124  
      * @param containerNamespace
 125  
      *            namespace that may contain a library referenced in the type
 126  
      * @param libraryId
 127  
      *            the library id within the container namespace, or null
 128  
      * @param type
 129  
      *            the component specification to find as a simple name (without a library prefix)
 130  
      * @param location
 131  
      *            of reference to be resolved
 132  
      * @throws ApplicationRuntimeException
 133  
      *             if the type cannot be resolved
 134  
      */
 135  
 
 136  
     public void resolve(IRequestCycle cycle, INamespace containerNamespace, String libraryId,
 137  
             String type, Location location)
 138  
     {
 139  11
         reset();
 140  11
         _type = type;
 141  
 
 142  
         INamespace namespace;
 143  
         try
 144  
         {
 145  11
             namespace = findNamespaceForId(containerNamespace, libraryId);
 146  
         }
 147  1
         catch (ApplicationRuntimeException e)
 148  
         {
 149  1
             throw new ApplicationRuntimeException(e.getMessage(), location, e);
 150  10
         }
 151  
 
 152  10
         setNamespace(namespace);
 153  
 
 154  10
         if (namespace.containsComponentType(type))
 155  
         {
 156  3
             setSpecification(namespace.getComponentSpecification(type));
 157  3
             return;
 158  
         }
 159  
 
 160  7
         IComponentSpecification spec = searchForComponent(cycle);
 161  
 
 162  
         // If not found after search, check to see if it's in
 163  
         // the framework instead.
 164  
 
 165  7
         if (spec == null)
 166  
         {
 167  1
             throw new ApplicationRuntimeException(ResolverMessages.noSuchComponentType(
 168  
                     type,
 169  
                     namespace), location, null);
 170  
 
 171  
         }
 172  
 
 173  6
         setSpecification(spec);
 174  
 
 175  
         // Install it into the namespace, to short-circuit any future search.
 176  
 
 177  6
         install();
 178  6
     }
 179  
 
 180  
     // Hm. This could maybe go elsewhere, say onto ISpecificationSource
 181  
 
 182  
     private IComponentSpecification searchForComponent(IRequestCycle cycle)
 183  
     {
 184  7
         IComponentSpecification result = null;
 185  7
         INamespace namespace = getNamespace();
 186  
 
 187  7
         if (_log.isDebugEnabled())
 188  7
             _log.debug(ResolverMessages.resolvingComponent(_type, namespace));
 189  
         
 190  7
         String expectedName = _type + ".jwc";
 191  7
         Resource namespaceLocation = namespace.getSpecificationLocation();
 192  
         
 193  
         // Look for appropriate file in same folder as the library (or application)
 194  
         // specificaiton.
 195  
         
 196  7
         result = check(namespaceLocation.getRelativeResource(expectedName));
 197  
         
 198  7
         if (result != null)
 199  1
             return result;
 200  
 
 201  6
         if (namespace.isApplicationNamespace()) {
 202  
             
 203  
             // The application namespace gets some extra searching.
 204  
             
 205  3
             result = check(getWebInfAppLocation().getRelativeResource(expectedName));
 206  
 
 207  3
             if (result == null)
 208  2
                 result = check(getWebInfLocation().getRelativeResource(expectedName));
 209  
 
 210  3
             if (result == null)
 211  1
                 result = check((getContextRoot().getRelativeResource(expectedName)));
 212  
             
 213  3
             if (result != null)
 214  3
                 return result;
 215  
         }
 216  
         
 217  3
         result = getDelegate().findComponentSpecification(cycle, namespace, _type);
 218  3
         if (result != null)
 219  1
             return result;
 220  
         
 221  2
         result = searchForComponentClass(namespace, _type);
 222  
 
 223  2
         if (result != null)
 224  0
             return result;
 225  
 
 226  
         // Not in the library or app spec; does it match a component
 227  
         // provided by the Framework?
 228  
         
 229  2
         INamespace framework = getSpecificationSource().getFrameworkNamespace();
 230  
         
 231  2
         if (framework.containsComponentType(_type))
 232  1
             return framework.getComponentSpecification(_type);
 233  
         
 234  1
         return null;
 235  
     }
 236  
 
 237  
     IComponentSpecification searchForComponentClass(INamespace namespace, String type)
 238  
     {
 239  3
         String packages = namespace.getPropertyValue("org.apache.tapestry.component-class-packages");
 240  
 
 241  3
         String className = type.replace('/', '.');
 242  
 
 243  3
         Class componentClass = _classFinder.findClass(packages, className);
 244  3
         if (componentClass == null)
 245  2
             return null;
 246  
 
 247  1
         IComponentSpecification spec = new ComponentSpecification();
 248  
 
 249  1
         Resource namespaceResource = namespace.getSpecificationLocation();
 250  1
         Resource componentResource = namespaceResource.getRelativeResource(type + ".jwc");
 251  
 
 252  
         // try classpath relative if namespace relative doesn't resolve
 253  
 
 254  1
         if (componentResource.getResourceURL() == null) {
 255  
             
 256  0
             componentResource = new ClasspathResource(_classResolver, componentClass.getName().replace('.', '/'));
 257  
         }
 258  
 
 259  1
         Location location = new LocationImpl(componentResource);
 260  
 
 261  1
         spec.setLocation(location);
 262  1
         spec.setSpecificationLocation(componentResource);
 263  1
         spec.setComponentClassName(componentClass.getName());
 264  
 
 265  1
         return spec;
 266  
     }
 267  
 
 268  
     private IComponentSpecification check(Resource resource)
 269  
     {
 270  13
         if (_log.isDebugEnabled())
 271  13
             _log.debug("Checking: " + resource);
 272  
 
 273  13
         if (resource.getResourceURL() == null)
 274  9
             return null;
 275  
 
 276  4
         return getSpecificationSource().getComponentSpecification(resource);
 277  
     }
 278  
     
 279  
     private void install()
 280  
     {
 281  6
         INamespace namespace = getNamespace();
 282  6
         IComponentSpecification specification = getSpecification();
 283  
         
 284  6
         if (_log.isDebugEnabled())
 285  5
             _log.debug(ResolverMessages.installingComponent(_type, namespace, specification));
 286  
         
 287  6
         namespace.installComponentSpecification(_type, specification);
 288  6
     }
 289  
 
 290  
     public String getType()
 291  
     {
 292  0
         return _type;
 293  
     }
 294  
 
 295  
     public void setLog(Log log)
 296  
     {
 297  8
         _log = log;
 298  8
     }
 299  
 
 300  
     public void setClassFinder(ClassFinder classFinder)
 301  
     {
 302  3
         _classFinder = classFinder;
 303  3
     }
 304  
 
 305  
     public void setClassResolver(ClassResolver classResolver)
 306  
     {
 307  0
         _classResolver = classResolver;
 308  0
     }
 309  
 }