You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tapestry.apache.org by jk...@apache.org on 2007/05/08 05:13:06 UTC

svn commit: r536045 - in /tapestry/tapestry4/trunk: tapestry-examples/Workbench/src/context/WEB-INF/form/ tapestry-framework/src/descriptor/META-INF/ tapestry-framework/src/java/org/apache/tapestry/l10n/ tapestry-framework/src/java/org/apache/tapestry/...

Author: jkuhnert
Date: Mon May  7 20:13:04 2007
New Revision: 536045

URL: http://svn.apache.org/viewvc?view=rev&rev=536045
Log:
Because Ben won't let me sleep unless this happens correctly. =p

Changed Component template / properties resolution to use new single service to handle the logic of finding things in the context/classpath/whatever so that logic isn't duplicated anymore and context resources always take precidence over classpath resources in the resolving chain.

Added:
    tapestry/tapestry4/trunk/tapestry-examples/Workbench/src/context/WEB-INF/form/ShowError.properties
    tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/resolver/ComponentResourceResolverImpl.java   (with props)
    tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/resolver/IComponentResourceResolver.java   (with props)
    tapestry/tapestry4/trunk/tapestry-framework/src/test/org/apache/tapestry/resolver/TestComponentResourceResolver.java   (with props)
Modified:
    tapestry/tapestry4/trunk/tapestry-framework/src/descriptor/META-INF/hivemodule.xml
    tapestry/tapestry4/trunk/tapestry-framework/src/descriptor/META-INF/tapestry.page.xml
    tapestry/tapestry4/trunk/tapestry-framework/src/descriptor/META-INF/tapestry.parse.xml
    tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/l10n/DefaultResourceLocalizer.java
    tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/services/ClasspathResourceFactory.java
    tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/services/impl/ComponentMessagesSourceImpl.java
    tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/services/impl/ComponentPropertySourceImpl.java
    tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/services/impl/ComponentTemplateLoaderImpl.java
    tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/services/impl/ComponentTemplateLoaderLogic.java
    tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/services/impl/TemplateSourceImpl.java
    tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/web/LocalizedWebContextResourceFinder.java
    tapestry/tapestry4/trunk/tapestry-framework/src/test/org/apache/tapestry/junit/TestComponentMessages.java

Added: tapestry/tapestry4/trunk/tapestry-examples/Workbench/src/context/WEB-INF/form/ShowError.properties
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-examples/Workbench/src/context/WEB-INF/form/ShowError.properties?view=auto&rev=536045
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-examples/Workbench/src/context/WEB-INF/form/ShowError.properties (added)
+++ tapestry/tapestry4/trunk/tapestry-examples/Workbench/src/context/WEB-INF/form/ShowError.properties Mon May  7 20:13:04 2007
@@ -0,0 +1 @@
+test.error=Test error property found.
\ No newline at end of file

Modified: tapestry/tapestry4/trunk/tapestry-framework/src/descriptor/META-INF/hivemodule.xml
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/descriptor/META-INF/hivemodule.xml?view=diff&rev=536045&r1=536044&r2=536045
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/src/descriptor/META-INF/hivemodule.xml (original)
+++ tapestry/tapestry4/trunk/tapestry-framework/src/descriptor/META-INF/hivemodule.xml Mon May  7 20:13:04 2007
@@ -207,6 +207,7 @@
       <construct class="impl.ComponentMessagesSourceImpl">
         <event-listener service-id="ResetEventHub"/>
         <set-object property="componentPropertySource" value="infrastructure:componentPropertySource"/>
+        <set-service property="componentResourceResolver" service-id="tapestry.page.ComponentResourceResolver" />
       </construct>
     </invoke-factory>
     

Modified: tapestry/tapestry4/trunk/tapestry-framework/src/descriptor/META-INF/tapestry.page.xml
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/descriptor/META-INF/tapestry.page.xml?view=diff&rev=536045&r1=536044&r2=536045
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/src/descriptor/META-INF/tapestry.page.xml (original)
+++ tapestry/tapestry4/trunk/tapestry-framework/src/descriptor/META-INF/tapestry.page.xml Mon May  7 20:13:04 2007
@@ -135,6 +135,21 @@
 
     </service-point>
 
+    <service-point id="ComponentResourceResolver" interface="org.apache.tapestry.resolver.IComponentResourceResolver">
+
+        Locates and loads resource relative to a component / page.
+
+        <invoke-factory>
+            <construct class="org.apache.tapestry.resolver.ComponentResourceResolverImpl">
+                <set-object property="contextRoot" value="infrastructure:contextRoot"/>
+                <set-object property="applicationId" value="infrastructure:applicationId"/>
+                <set-service property="contextAssetFactory" service-id="tapestry.asset.ContextAssetFactory" />
+                <set-service property="classpathAssetFactory" service-id="tapestry.asset.ClasspathAssetFactory" />
+            </construct>
+        </invoke-factory>
+
+    </service-point>
+
     <configuration-point id="PageClassProviderChain" schema-id="hivemind.lib.ChainContribution">
 
         Chain of objects implementing ComponentClassProvider that are used to locate  the page class

Modified: tapestry/tapestry4/trunk/tapestry-framework/src/descriptor/META-INF/tapestry.parse.xml
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/descriptor/META-INF/tapestry.parse.xml?view=diff&rev=536045&r1=536044&r2=536045
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/src/descriptor/META-INF/tapestry.parse.xml (original)
+++ tapestry/tapestry4/trunk/tapestry-framework/src/descriptor/META-INF/tapestry.parse.xml Mon May  7 20:13:04 2007
@@ -16,98 +16,95 @@
 -->
 
 <module id="tapestry.parse" version="4.0.0" package="org.apache.tapestry.parse">
-  
-  Template and specification parsers.
-  
-  <service-point id="SpecificationParser" interface="ISpecificationParser">
-    
-    The parser for all types of specifications (page, component, library and application).
-    
-    <!-- This one is constructed a little wierdly, to help maintain compatibility with Spindle. -->
-    
-    <invoke-factory model="pooled">
-      <construct class="SpecificationParser" autowire-services="false">
-        <error-handler/>
-        <log/>
-        <class-resolver/>
-        <object> instance:org.apache.tapestry.spec.SpecFactory </object>
-        
-        <!-- Can't use infrastructure:valueConverter, because SpecificationParser will be created earlier than
-             tapestry.Infrastructure -->
-             
-        <set-service property="valueConverter" service-id="tapestry.coerce.ValueConverter"/>
-        <set-service property="bindingSource" service-id="tapestry.bindings.BindingSource"/>
-      </construct>
-    </invoke-factory>
-    
-    <interceptor service-id="hivemind.LoggingInterceptor"/>
-  </service-point>  
-  
-  <service-point id="SpecificationSource" interface="org.apache.tapestry.engine.ISpecificationSource">
-    
-    Used to obtain specifications for pages, components and libraries.
-    
-    <invoke-factory>
-      <construct class="org.apache.tapestry.services.impl.SpecificationSourceImpl">
-        <set-service property="parser" service-id="SpecificationParser"/>
-        <set-object property="specification" value="infrastructure:applicationSpecification"/>
-        <set-object property="assetSource" value="service:tapestry.asset.AssetSource"/>
-        <event-listener service-id="tapestry.ResetEventHub"/>
-        <event-listener service-id="tapestry.describe.ReportStatusHub"/>
-      </construct>
-    </invoke-factory>
-    
-  </service-point>
-  
-  <service-point id="TemplateParser" interface="ITemplateParser">
-    
-    Parses a template into a series of tokens that are used to construct a component's body.
-    
-    <invoke-factory model="threaded">
-      <construct class="TemplateParser">
-        <set-object property="factory" value="instance:TemplateTokenFactory"/>
-      </construct>
-    </invoke-factory>
-    
-  </service-point>
-  
-  <service-point id="TemplateSource" interface="org.apache.tapestry.services.TemplateSource">
-    
-    A smart cache for localized templates for pages and components.  Retrieves a template on
-    first reference, and returns it on subsequent references.
-    
-    
-    <invoke-factory>
-      <construct class="org.apache.tapestry.services.impl.TemplateSourceImpl">
-        <set-service property="parser" service-id="TemplateParser"/>
-        <set-service property="delegate" service-id="TemplateSourceDelegate"/>
-        <set-object property="contextRoot" value="infrastructure:contextRoot"/>
-        <set-object property="applicationId" value="infrastructure:applicationId"/>
-        <set-service property="componentSpecificationResolver" service-id="tapestry.page.ComponentSpecificationResolver"/>
-        <set-object property="componentPropertySource"  value="infrastructure:componentPropertySource"/>
-        <set-object property="localizer" value="infrastructure:resourceLocalizer"/>
-        <set-service property="contextAssetFactory" service-id="tapestry.asset.ContextAssetFactory" />
-        <set-service property="classpathAssetFactory" service-id="tapestry.asset.ClasspathAssetFactory" />
-        <event-listener service-id="tapestry.ResetEventHub"/>
-        <event-listener service-id="tapestry.describe.ReportStatusHub"/>
-      </construct>
-    </invoke-factory>
-    
-  </service-point>
-  
-  <service-point id="TemplateSourceDelegate" interface="org.apache.tapestry.engine.ITemplateSourceDelegate">
-    
-    Delegate for TemplateSource that knows how to find templates in unusual places.
-    
-    <invoke-factory service-id="tapestry.ExtensionLookupFactory">
-      <lookup extension-name="org.apache.tapestry.template-source-delegate"/>
-    </invoke-factory>
-    
-  </service-point>
-  
-  <contribution configuration-id="tapestry.Infrastructure">
-    <property name="templateSource" object="service:TemplateSource"/>
-    <property name="specificationSource" object="service:SpecificationSource"/>    
-  </contribution>
-  
+
+    Template and specification parsers.
+
+    <service-point id="SpecificationParser" interface="ISpecificationParser">
+
+        The parser for all types of specifications (page, component, library and application).
+
+        <!-- This one is constructed a little wierdly, to help maintain compatibility with Spindle. -->
+
+        <invoke-factory model="pooled">
+            <construct class="SpecificationParser" autowire-services="false">
+                <error-handler/>
+                <log/>
+                <class-resolver/>
+                <object> instance:org.apache.tapestry.spec.SpecFactory </object>
+
+                <!-- Can't use infrastructure:valueConverter, because SpecificationParser will be created earlier than
+               tapestry.Infrastructure -->
+
+                <set-service property="valueConverter" service-id="tapestry.coerce.ValueConverter"/>
+                <set-service property="bindingSource" service-id="tapestry.bindings.BindingSource"/>
+            </construct>
+        </invoke-factory>
+
+        <interceptor service-id="hivemind.LoggingInterceptor"/>
+    </service-point>
+
+    <service-point id="SpecificationSource" interface="org.apache.tapestry.engine.ISpecificationSource">
+
+        Used to obtain specifications for pages, components and libraries.
+
+        <invoke-factory>
+            <construct class="org.apache.tapestry.services.impl.SpecificationSourceImpl">
+                <set-service property="parser" service-id="SpecificationParser"/>
+                <set-object property="specification" value="infrastructure:applicationSpecification"/>
+                <set-object property="assetSource" value="service:tapestry.asset.AssetSource"/>
+                <event-listener service-id="tapestry.ResetEventHub"/>
+                <event-listener service-id="tapestry.describe.ReportStatusHub"/>
+            </construct>
+        </invoke-factory>
+
+    </service-point>
+
+    <service-point id="TemplateParser" interface="ITemplateParser">
+
+        Parses a template into a series of tokens that are used to construct a component's body.
+
+        <invoke-factory model="threaded">
+            <construct class="TemplateParser">
+                <set-object property="factory" value="instance:TemplateTokenFactory"/>
+            </construct>
+        </invoke-factory>
+
+    </service-point>
+
+    <service-point id="TemplateSource" interface="org.apache.tapestry.services.TemplateSource">
+
+        A smart cache for localized templates for pages and components.  Retrieves a template on
+        first reference, and returns it on subsequent references.
+
+        <invoke-factory>
+            <construct class="org.apache.tapestry.services.impl.TemplateSourceImpl">
+                <set-service property="parser" service-id="TemplateParser"/>
+                <set-service property="delegate" service-id="TemplateSourceDelegate"/>
+                <set-object property="contextRoot" value="infrastructure:contextRoot"/>
+                <set-service property="componentSpecificationResolver" service-id="tapestry.page.ComponentSpecificationResolver"/>
+                <set-object property="componentPropertySource"  value="infrastructure:componentPropertySource"/>
+                <set-object property="localizer" value="infrastructure:resourceLocalizer"/>
+                <set-service property="componentResourceResolver" service-id="tapestry.page.ComponentResourceResolver" />
+                <event-listener service-id="tapestry.ResetEventHub"/>
+                <event-listener service-id="tapestry.describe.ReportStatusHub"/>
+            </construct>
+        </invoke-factory>
+
+    </service-point>
+
+    <service-point id="TemplateSourceDelegate" interface="org.apache.tapestry.engine.ITemplateSourceDelegate">
+
+        Delegate for TemplateSource that knows how to find templates in unusual places.
+
+        <invoke-factory service-id="tapestry.ExtensionLookupFactory">
+            <lookup extension-name="org.apache.tapestry.template-source-delegate"/>
+        </invoke-factory>
+
+    </service-point>
+
+    <contribution configuration-id="tapestry.Infrastructure">
+        <property name="templateSource" object="service:TemplateSource"/>
+        <property name="specificationSource" object="service:SpecificationSource"/>
+    </contribution>
+
 </module>

Modified: tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/l10n/DefaultResourceLocalizer.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/l10n/DefaultResourceLocalizer.java?view=diff&rev=536045&r1=536044&r2=536045
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/l10n/DefaultResourceLocalizer.java (original)
+++ tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/l10n/DefaultResourceLocalizer.java Mon May  7 20:13:04 2007
@@ -14,17 +14,15 @@
 
 package org.apache.tapestry.l10n;
 
-import java.util.Locale;
-
 import org.apache.hivemind.Resource;
 
+import java.util.Locale;
+
 /**
  * Default implementation of {@link org.apache.tapestry.l10n.ResourceLocalizer} that leverages the
  * localization rules built into
  * {@link org.apache.hivemind.Resource#getLocalization(java.util.Locale)}.
  * 
- * @author Howard M. Lewis Ship
- * @since 4.0
  */
 public class DefaultResourceLocalizer implements ResourceLocalizer
 {

Added: tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/resolver/ComponentResourceResolverImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/resolver/ComponentResourceResolverImpl.java?view=auto&rev=536045
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/resolver/ComponentResourceResolverImpl.java (added)
+++ tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/resolver/ComponentResourceResolverImpl.java Mon May  7 20:13:04 2007
@@ -0,0 +1,165 @@
+package org.apache.tapestry.resolver;
+
+import org.apache.hivemind.Resource;
+import org.apache.hivemind.util.ContextResource;
+import org.apache.tapestry.IComponent;
+import org.apache.tapestry.IRequestCycle;
+import org.apache.tapestry.TapestryUtils;
+import org.apache.tapestry.asset.AssetFactory;
+import org.apache.tapestry.web.WebContextResource;
+
+import java.util.Locale;
+
+/**
+ * Implementation of {@link IComponentResourceResolver}.
+ */
+public class ComponentResourceResolverImpl implements IComponentResourceResolver {
+
+    /**
+     * Used to find resources under the context WEB-INF/ directory.
+     */
+    private static final String WEB_INF = "WEB-INF/";
+
+    private AssetFactory _classpathAssetFactory;
+    private AssetFactory _contextAssetFactory;
+
+    /** Application id of the current tapestry app - as in applicationId.application */
+    private String _applicationId;
+    
+    /** Root web context directory */
+    private Resource _contextRoot;
+    /** The location of the WEB-INF context directory */
+    private Resource _webInfLocation;
+    /** The location of the application within the WEB-INF/ folder */
+    private Resource _webInfAppLocation;
+
+    /**
+     * Called by hivemind automatically.
+     */
+    public void initializeService()
+    {
+        _webInfLocation = _contextRoot.getRelativeResource(WEB_INF);
+        
+        _webInfAppLocation = _webInfLocation.getRelativeResource(_applicationId + "/");
+    }
+
+    public Resource findComponentResource(IComponent component, IRequestCycle cycle, String path, String extension, Locale locale)
+    {
+        Resource base = component.getSpecification().getSpecificationLocation();
+        String baseName = path == null ? extractBaseName(base) : path;
+        Resource resource = null;
+
+        // have to do explicit check for context resource first
+        // as it might be a classpath based spec and then we need to manually figure out
+        // the best location to start from as context paths always get resolved first
+        // before classpath resources
+        
+        if (WebContextResource.class.isInstance(base) || ContextResource.class.isInstance(base))
+        {
+            resource = base.getRelativeResource(baseName + extension);
+
+            if (resource != null)
+                return localizeResource(resource, locale);
+        }
+
+        resource = findComponentClassResource(component, cycle, baseName, extension, locale);
+
+        // In some cases the generic classpath resource path is fine - such as bundled component properties
+
+        if (resource == null) {
+            
+            resource = base.getRelativeResource(baseName + extension);
+            
+            if (resource != null)
+                resource = localizeResource(resource, locale);
+        }
+
+        return resource;
+    }
+
+    String extractBaseName(Resource baseResourceLocation)
+    {
+        String fileName = baseResourceLocation.getName();
+        int dotx = fileName.lastIndexOf('.');
+
+        return dotx > -1 ? fileName.substring(0, dotx) : fileName;
+    }
+
+    Resource localizeResource(Resource resource, Locale locale)
+    {
+        if (locale == null)
+            return resource;
+
+        Resource localized = resource.getLocalization(locale);
+        if (localized != null && localized.getResourceURL() != null)
+            return localized;
+
+        return resource;
+    }
+
+    Resource findComponentClassResource(IComponent component, IRequestCycle cycle, String baseName, String extension, Locale locale)
+    {
+        Resource base = component.getSpecification().getSpecificationLocation();
+        String componentPackages = component.getNamespace().getPropertyValue("org.apache.tapestry.component-class-packages");
+
+        // this relies on finding things from the component class name
+
+        if (componentPackages == null)
+            return null;
+
+        String className = component.getSpecification().getComponentClassName();
+        if (className == null)
+            return null;
+
+        String[] packages = TapestryUtils.split(componentPackages);
+        for (int i=0; i < packages.length; i++)
+        {
+            // find matching package in class
+            int index = className.lastIndexOf(packages[i]);
+            if (index < 0)
+                continue;
+            
+            // First try context
+
+            String templateName = className.substring((index + packages[i].length()) + 1, className.length()).replaceAll("\\.", "/");
+            templateName =  templateName + extension;
+
+            if (_contextAssetFactory.assetExists(component.getSpecification(), _webInfAppLocation, templateName, locale)) {
+
+                return _contextAssetFactory.createAsset(_webInfAppLocation, component.getSpecification(),  templateName, locale, component.getLocation()).getResourceLocation();
+            } else if (_contextAssetFactory.assetExists(component.getSpecification(), _webInfLocation, templateName, locale)) {
+
+                return _contextAssetFactory.createAsset(_webInfLocation, component.getSpecification(), templateName, locale, component.getLocation()).getResourceLocation();
+            }
+
+            // else classpath
+
+            String resourceName = baseName + extension;
+
+            if (_classpathAssetFactory.assetExists(component.getSpecification(), base, resourceName, locale))
+                return _classpathAssetFactory.createAsset(base, component.getSpecification(), resourceName, locale, component.getLocation()).getResourceLocation();
+        }
+
+        return null;
+    }
+
+    public void setContextRoot(Resource contextRoot)
+    {
+        _contextRoot = contextRoot;
+    }
+
+    public void setClasspathAssetFactory(AssetFactory classpathAssetFactory)
+    {
+        _classpathAssetFactory = classpathAssetFactory;
+    }
+
+    public void setContextAssetFactory(AssetFactory contextAssetFactory)
+    {
+        _contextAssetFactory = contextAssetFactory;
+    }
+
+    public void setApplicationId(String applicationId)
+    {
+        _applicationId = applicationId;
+    }
+}

Propchange: tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/resolver/ComponentResourceResolverImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/resolver/IComponentResourceResolver.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/resolver/IComponentResourceResolver.java?view=auto&rev=536045
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/resolver/IComponentResourceResolver.java (added)
+++ tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/resolver/IComponentResourceResolver.java Mon May  7 20:13:04 2007
@@ -0,0 +1,36 @@
+package org.apache.tapestry.resolver;
+
+import org.apache.hivemind.Resource;
+import org.apache.tapestry.IComponent;
+import org.apache.tapestry.IRequestCycle;
+
+import java.util.Locale;
+
+/**
+ * Service responsible for finding resources relative or specific to a {@link org.apache.tapestry.IComponent}.
+ * 
+ */
+public interface IComponentResourceResolver {
+
+    /**
+     * Searches for a resource relative to the specified {@link IComponent}, optionally also attemping to
+     * find a localized version of the resource using the specified {@link Locale}.
+     * 
+     * @param component
+     *          The component to find the resource relative to.
+     * @param cycle
+     *          The current request.
+     * @param name
+     *          Optional resource name to search for, the default is to use the component name.
+     * @param extension
+     *          Extension name of the resource, such as &lt;ComponentName&gt;.properties for properties
+     *          / &lt;ComponentName&gt;.html for templates and so on.  
+     * @param locale
+     *          Optional localization specifier.
+     * 
+     * @return The resolved resource, or null if none could be found. The returned {@link Resource} may
+     *          also be not null but still not valid. To ensure validity check {@link org.apache.hivemind.Resource#getResourceURL()} for
+     *          a not null value.
+     */
+    Resource findComponentResource(IComponent component, IRequestCycle cycle, String name, String extension, Locale locale);
+}

Propchange: tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/resolver/IComponentResourceResolver.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/services/ClasspathResourceFactory.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/services/ClasspathResourceFactory.java?view=diff&rev=536045&r1=536044&r2=536045
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/services/ClasspathResourceFactory.java (original)
+++ tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/services/ClasspathResourceFactory.java Mon May  7 20:13:04 2007
@@ -18,9 +18,6 @@
 
 /**
  * Used to create new instances of {@link org.apache.hivemind.util.ClasspathResource}.
- *
- * @author Howard Lewis Ship
- * @since 4.0
  */
 public interface ClasspathResourceFactory
 {

Modified: tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/services/impl/ComponentMessagesSourceImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/services/impl/ComponentMessagesSourceImpl.java?view=diff&rev=536045&r1=536044&r2=536045
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/services/impl/ComponentMessagesSourceImpl.java (original)
+++ tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/services/impl/ComponentMessagesSourceImpl.java Mon May  7 20:13:04 2007
@@ -23,6 +23,7 @@
 import org.apache.tapestry.IComponent;
 import org.apache.tapestry.INamespace;
 import org.apache.tapestry.event.ResetEventListener;
+import org.apache.tapestry.resolver.IComponentResourceResolver;
 import org.apache.tapestry.services.ClasspathResourceFactory;
 import org.apache.tapestry.services.ComponentMessagesSource;
 import org.apache.tapestry.services.ComponentPropertySource;
@@ -36,7 +37,7 @@
 
 /**
  * Service used to access localized properties for a component.
- * 
+ *
  * @author Howard Lewis Ship
  * @since 2.0.4
  */
@@ -49,16 +50,16 @@
      */
 
     public static final String MESSAGES_ENCODING_PROPERTY_NAME = "org.apache.tapestry.messages-encoding";
-    
+
     /**
      * The alternate file name of a namespace properties file to lookup. Can be used to override the default
      * behaviour which is to look for a &lt;namespace name&gt;.properties file to find localized/global properties.
      */
-    
+
     public static final String NAMESPACE_PROPERTIES_NAME = "org.apache.tapestry.namespace-properties-name";
-    
+
     private static final String SUFFIX = ".properties";
-    
+
     private Properties _emptyProperties = new Properties();
 
     /**
@@ -75,7 +76,9 @@
      * For locating resources on the classpath as well as context path.
      */
     private ClasspathResourceFactory _classpathResourceFactory;
-    
+
+    private IComponentResourceResolver _resourceResolver;
+
     /**
      * Returns an instance of {@link Properties}containing the properly
      * localized messages for the component, in the {@link Locale}identified by
@@ -87,19 +90,19 @@
         Defense.notNull(component, "component");
 
         Resource specificationLocation = component.getSpecification().getSpecificationLocation();
-        
+
         Locale locale = component.getPage().getLocale();
-        
+
         Map propertiesMap = findPropertiesMapForResource(specificationLocation);
-        
+
         Properties result = (Properties) propertiesMap.get(locale);
 
         if (result == null)
         {
             // Not found, create it now.
-            
+
             result = assembleComponentProperties(component, specificationLocation, propertiesMap, locale);
-            
+
             propertiesMap.put(locale, result);
         }
 
@@ -122,13 +125,13 @@
     private Properties getNamespaceProperties(IComponent component, Locale locale)
     {
         INamespace namespace = component.getNamespace();
-        
+
         Resource namespaceLocation = namespace.getSpecificationLocation();
-        
+
         Map propertiesMap = findPropertiesMapForResource(namespaceLocation);
-        
+
         Properties result = (Properties) propertiesMap.get(locale);
-        
+
         if (result == null)
         {
             result = assembleNamespaceProperties(namespace, propertiesMap, locale);
@@ -139,12 +142,12 @@
         return result;
     }
 
-    private Properties assembleComponentProperties(IComponent component, Resource baseResourceLocation, 
-            Map propertiesMap, Locale locale)
+    private Properties assembleComponentProperties(IComponent component, Resource baseResourceLocation,
+                                                   Map propertiesMap, Locale locale)
     {
-        List localizations =  findLocalizationsForResource(baseResourceLocation, locale, 
-                component.getSpecification().getProperty(NAMESPACE_PROPERTIES_NAME));
-        
+        List localizations =  findLocalizationsForResource(component, baseResourceLocation, locale,
+                                                           component.getSpecification().getProperty(NAMESPACE_PROPERTIES_NAME));
+
         Properties parent = null;
         Properties assembledProperties = null;
 
@@ -169,31 +172,34 @@
             // Override parent properties with current locale
             if (parent != null)
             {
-                if (properties != null) 
+                if (properties != null)
                     parent.putAll(properties);
             }
-            else 
+            else
                 parent = properties;
 
             // Add to assembled properties
-            if (parent != null) 
+            if (parent != null)
                 assembledProperties.putAll(parent);
 
             // Save result in cache
             propertiesMap.put(l, assembledProperties);
         }
 
+        if (assembledProperties == null)
+            assembledProperties = new Properties();
+
         return assembledProperties;
     }
 
     private Properties assembleNamespaceProperties(INamespace namespace,
-            Map propertiesMap, Locale locale)
+                                                   Map propertiesMap, Locale locale)
     {
-        List localizations = findLocalizationsForResource(namespace.getSpecificationLocation(), locale, 
-                    namespace.getPropertyValue(NAMESPACE_PROPERTIES_NAME));
-        
+        List localizations = findLocalizationsForResource(namespace.getSpecificationLocation(), locale,
+                                                          namespace.getPropertyValue(NAMESPACE_PROPERTIES_NAME));
+
         // Build them back up in reverse order.
-        
+
         Properties parent = _emptyProperties;
 
         Iterator i = localizations.iterator();
@@ -209,7 +215,7 @@
             if (properties == null)
             {
                 properties = readNamespaceProperties(namespace, l, rl.getResource(), parent);
-                
+
                 propertiesMap.put(l, properties);
             }
 
@@ -230,30 +236,62 @@
     private List findLocalizationsForResource(Resource resource, Locale locale, String alternateName)
     {
         List result = new ArrayList();
-        
+
         String baseName = null;
         if (alternateName != null) {
-            
+
             baseName = alternateName.replace('.', '/');
         } else {
-            
+
             baseName = extractBaseName(resource);
         }
-        
+
         LocalizedNameGenerator g = new LocalizedNameGenerator(baseName, locale, SUFFIX);
-        
+
         while(g.more())
         {
             String localizedName = g.next();
             Locale l = g.getCurrentLocale();
-            
+
             Resource localizedResource = resource.getRelativeResource(localizedName);
-            
+
             if (localizedResource.getResourceURL() == null) {
-                
+
                 localizedResource = _classpathResourceFactory.newResource(baseName + SUFFIX);
             }
-            
+
+            result.add(new ResourceLocalization(l, localizedResource));
+        }
+
+        Collections.reverse(result);
+
+        return result;
+    }
+
+    private List findLocalizationsForResource(IComponent component, Resource resource, Locale locale, String alternateName)
+    {
+        List result = new ArrayList();
+
+        String baseName = null;
+        if (alternateName != null) {
+
+            baseName = alternateName.replace('.', '/');
+        } else {
+
+            baseName = extractBaseName(resource);
+        }
+
+        LocalizedNameGenerator g = new LocalizedNameGenerator(baseName, locale, "");
+
+        while(g.more())
+        {
+            String localizedName = g.next();
+            Locale l = g.getCurrentLocale();
+
+            Resource localizedResource = _resourceResolver.findComponentResource(component, null, localizedName, SUFFIX, null);
+            if (localizedResource == null)
+                continue;
+
             result.add(new ResourceLocalization(l, localizedResource));
         }
 
@@ -271,18 +309,18 @@
     }
 
     private Properties readComponentProperties(IComponent component,
-            Locale locale, Resource propertiesResource, Properties parent)
+                                               Locale locale, Resource propertiesResource, Properties parent)
     {
         String encoding = getComponentMessagesEncoding(component, locale);
-        
+
         return readPropertiesResource(propertiesResource.getResourceURL(), encoding, parent);
     }
-    
+
     private Properties readNamespaceProperties(INamespace namespace,
-            Locale locale, Resource propertiesResource, Properties parent)
+                                               Locale locale, Resource propertiesResource, Properties parent)
     {
         String encoding = getNamespaceMessagesEncoding(namespace, locale);
-        
+
         return readPropertiesResource(propertiesResource.getResourceURL(), encoding, parent);
     }
 
@@ -290,11 +328,11 @@
     {
         if (resourceURL == null)
             return parent;
-        
+
         Properties result = new Properties(parent);
-        
+
         LocalizedProperties wrapper = new LocalizedProperties(result);
-        
+
         InputStream input = null;
 
         try
@@ -303,15 +341,14 @@
 
             if (encoding == null)
                 wrapper.load(input);
-            else 
+            else
                 wrapper.load(input, encoding);
 
             input.close();
         }
         catch (IOException ex)
         {
-            throw new ApplicationRuntimeException(ImplMessages
-                    .unableToLoadProperties(resourceURL, ex), ex);
+            throw new ApplicationRuntimeException(ImplMessages.unableToLoadProperties(resourceURL, ex), ex);
         }
         finally
         {
@@ -345,14 +382,14 @@
     public Messages getMessages(IComponent component)
     {
         return new ComponentMessages(component.getPage().getLocale(),
-                getLocalizedProperties(component));
+                                     getLocalizedProperties(component));
     }
 
     private String getComponentMessagesEncoding(IComponent component,
-            Locale locale)
+                                                Locale locale)
     {
         String encoding = _componentPropertySource.getLocalizedComponentProperty(component, locale,
-                        MESSAGES_ENCODING_PROPERTY_NAME);
+                                                                                 MESSAGES_ENCODING_PROPERTY_NAME);
 
         if (encoding == null)
             encoding = _componentPropertySource.getLocalizedComponentProperty(
@@ -363,7 +400,7 @@
     }
 
     private String getNamespaceMessagesEncoding(INamespace namespace,
-            Locale locale)
+                                                Locale locale)
     {
         return _componentPropertySource.getLocalizedNamespaceProperty(
                 namespace, locale, MESSAGES_ENCODING_PROPERTY_NAME);
@@ -373,9 +410,14 @@
     {
         _componentPropertySource = componentPropertySource;
     }
-    
+
     public void setClasspathResourceFactory(ClasspathResourceFactory factory)
     {
         _classpathResourceFactory = factory;
+    }
+
+    public void setComponentResourceResolver(IComponentResourceResolver resourceResolver)
+    {
+        _resourceResolver = resourceResolver;
     }
 }

Modified: tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/services/impl/ComponentPropertySourceImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/services/impl/ComponentPropertySourceImpl.java?view=diff&rev=536045&r1=536044&r2=536045
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/services/impl/ComponentPropertySourceImpl.java (original)
+++ tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/services/impl/ComponentPropertySourceImpl.java Mon May  7 20:13:04 2007
@@ -14,12 +14,6 @@
 
 package org.apache.tapestry.services.impl;
 
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-
 import org.apache.hivemind.Resource;
 import org.apache.hivemind.lib.chain.ChainBuilder;
 import org.apache.tapestry.IComponent;
@@ -30,6 +24,8 @@
 import org.apache.tapestry.spec.IComponentSpecification;
 import org.apache.tapestry.util.PropertyHolderPropertySource;
 
+import java.util.*;
+
 /**
  * Implementation of tapestry.props.ComponentPropertySource.
  * <p>
@@ -94,8 +90,7 @@
     {
         Resource key = component.getSpecification().getSpecificationLocation();
 
-        LocalizedPropertySource result = (LocalizedPropertySource) _localizedComponentSources
-                .get(key);
+        LocalizedPropertySource result = (LocalizedPropertySource) _localizedComponentSources.get(key);
 
         if (result == null)
         {
@@ -111,8 +106,7 @@
     {
         Resource key = namespace.getSpecificationLocation();
 
-        LocalizedPropertySource result = (LocalizedPropertySource) _localizedNamespaceSources
-                .get(key);
+        LocalizedPropertySource result = (LocalizedPropertySource) _localizedNamespaceSources.get(key);
 
         if (result == null)
         {

Modified: tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/services/impl/ComponentTemplateLoaderImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/services/impl/ComponentTemplateLoaderImpl.java?view=diff&rev=536045&r1=536044&r2=536045
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/services/impl/ComponentTemplateLoaderImpl.java (original)
+++ tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/services/impl/ComponentTemplateLoaderImpl.java Mon May  7 20:13:04 2007
@@ -55,8 +55,7 @@
     {
         ComponentTemplate template = _templateSource.getTemplate(requestCycle, loadComponent);
 
-        ComponentTemplateLoaderLogic logic =
-                new ComponentTemplateLoaderLogic(_log, _pageLoader, _bindingSource);
+        ComponentTemplateLoaderLogic logic = new ComponentTemplateLoaderLogic(_log, _pageLoader, _bindingSource);
 
         logic.loadTemplate(requestCycle, loadComponent, template);
     }

Modified: tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/services/impl/ComponentTemplateLoaderLogic.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/services/impl/ComponentTemplateLoaderLogic.java?view=diff&rev=536045&r1=536044&r2=536045
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/services/impl/ComponentTemplateLoaderLogic.java (original)
+++ tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/services/impl/ComponentTemplateLoaderLogic.java Mon May  7 20:13:04 2007
@@ -37,9 +37,7 @@
  * Contains the logic from {@link org.apache.tapestry.services.impl.ComponentTemplateLoaderImpl},
  * which creates one of these instances to process the request. This is necessary because the
  * service must be re-entrant (because templates can contain components that have templates).
- * 
- * @author Howard Lewis Ship
- * @since 4.0
+ *
  */
 public class ComponentTemplateLoaderLogic
 {
@@ -69,7 +67,7 @@
     }
 
     public void loadTemplate(IRequestCycle requestCycle, ITemplateComponent loadComponent,
-            ComponentTemplate template)
+                             ComponentTemplate template)
     {
         _requestCycle = requestCycle;
         _loadComponent = loadComponent;
@@ -110,7 +108,6 @@
             if (type == TokenType.LOCALIZATION)
             {
                 process((LocalizationToken) token);
-                continue;
             }
         }
 
@@ -118,8 +115,8 @@
         // of date, too.
 
         if (_stackx != 0)
-            throw new ApplicationRuntimeException(Tapestry
-                    .getMessage("BaseComponent.unbalance-open-tags"), _loadComponent, null, null);
+            throw new ApplicationRuntimeException(Tapestry.getMessage("BaseComponent.unbalance-open-tags"),
+                                                  _loadComponent, null, null);
 
         checkAllComponentsReferenced();
     }
@@ -142,7 +139,7 @@
 
         if (!_activeComponent.getSpecification().getAllowBody())
             throw createBodylessComponentException(_activeComponent);
-        
+
         _activeComponent.addBody(token);
     }
 
@@ -164,9 +161,8 @@
         // Make sure the template contains each component only once.
 
         if (_seenIds.contains(id))
-            throw new ApplicationRuntimeException(ImplMessages.multipleComponentReferences(
-                    _loadComponent,
-                    id), _loadComponent, token.getLocation(), null);
+            throw new ApplicationRuntimeException(ImplMessages.multipleComponentReferences(_loadComponent,id),
+                                                  _loadComponent, token.getLocation(), null);
 
         _seenIds.add(id);
 
@@ -179,7 +175,7 @@
 
             if (!_activeComponent.getSpecification().getAllowBody())
                 throw createBodylessComponentException(_activeComponent);
-            
+
             _activeComponent.addBody(component);
         }
 
@@ -199,19 +195,17 @@
 
         if (cc != null)
             throw new ApplicationRuntimeException(ImplMessages.dupeComponentId(id, cc),
-                    _loadComponent, location, null);
+                                                  _loadComponent, location, null);
     }
 
     private IComponent createImplicitComponent(String id, String componentType, Location location)
     {
-        IComponent result = _pageLoader.createImplicitComponent(
+        return _pageLoader.createImplicitComponent(
                 _requestCycle,
                 _loadComponent,
                 id,
                 componentType,
                 location);
-
-        return result;
     }
 
     private IComponent getEmbeddedComponent(String id)
@@ -226,7 +220,7 @@
 
         if (_stackx <= 0)
             throw new ApplicationRuntimeException(ImplMessages.unbalancedCloseTags(),
-                    _loadComponent, token.getLocation(), null);
+                                                  _loadComponent, token.getLocation(), null);
 
         // Null and forget the top element on the stack.
 
@@ -252,9 +246,9 @@
     void addTemplateBindings(IComponent component, OpenToken token)
     {
         // sets the html tag name used to specify the component
-        
+
         component.setTemplateTagName(token.getTag());
-        
+
         IComponentSpecification spec = component.getSpecification();
 
         Map attributes = token.getAttributesMap();
@@ -299,7 +293,7 @@
         // add a static binding carrying the template tag
 
         if (spec.getParameter(TemplateSource.TEMPLATE_TAG_PARAMETER_NAME) != null
-                && component.getBinding(TemplateSource.TEMPLATE_TAG_PARAMETER_NAME) == null)
+            && component.getBinding(TemplateSource.TEMPLATE_TAG_PARAMETER_NAME) == null)
         {
             IBinding binding = _bindingSource.createBinding(
                     component,
@@ -318,8 +312,8 @@
      * It is an error to specify expression bindings in both the specification and the template.
      */
 
-    private void addBinding(IComponent component, IComponentSpecification spec, String name,
-            IBinding binding)
+    private void addBinding(IComponent component, IComponentSpecification spec,
+                            String name, IBinding binding)
     {
 
         // If matches a formal parameter name, allow it to be set
@@ -331,8 +325,8 @@
             component.setBinding(name, binding);
     }
 
-    private boolean validate(IComponent component, IComponentSpecification spec, String name,
-            IBinding binding)
+    private boolean validate(IComponent component, IComponentSpecification spec,
+                             String name, IBinding binding)
     {
         // TODO: This is ugly! Need a better/smarter way, even if we have to extend BindingSource
         // to tell us.
@@ -351,9 +345,8 @@
                 if (isLiteral)
                     return false;
 
-                throw new ApplicationRuntimeException(ImplMessages
-                        .templateBindingForInformalParameter(_loadComponent, name, component),
-                        component, binding.getLocation(), null);
+                throw new ApplicationRuntimeException(ImplMessages.templateBindingForInformalParameter(_loadComponent, name, component),
+                                                      component, binding.getLocation(), null);
             }
 
             // If the name is reserved (matches a formal parameter
@@ -367,9 +360,8 @@
                 if (isLiteral)
                     return false;
 
-                throw new ApplicationRuntimeException(ImplMessages
-                        .templateBindingForReservedParameter(_loadComponent, name, component),
-                        component, binding.getLocation(), null);
+                throw new ApplicationRuntimeException(ImplMessages.templateBindingForReservedParameter(_loadComponent, name, component),
+                                                      component, binding.getLocation(), null);
             }
         }
 
@@ -424,7 +416,6 @@
 
     private ApplicationRuntimeException createBodylessComponentException(IComponent component)
     {
-        return new ApplicationRuntimeException(ImplMessages.bodylessComponent(), component, null,
-                null);
+        return new ApplicationRuntimeException(ImplMessages.bodylessComponent(), component, null, null);
     }
 }

Modified: tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/services/impl/TemplateSourceImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/services/impl/TemplateSourceImpl.java?view=diff&rev=536045&r1=536044&r2=536045
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/services/impl/TemplateSourceImpl.java (original)
+++ tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/services/impl/TemplateSourceImpl.java Mon May  7 20:13:04 2007
@@ -19,7 +19,6 @@
 import org.apache.hivemind.ApplicationRuntimeException;
 import org.apache.hivemind.Resource;
 import org.apache.tapestry.*;
-import org.apache.tapestry.asset.AssetFactory;
 import org.apache.tapestry.engine.ITemplateSourceDelegate;
 import org.apache.tapestry.event.ReportStatusEvent;
 import org.apache.tapestry.event.ReportStatusListener;
@@ -27,6 +26,7 @@
 import org.apache.tapestry.l10n.ResourceLocalizer;
 import org.apache.tapestry.parse.*;
 import org.apache.tapestry.resolver.ComponentSpecificationResolver;
+import org.apache.tapestry.resolver.IComponentResourceResolver;
 import org.apache.tapestry.services.ComponentPropertySource;
 import org.apache.tapestry.services.TemplateSource;
 import org.apache.tapestry.spec.IComponentSpecification;
@@ -56,8 +56,6 @@
 
     public static final String TEMPLATE_ENCODING_PROPERTY_NAME = "org.apache.tapestry.template-encoding";
 
-    private static final String WEB_INF = "WEB-INF/";
-
     private static final int BUFFER_SIZE = 2000;
 
     private String _serviceId;
@@ -98,23 +96,8 @@
     private ResourceLocalizer _localizer;
 
     /** @since 4.1.2 */
-    private AssetFactory _classpathAssetFactory;
-
-    /** @since 4.1.2 */
-    private AssetFactory _contextAssetFactory;
-
-    private String _applicationId;
-
-    private Resource _webInfLocation;
-
-    private Resource _webInfAppLocation;
-
-    public void initializeService()
-    {
-        _webInfLocation = _contextRoot.getRelativeResource(WEB_INF);
-
-        _webInfAppLocation = _webInfLocation.getRelativeResource(_applicationId + "/");
-    }
+    
+    private IComponentResourceResolver _resourceResolver;
 
     /**
      * Clears the template cache. This is used during debugging.
@@ -246,7 +229,7 @@
         IAsset templateAsset = component.getAsset(TEMPLATE_ASSET_NAME);
 
         if (templateAsset != null)
-            return readTemplateFromAsset(cycle, component, templateAsset);
+            return readTemplateFromAsset(cycle, component, templateAsset.getResourceLocation());
 
         String name = resource.getName();
         int dotx = name.lastIndexOf('.');
@@ -269,57 +252,16 @@
                     locale);
 
         if (result == null) {
+
+            Resource template = _resourceResolver.findComponentResource(component, cycle, null, "." + templateExtension, locale);
             
-            templateAsset = findSpeclessTemplate(cycle, resource, component, locale, templateExtension);
-            
-            if (templateAsset != null)
-                return readTemplateFromAsset(cycle, component, templateAsset);
+            if (template != null)
+                return readTemplateFromAsset(cycle, component, template);
         }
 
         return result;
     }
 
-    private IAsset findSpeclessTemplate(IRequestCycle cycle, Resource base,
-                                                   IComponent component, Locale locale, String templateExtension)
-    {
-        String componentPackages = component.getNamespace().getPropertyValue("org.apache.tapestry.component-class-packages");
-        if (componentPackages == null)
-            return null;
-
-        String name = base.getName();
-        String className = component.getSpecification().getComponentClassName();
-
-        String[] packages = TapestryUtils.split(componentPackages);
-        for (int i=0; i < packages.length; i++)
-        {
-            int index = className.lastIndexOf(packages[i]);
-            if (index < 0)
-                continue;
-            
-            // First try context
-
-            String templateName = className.substring((index + packages[i].length()) + 1, className.length()).replaceAll("\\.", "/");
-            templateName =  templateName + "." + templateExtension;
-
-            if (_contextAssetFactory.assetExists(component.getSpecification(), _webInfAppLocation, templateName, locale)) {
-
-                return _contextAssetFactory.createAsset(_webInfAppLocation, component.getSpecification(),  templateName, locale, component.getLocation());
-            } else if (_contextAssetFactory.assetExists(component.getSpecification(), _webInfLocation, templateName, locale)) {
-
-                return _contextAssetFactory.createAsset(_webInfLocation, component.getSpecification(), templateName, locale, component.getLocation());
-            }
-
-            // else classpath
-
-            templateName = name + "." + templateExtension;
-
-            if (_classpathAssetFactory.assetExists(component.getSpecification(), base, templateName, locale))
-                return _classpathAssetFactory.createAsset(base, component.getSpecification(), templateName, locale, component.getLocation());
-        }
-        
-        return null;
-    }
-
     private ComponentTemplate findPageTemplateInApplicationRoot(IRequestCycle cycle, IPage page,
             String templateExtension, Locale locale)
     {
@@ -345,19 +287,23 @@
         return getOrParseTemplate(cycle, localizedLocation, page);
     }
 
+
+
     /**
      * Reads an asset to get the template.
      */
 
     private ComponentTemplate readTemplateFromAsset(IRequestCycle cycle, IComponent component,
-            IAsset asset)
+            Resource asset)
     {
-        InputStream stream = asset.getResourceAsStream();
+        InputStream stream = null;
 
         char[] templateData = null;
 
         try
         {
+            stream = asset.getResourceURL().openStream();
+
             String encoding = getTemplateEncoding(component, null);
 
             templateData = readTemplateStream(stream, encoding);
@@ -369,9 +315,7 @@
             throw new ApplicationRuntimeException(ImplMessages.unableToReadTemplate(asset), ex);
         }
 
-        Resource resourceLocation = asset.getResourceLocation();
-
-        return constructTemplateInstance(cycle, templateData, resourceLocation, component);
+        return constructTemplateInstance(cycle, templateData, asset, component);
     }
 
     /**
@@ -635,20 +579,8 @@
         _localizer = localizer;
     }
 
-    /** @since 4.1.2 */
-    public void setClasspathAssetFactory(AssetFactory classpathAssetFactory)
-    {
-        _classpathAssetFactory = classpathAssetFactory;
-    }
-
-    /** @since 4.1.2 */
-    public void setContextAssetFactory(AssetFactory contextAssetFactory)
-    {
-        _contextAssetFactory = contextAssetFactory;
-    }
-
-    public void setApplicationId(String applicationId)
+    public void setComponentResourceResolver(IComponentResourceResolver resourceResolver)
     {
-        _applicationId = applicationId;
+        _resourceResolver = resourceResolver;
     }
 }

Modified: tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/web/LocalizedWebContextResourceFinder.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/web/LocalizedWebContextResourceFinder.java?view=diff&rev=536045&r1=536044&r2=536045
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/web/LocalizedWebContextResourceFinder.java (original)
+++ tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/web/LocalizedWebContextResourceFinder.java Mon May  7 20:13:04 2007
@@ -73,8 +73,7 @@
             String candidatePath = generator.next();
 
             if (isExistingResource(candidatePath))
-                return new LocalizedResource(candidatePath, generator
-                        .getCurrentLocale());
+                return new LocalizedResource(candidatePath, generator.getCurrentLocale());
         }
 
         return null;

Modified: tapestry/tapestry4/trunk/tapestry-framework/src/test/org/apache/tapestry/junit/TestComponentMessages.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/test/org/apache/tapestry/junit/TestComponentMessages.java?view=diff&rev=536045&r1=536044&r2=536045
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/src/test/org/apache/tapestry/junit/TestComponentMessages.java (original)
+++ tapestry/tapestry4/trunk/tapestry-framework/src/test/org/apache/tapestry/junit/TestComponentMessages.java Mon May  7 20:13:04 2007
@@ -14,11 +14,6 @@
 
 package org.apache.tapestry.junit;
 
-import java.util.Calendar;
-import java.util.Date;
-import java.util.GregorianCalendar;
-import java.util.Locale;
-
 import org.apache.hivemind.Location;
 import org.apache.hivemind.Messages;
 import org.apache.hivemind.Resource;
@@ -34,6 +29,7 @@
 import org.apache.tapestry.enhance.InjectMessagesWorker;
 import org.apache.tapestry.enhance.InjectSpecificationWorker;
 import org.apache.tapestry.html.BasePage;
+import org.apache.tapestry.resolver.ComponentResourceResolverImpl;
 import org.apache.tapestry.services.ComponentMessagesSource;
 import org.apache.tapestry.services.ComponentPropertySource;
 import org.apache.tapestry.services.impl.ClasspathResourceFactoryImpl;
@@ -44,6 +40,11 @@
 import org.apache.tapestry.spec.LibrarySpecification;
 import org.testng.annotations.Test;
 
+import java.util.Calendar;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.Locale;
+
 /**
  * Tests the class {@link org.apache.tapestry.services.impl.ComponentMessagesSourceImpl}.
  * <p>
@@ -105,7 +106,6 @@
         String actual = messages.getMessage(key);
 
         assertEquals(expected, actual);
-
     }
 
     private static final String MOCK1 = "/org/apache/tapestry/junit/MockPage1.page";
@@ -164,6 +164,7 @@
         ComponentMessagesSourceImpl source = new ComponentMessagesSourceImpl();
         source.setClasspathResourceFactory(new ClasspathResourceFactoryImpl(new DefaultClassResolver()));
         source.setComponentPropertySource(new NullComponentPropertySource());
+        source.setComponentResourceResolver(new ComponentResourceResolverImpl());
 
         IComponentSpecification spec = newSpec(location);
         spec.setLocation(_locationFixture);
@@ -182,6 +183,7 @@
         ComponentMessagesSourceImpl source = new ComponentMessagesSourceImpl();
         source.setClasspathResourceFactory(new ClasspathResourceFactoryImpl(new DefaultClassResolver()));
         source.setComponentPropertySource(new NullComponentPropertySource());
+        source.setComponentResourceResolver(new ComponentResourceResolverImpl());
 
         IComponentSpecification spec = newSpec(location);
         spec.setLocation(_locationFixture);
@@ -353,6 +355,7 @@
         ComponentMessagesSourceImpl source = new ComponentMessagesSourceImpl();
         source.setClasspathResourceFactory(new ClasspathResourceFactoryImpl(new DefaultClassResolver()));
         source.setComponentPropertySource(new NullComponentPropertySource());
+        source.setComponentResourceResolver(new ComponentResourceResolverImpl());
 
         IComponentSpecification spec = newSpec(MOCK1);
         spec.setLocation(_locationFixture);

Added: tapestry/tapestry4/trunk/tapestry-framework/src/test/org/apache/tapestry/resolver/TestComponentResourceResolver.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/test/org/apache/tapestry/resolver/TestComponentResourceResolver.java?view=auto&rev=536045
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/src/test/org/apache/tapestry/resolver/TestComponentResourceResolver.java (added)
+++ tapestry/tapestry4/trunk/tapestry-framework/src/test/org/apache/tapestry/resolver/TestComponentResourceResolver.java Mon May  7 20:13:04 2007
@@ -0,0 +1,239 @@
+package org.apache.tapestry.resolver;
+
+import org.apache.hivemind.Location;
+import org.apache.hivemind.Resource;
+import org.apache.hivemind.impl.DefaultClassResolver;
+import org.apache.hivemind.util.ClasspathResource;
+import org.apache.tapestry.*;
+import org.apache.tapestry.asset.AssetFactory;
+import org.apache.tapestry.spec.ComponentSpecification;
+import org.apache.tapestry.spec.IComponentSpecification;
+import org.apache.tapestry.web.WebContext;
+import org.apache.tapestry.web.WebContextResource;
+import static org.easymock.EasyMock.checkOrder;
+import static org.easymock.EasyMock.expect;
+import org.testng.annotations.Test;
+
+import java.net.URL;
+import java.util.Locale;
+
+/**
+ * Tests functionality of {@link ComponentResourceResolverImpl}.
+ */
+@Test
+public class TestComponentResourceResolver extends TestBase {
+
+    public void test_Context_Spec_Resource()
+    {
+        IComponent comp = newMock(IComponent.class);
+        checkOrder(comp, false);
+        WebContext context = newMock(WebContext.class);
+        IRequestCycle cycle = newMock(IRequestCycle.class);
+
+        IComponentSpecification spec = new ComponentSpecification();
+        WebContextResource base = new WebContextResource(context, "/WEB-INF/MyComponent.jwc");
+        spec.setSpecificationLocation(base);
+        
+        ComponentResourceResolverImpl resolver = new ComponentResourceResolverImpl();
+
+        expect(comp.getSpecification()).andReturn(spec).anyTimes();
+        expect(context.getResource("/WEB-INF/MyComponent.html")).andReturn(newURL());
+
+        replay();
+
+        Resource resolved = resolver.findComponentResource(comp, cycle, null, ".html", null);
+        assert resolved != null;
+        assert resolved.getResourceURL() != null;
+
+        verify();
+    }
+
+    public void test_Context_Spec_Localized_Resource()
+    {
+        IComponent comp = newMock(IComponent.class);
+        checkOrder(comp, false);
+        WebContext context = newMock(WebContext.class);
+        IRequestCycle cycle = newMock(IRequestCycle.class);
+
+        IComponentSpecification spec = new ComponentSpecification();
+        WebContextResource base = new WebContextResource(context, "/WEB-INF/MyComponent.jwc");
+        spec.setSpecificationLocation(base);
+
+        ComponentResourceResolverImpl resolver = new ComponentResourceResolverImpl();
+
+        expect(comp.getSpecification()).andReturn(spec).anyTimes();
+        expect(context.getResource("/WEB-INF/MyComponent_en.html")).andReturn(newURL()).anyTimes();
+        expect(context.getResource("/WEB-INF/MyComponent_en_US.html")).andReturn(null);
+
+        replay();
+
+        Resource resolved = resolver.findComponentResource(comp, cycle, null, ".html", Locale.US);
+        assert resolved != null;
+        assert resolved.getResourceURL() != null;
+        
+        verify();
+    }
+
+    public void test_Classpath_Spec_Resource_App_Context_Resolved()
+    {
+        IComponent comp = newMock(IComponent.class);
+        checkOrder(comp, false);
+
+        INamespace namespace = newMock(INamespace.class);
+        IRequestCycle cycle = newMock(IRequestCycle.class);
+
+        IComponentSpecification spec = new ComponentSpecification();
+        ClasspathResource base = new ClasspathResource(new DefaultClassResolver(), "/org/apache/tapestry/resolver/MyComponent.jwc");
+        spec.setSpecificationLocation(base);
+        spec.setComponentClassName("org.apache.tapestry.resolver.MyComponent");
+
+        AssetFactory classpathFactory = newMock(AssetFactory.class);
+        AssetFactory contextFactory = newMock(AssetFactory.class);
+        Resource contextRoot = newMock(Resource.class);
+        Resource webinfLocation = newMock(Resource.class);
+        Resource webinfAppLocation = newMock(Resource.class);
+
+        ComponentResourceResolverImpl resolver = new ComponentResourceResolverImpl();
+        resolver.setApplicationId("foo");
+        resolver.setClasspathAssetFactory(classpathFactory);
+        resolver.setContextAssetFactory(contextFactory);
+        resolver.setContextRoot(contextRoot);
+        
+        expect(contextRoot.getRelativeResource("WEB-INF/")).andReturn(webinfLocation);
+        expect(webinfLocation.getRelativeResource("foo/")).andReturn(webinfAppLocation);
+
+        expect(comp.getSpecification()).andReturn(spec).anyTimes();
+        expect(comp.getNamespace()).andReturn(namespace);
+        expect(namespace.getPropertyValue("org.apache.tapestry.component-class-packages")).andReturn("org.apache.tapestry.resolver");
+
+        Location l = newMock(Location.class);
+        IAsset asset = newMock(IAsset.class);
+        Resource resource = newMock(Resource.class);
+        
+        expect(contextFactory.assetExists(spec, webinfAppLocation, "MyComponent.html", null)).andReturn(true);
+        expect(comp.getLocation()).andReturn(l);
+        expect(contextFactory.createAsset(webinfAppLocation, spec, "MyComponent.html", null, l)).andReturn(asset);
+        expect(asset.getResourceLocation()).andReturn(resource);
+
+        replay();
+
+        resolver.initializeService();
+
+        Resource resolved = resolver.findComponentResource(comp, cycle, null, ".html", null);
+        assertEquals(resolved, resource);
+
+        verify();
+    }
+
+    public void test_Classpath_Spec_Resource_WebInf_Context_Resolved()
+    {
+        IComponent comp = newMock(IComponent.class);
+        checkOrder(comp, false);
+
+        INamespace namespace = newMock(INamespace.class);
+        IRequestCycle cycle = newMock(IRequestCycle.class);
+
+        IComponentSpecification spec = new ComponentSpecification();
+        ClasspathResource base = new ClasspathResource(new DefaultClassResolver(), "/org/apache/tapestry/resolver/MyComponent.jwc");
+        spec.setSpecificationLocation(base);
+        spec.setComponentClassName("org.apache.tapestry.resolver.MyComponent");
+
+        AssetFactory classpathFactory = newMock(AssetFactory.class);
+        AssetFactory contextFactory = newMock(AssetFactory.class);
+        Resource contextRoot = newMock(Resource.class);
+        Resource webinfLocation = newMock(Resource.class);
+        Resource webinfAppLocation = newMock(Resource.class);
+
+        ComponentResourceResolverImpl resolver = new ComponentResourceResolverImpl();
+        resolver.setApplicationId("foo");
+        resolver.setClasspathAssetFactory(classpathFactory);
+        resolver.setContextAssetFactory(contextFactory);
+        resolver.setContextRoot(contextRoot);
+
+        expect(contextRoot.getRelativeResource("WEB-INF/")).andReturn(webinfLocation);
+        expect(webinfLocation.getRelativeResource("foo/")).andReturn(webinfAppLocation);
+
+        expect(comp.getSpecification()).andReturn(spec).anyTimes();
+        expect(comp.getNamespace()).andReturn(namespace);
+        expect(namespace.getPropertyValue("org.apache.tapestry.component-class-packages")).andReturn("org.apache.tapestry.resolver");
+
+        Location l = newMock(Location.class);
+        IAsset asset = newMock(IAsset.class);
+        Resource resource = newMock(Resource.class);
+
+        expect(contextFactory.assetExists(spec, webinfAppLocation, "MyComponent.html", null)).andReturn(false);
+        expect(contextFactory.assetExists(spec, webinfLocation, "MyComponent.html", null)).andReturn(true);
+        expect(comp.getLocation()).andReturn(l);
+        expect(contextFactory.createAsset(webinfLocation, spec, "MyComponent.html", null, l)).andReturn(asset);
+        expect(asset.getResourceLocation()).andReturn(resource);
+
+        replay();
+
+        resolver.initializeService();
+
+        Resource resolved = resolver.findComponentResource(comp, cycle, null, ".html", null);
+        assertEquals(resolved, resource);
+
+        verify();
+    }
+
+     public void test_Classpath_Spec_Resource_Classpath_Resolved()
+    {
+        IComponent comp = newMock(IComponent.class);
+        checkOrder(comp, false);
+
+        INamespace namespace = newMock(INamespace.class);
+        IRequestCycle cycle = newMock(IRequestCycle.class);
+
+        IComponentSpecification spec = new ComponentSpecification();
+        ClasspathResource base = new ClasspathResource(new DefaultClassResolver(), "/org/apache/tapestry/resolver/MyComponent.jwc");
+        spec.setSpecificationLocation(base);
+        spec.setComponentClassName("org.apache.tapestry.resolver.MyComponent");
+
+        AssetFactory classpathFactory = newMock(AssetFactory.class);
+        AssetFactory contextFactory = newMock(AssetFactory.class);
+        Resource contextRoot = newMock(Resource.class);
+        Resource webinfLocation = newMock(Resource.class);
+        Resource webinfAppLocation = newMock(Resource.class);
+
+        ComponentResourceResolverImpl resolver = new ComponentResourceResolverImpl();
+        resolver.setApplicationId("foo");
+        resolver.setClasspathAssetFactory(classpathFactory);
+        resolver.setContextAssetFactory(contextFactory);
+        resolver.setContextRoot(contextRoot);
+
+        expect(contextRoot.getRelativeResource("WEB-INF/")).andReturn(webinfLocation);
+        expect(webinfLocation.getRelativeResource("foo/")).andReturn(webinfAppLocation);
+
+        expect(comp.getSpecification()).andReturn(spec).anyTimes();
+        expect(comp.getNamespace()).andReturn(namespace);
+        expect(namespace.getPropertyValue("org.apache.tapestry.component-class-packages")).andReturn("org.apache.tapestry.resolver");
+
+        Location l = newMock(Location.class);
+        IAsset asset = newMock(IAsset.class);
+        Resource resource = newMock(Resource.class);
+
+        expect(contextFactory.assetExists(spec, webinfAppLocation, "MyComponent.html", null)).andReturn(false);
+        expect(contextFactory.assetExists(spec, webinfLocation, "MyComponent.html", null)).andReturn(false);
+        expect(classpathFactory.assetExists(spec, base, "MyComponent.html", null)).andReturn(true);
+
+        expect(comp.getLocation()).andReturn(l);
+        expect(classpathFactory.createAsset(base, spec, "MyComponent.html", null, l)).andReturn(asset);
+        expect(asset.getResourceLocation()).andReturn(resource);
+
+        replay();
+
+        resolver.initializeService();
+
+        Resource resolved = resolver.findComponentResource(comp, cycle, null, ".html", null);
+        assertEquals(resolved, resource);
+
+        verify();
+    }
+
+    // Returns the same URL object pointing to any arbitrary test classpath resource
+    public URL newURL()
+    {
+        return this.getClass().getResource("MyComponent.jwc");
+    }
+}

Propchange: tapestry/tapestry4/trunk/tapestry-framework/src/test/org/apache/tapestry/resolver/TestComponentResourceResolver.java
------------------------------------------------------------------------------
    svn:eol-style = native