Author: mck
Date: Sun Mar 30 13:57:47 2014
New Revision: 1583141

URL: http://svn.apache.org/r1583141
Log:
TILES-571 – Please make the significance of underscore (_) in tiles definition 
filename more obvious
SPR-11491 – Doc: Tiles 3 and underscores in definition names

<quote> 
… it looks like there is an issue with PostfixedApplicationResource.
 
This issue comes from 
SpringWildcardServletTilesApplicationContext#getResources(String) -> 
URLApplicationResource(String, URL) constructor -> super 
PostfixedApplicationResource(String localePath) constructor. When there is an
underscore, the string after the last underscore is identified as the locale. 
But clearly it's not a locale and one should be able to load 
/WEB-INF/base_tiles.xml.
</quote>

Along with improving the documentation the following code changes have been made
• if the resource name contains "_" and after it there is no supported locale 
language code then the whole resource name is treated as a non-localized path.
        This situation prints a warning like 
                > No supported matching language for locale "zz". Using 
/my/path_zz.html as a non-localized resource path.
• if the resource name contains "_" and after it there is a supported locale 
language code but the locale constructed isn't valid/supported then the closest 
supported locale is used.
This situation prints a warning like
        > 
For resource /my/path_en_ZZ.html the closest supported matching locale to 
"en_ZZ" is "en". Using /my/path.html as resource path. 

Modified:
    tiles/framework/branches/TILES_3_0_X/src/site/apt/config-reference.apt
    
tiles/request/branches/TREQ_1_0_X/tiles-request-api/src/main/java/org/apache/tiles/request/locale/PostfixedApplicationResource.java
    
tiles/request/branches/TREQ_1_0_X/tiles-request-api/src/test/java/org/apache/tiles/request/locale/PostfixedApplicationResourceTest.java
    
tiles/request/branches/TREQ_1_0_X/tiles-request-api/src/test/java/org/apache/tiles/request/locale/URLApplicationResourceTest.java

Modified: tiles/framework/branches/TILES_3_0_X/src/site/apt/config-reference.apt
URL: 
http://svn.apache.org/viewvc/tiles/framework/branches/TILES_3_0_X/src/site/apt/config-reference.apt?rev=1583141&r1=1583140&r2=1583141&view=diff
==============================================================================
--- tiles/framework/branches/TILES_3_0_X/src/site/apt/config-reference.apt 
(original)
+++ tiles/framework/branches/TILES_3_0_X/src/site/apt/config-reference.apt Sun 
Mar 30 13:57:47 2014
@@ -143,9 +143,14 @@ Configuring Tiles internals
 
   The reason to use a custom Tiles application context could be:
 
-  * supporting a platform not supported yet;
+   * supporting a platform not supported yet;
 
-  * providing custom behaviour, such as loading resources in a different 
manner.
+   * providing custom behaviour, such as loading resources in a different 
manner.
+
+
+  When loading resources (by 
{{{/tiles-request/apidocs/org/apache/tiles/request/locale/PostfixedApplicationResource.html}default}})
+  an underscore in the name of a file is used to indicate locale information.
+  See the documentation for 
{{{/framework/tutorial/advanced/l10n.html}localization}}.
 
 * Custom {TilesContainerFactory}
 
@@ -160,41 +165,41 @@ Configuring Tiles internals
   
{{{./apidocs/org/apache/tiles/factory/BasicTilesContainerFactory.html}Javadoc 
documentation of BasicTilesContainerFactory}}
   documents all the methods that can be overridden to use your own
   configuration.
-  
+
 ** Changing the path for the Tiles Definitions file
 
   The <<<BasicTilesContainerFactory>>> loads the "/WEB-INF/tiles.xml" file; 
the <<<CompleteAutoloadTilesContainerFactory>>>
   loads all the files named "tiles*.xml" under /WEB-INF and under every 
META-INF in any part of the classpath.
-  
+
   If this behaviour doesn't suits you, you can override the method 
<<<getSources>>> and retrieve whatever resource you
   prefer. Just specify the path for the default locale; Tiles will extrapolate 
and load the localized files as needed.
 
 * Custom components
 
   These components can be used by overriding the appropriate <<<create>>> 
method in a custom TilesContainerFactory.
-  
+
 ** Custom {LocaleResolver}
-  
+
   The default implementation is 
{{{./apidocs/org/apache/tiles/locale/impl/DefaultLocaleResolver.html}DefaultLocaleResolver}}.
 
 ** Custom {DefinitionDAO}
 
   The default implementation is 
{{{./apidocs/org/apache/tiles/definition/dao/ResolvingLocaleUrlDefinitionDAO.html}ResolvingLocaleUrlDefinitionDAO}}.
-  
+
 ** Custom {AttributeEvaluatorFactory}
 
   The default implementation is 
{{{./apidocs/org/apache/tiles/evaluator/BasicAttributeEvaluatorFactory.html}BasicAttributeEvaluatorFactory}}.
-  
+
   It can be used with a number of AttributeEvaluators like:
-  
-  * the 
{{{./apidocs/org/apache/tiles/evaluator/impl/DirectAttributeEvaluator.html}DirectAttributeEvaluator}},
 
-  * the 
{{{./apidocs/org/apache/tiles/el/ELAttributeEvaluator.html}ELAttributeEvaluator}},
+   * the 
{{{./apidocs/org/apache/tiles/evaluator/impl/DirectAttributeEvaluator.html}DirectAttributeEvaluator}},
+
+   * the 
{{{./apidocs/org/apache/tiles/el/ELAttributeEvaluator.html}ELAttributeEvaluator}},
+
+   * the 
{{{./apidocs/org/apache/tiles/mvel/MVELAttributeEvaluator.html}MVELAttributeEvaluator}},
 
-  * the 
{{{./apidocs/org/apache/tiles/mvel/MVELAttributeEvaluator.html}MVELAttributeEvaluator}},
+   * the 
{{{./apidocs/org/apache/tiles/ognl/OGNLAttributeEvaluator.html}OGNLAttributeEvaluator}}.
 
-  * the 
{{{./apidocs/org/apache/tiles/ognl/OGNLAttributeEvaluator.html}OGNLAttributeEvaluator}}.
-  
   Please see 
{{{./xref/org/apache/tiles/extras/complete/CompleteAutoloadTilesContainerFactory.html}CompleteAutoloadTilesContainerFactory}}
   for an example of how to configure those.
 
@@ -214,20 +219,20 @@ Configuring Tiles internals
 
   The default implementation is 
{{{./apidocs/org/apache/tiles/definition/pattern/BasicPatternDefinitionResolver.html}BasicPatternDefinitionResolver}},
   that implements the <wildcard> syntax.
-  
-  <<<CompleteAutoloadTilesContainerFactory>>> defines a 
<<<PrefixedPatternDefinitionResolver>>> to enable the use of 
+
+  <<<CompleteAutoloadTilesContainerFactory>>> defines a 
<<<PrefixedPatternDefinitionResolver>>> to enable the use of
   both the <wildcard> syntax and the <regexp> syntax, with appropriate 
prefixes.
 
 * Registering {Renderers}
 
   Custom 
{{{/tiles-request/apidocs/org/apache/tiles/request/render/Renderer.html}Renderers}}
 can be registered by overriding the methods
   <<<registerAttributeRenderers>>> and <<<createDefaultAttributeRenderer>>>.
-  
+
   <<<BasicTilesContainerFactory>>> registers 3 renderers: <<<string>>>, 
<<<template>>>, and <<<definition>>>, in order to
   render plain strings, JSPs and tiles definitions.
-  
-  <<<CompleteAutoloadTilesContainerFactory>>> registers 5 renderers: 
<<<string>>>, <<<template>>>, <<<freemarker>>>, 
-  <<<velocity>>> and <<<definition>>>, in order to render plain strings, JSPs, 
freemarker and velocity templates 
+
+  <<<CompleteAutoloadTilesContainerFactory>>> registers 5 renderers: 
<<<string>>>, <<<template>>>, <<<freemarker>>>,
+  <<<velocity>>> and <<<definition>>>, in order to render plain strings, JSPs, 
freemarker and velocity templates
   and tiles definitions.
 
 * Changing the {definition files}
@@ -245,6 +250,6 @@ protected List<ApplicationResource> getS
 -----------
 
   Please note that when using <<<CompleteAutoloadTilesContainerFactory>>>,
-  the <<<ApplicationContext>>> loads the resources via spring, and supports 
+  the <<<ApplicationContext>>> loads the resources via spring, and supports
   
{{{http://static.springsource.org/spring/docs/2.5.x/reference/resources.html#resources-resource-strings}the
 spring syntax}} for locating resources.
 

Modified: 
tiles/request/branches/TREQ_1_0_X/tiles-request-api/src/main/java/org/apache/tiles/request/locale/PostfixedApplicationResource.java
URL: 
http://svn.apache.org/viewvc/tiles/request/branches/TREQ_1_0_X/tiles-request-api/src/main/java/org/apache/tiles/request/locale/PostfixedApplicationResource.java?rev=1583141&r1=1583140&r2=1583141&view=diff
==============================================================================
--- 
tiles/request/branches/TREQ_1_0_X/tiles-request-api/src/main/java/org/apache/tiles/request/locale/PostfixedApplicationResource.java
 (original)
+++ 
tiles/request/branches/TREQ_1_0_X/tiles-request-api/src/main/java/org/apache/tiles/request/locale/PostfixedApplicationResource.java
 Sun Mar 30 13:57:47 2014
@@ -21,14 +21,18 @@
 
 package org.apache.tiles.request.locale;
 
+import java.util.Arrays;
+import java.util.IllformedLocaleException;
+import java.util.List;
 import java.util.Locale;
-
 import org.apache.tiles.request.ApplicationResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * An ApplicationResource whose localization is managed by postfixing the file 
name.
  * The various localizations are file sitting next to each other, with the 
locale identified in the postfix.
- * 
+ *
  * For instance:
  * <pre>
  * /WEB-INF/tiles.xml
@@ -36,13 +40,15 @@ import org.apache.tiles.request.Applicat
  * /WEB-INF/tiles_it.xml
  * /WEB-INF/tiles_it_IT.xml
  * </pre>
- * 
+ *
  * Two PostfixedApplicationResources are equals if they share the same 
localized path and the same class.
- * 
+ *
  * @version $Rev$ $Date$
  */
 public abstract class PostfixedApplicationResource implements 
ApplicationResource {
 
+    private static final Logger LOG = 
LoggerFactory.getLogger(PostfixedApplicationResource.class);
+
     /** The path without its suffix and its locale postfix. */
     private String pathPrefix;
     /** The suffix. */
@@ -69,18 +75,18 @@ public abstract class PostfixedApplicati
         } else {
             pathPrefix = localePath.substring(0, prefixIndex);
             String localeString = localePath.substring(prefixIndex + 1, 
suffixIndex);
-            int countryIndex = localeString.indexOf('_');
-            if (countryIndex < 0) {
-                locale = new Locale(localeString);
-            } else {
-                int variantIndex = localeString.indexOf('_', countryIndex + 1);
-                if (variantIndex < 0) {
-                    locale = new Locale(localeString.substring(0, 
countryIndex),
-                            localeString.substring(countryIndex + 1));
-                } else {
-                    locale = new Locale(localeString.substring(0, 
countryIndex), localeString.substring(
-                            countryIndex + 1, variantIndex), 
localeString.substring(variantIndex + 1));
-                }
+            Locale found = localeFrom(localeString);
+            locale = validateLocale(found);
+            if (Locale.ROOT.equals(locale)) {
+                pathPrefix = suffixIndex < 0 ? localePath : 
localePath.substring(0, suffixIndex);
+
+                LOG.warn("No supported matching language for locale \"" + 
localeString + "\". Using "
+                        + getPath() + " as a non-localized resource path. see 
TILES-571");
+
+            } else if 
(!localeString.equalsIgnoreCase(getPostfix(locale).substring(1))) {
+                LOG.warn("For resource " + localePath
+                        + " the closest supported matching locale to \"" + 
localeString + "\" is \"" + locale
+                        + "\". Using " + getPath() + " as resource path. see 
TILES-571");
             }
         }
     }
@@ -193,4 +199,45 @@ public abstract class PostfixedApplicati
             return false;
         return true;
     }
+
+    private static Locale localeFrom(String localeString) {
+        Locale.Builder builder = new Locale.Builder();
+        try {
+            int countryIndex = localeString.indexOf('_');
+            if (countryIndex < 0) {
+                builder.setLanguage(localeString);
+            } else {
+                int variantIndex = localeString.indexOf('_', countryIndex + 1);
+                builder.setLanguage(localeString.substring(0, countryIndex));
+                if (variantIndex < 0) {
+                    builder.setRegion(localeString.substring(countryIndex + 
1));
+                } else {
+                    builder.setRegion(localeString.substring(countryIndex + 1, 
variantIndex));
+                    builder.setVariant(localeString.substring(variantIndex + 
1));
+                }
+            }
+        } catch (IllformedLocaleException ex) {
+            LOG.debug(localeString + " is an ill-formed locale", ex);
+        }
+        return builder.build();
+    }
+
+    private static Locale validateLocale(Locale locale) {
+        List<Locale> availableLocales = 
Arrays.asList(Locale.getAvailableLocales());
+
+        Locale withoutVariant = locale.getVariant().isEmpty()
+                ? locale
+                : new Locale(locale.getLanguage(), locale.getCountry());
+
+        Locale result = locale;
+        if (!availableLocales.contains(withoutVariant)) {
+            if (!result.getCountry().isEmpty()) {
+                result = new Locale(result.getLanguage());
+            }
+            if (!availableLocales.contains(result)) {
+                result = Locale.ROOT;
+            }
+        }
+        return result;
+    }
 }

Modified: 
tiles/request/branches/TREQ_1_0_X/tiles-request-api/src/test/java/org/apache/tiles/request/locale/PostfixedApplicationResourceTest.java
URL: 
http://svn.apache.org/viewvc/tiles/request/branches/TREQ_1_0_X/tiles-request-api/src/test/java/org/apache/tiles/request/locale/PostfixedApplicationResourceTest.java?rev=1583141&r1=1583140&r2=1583141&view=diff
==============================================================================
--- 
tiles/request/branches/TREQ_1_0_X/tiles-request-api/src/test/java/org/apache/tiles/request/locale/PostfixedApplicationResourceTest.java
 (original)
+++ 
tiles/request/branches/TREQ_1_0_X/tiles-request-api/src/test/java/org/apache/tiles/request/locale/PostfixedApplicationResourceTest.java
 Sun Mar 30 13:57:47 2014
@@ -53,9 +53,9 @@ public class PostfixedApplicationResourc
         public long getLastModified() throws IOException {
             return 0;
         }
-        
+
     };
-    
+
     /**
      * Test getLocalePath(String path, Locale locale).
      */
@@ -68,7 +68,7 @@ public class PostfixedApplicationResourc
         assertEquals("/my/path_it_IT.html", 
resource.getLocalePath(Locale.ITALY));
         assertEquals("/my/path_en_GB_scotland.html", 
resource.getLocalePath(new Locale("en", "GB", "scotland")));
     }
-    
+
     @Test
     public void testBuildFromString() {
         TestApplicationResource resource = new 
TestApplicationResource("/my/path_en_GB_scotland.html");
@@ -87,8 +87,32 @@ public class PostfixedApplicationResourc
         assertEquals("/my/path.html", resource.getLocalePath());
         assertEquals("/my/path.html", resource.getPath());
         assertEquals(Locale.ROOT, resource.getLocale());
+        resource = new TestApplicationResource("/my/path_zz.html");
+        assertEquals("/my/path_zz.html", resource.getLocalePath());
+        assertEquals("/my/path_zz.html", resource.getPath());
+        assertEquals(Locale.ROOT, resource.getLocale());
+        resource = new TestApplicationResource("/my/path_en_ZZ.html");
+        assertEquals("/my/path_en.html", resource.getLocalePath());
+        assertEquals("/my/path.html", resource.getPath());
+        assertEquals(new Locale("en"), resource.getLocale());
+        resource = new TestApplicationResource("/my/path_tiles.html");
+        assertEquals("/my/path_tiles.html", resource.getLocalePath());
+        assertEquals("/my/path_tiles.html", resource.getPath());
+        assertEquals(Locale.ROOT, resource.getLocale());
+        resource = new 
TestApplicationResource("/my/path_longwordthatbreaksISO639.html");
+        assertEquals("/my/path_longwordthatbreaksISO639.html", 
resource.getLocalePath());
+        assertEquals("/my/path_longwordthatbreaksISO639.html", 
resource.getPath());
+        assertEquals(Locale.ROOT, resource.getLocale());
+        resource = new TestApplicationResource("/my/path_en_tiles.html");
+        assertEquals("/my/path_en.html", resource.getLocalePath());
+        assertEquals("/my/path.html", resource.getPath());
+        assertEquals(new Locale("en"), resource.getLocale());
+        resource = new 
TestApplicationResource("/my/path_en_longwordthatbreaksISO3166.html");
+        assertEquals("/my/path_en.html", resource.getLocalePath());
+        assertEquals("/my/path.html", resource.getPath());
+        assertEquals(new Locale("en"), resource.getLocale());
     }
-    
+
     @Test
     public void testBuildFromStringAndLocale() {
         TestApplicationResource resource = new 
TestApplicationResource("/my/path.html", new Locale("en", "GB", "scotland"));

Modified: 
tiles/request/branches/TREQ_1_0_X/tiles-request-api/src/test/java/org/apache/tiles/request/locale/URLApplicationResourceTest.java
URL: 
http://svn.apache.org/viewvc/tiles/request/branches/TREQ_1_0_X/tiles-request-api/src/test/java/org/apache/tiles/request/locale/URLApplicationResourceTest.java?rev=1583141&r1=1583140&r2=1583141&view=diff
==============================================================================
--- 
tiles/request/branches/TREQ_1_0_X/tiles-request-api/src/test/java/org/apache/tiles/request/locale/URLApplicationResourceTest.java
 (original)
+++ 
tiles/request/branches/TREQ_1_0_X/tiles-request-api/src/test/java/org/apache/tiles/request/locale/URLApplicationResourceTest.java
 Sun Mar 30 13:57:47 2014
@@ -97,6 +97,42 @@ public class URLApplicationResourceTest 
         assertEquals("file:/", resource.getURL().toString());
         assertEquals("/", resource.getFile().toString());
         assertEquals(Locale.ROOT, resource.getLocale());
+        resource = new TestApplicationResource("/my/path_zz.html", new 
URL("file:///"));
+        assertEquals("/my/path_zz.html", resource.getLocalePath());
+        assertEquals("/my/path_zz.html", resource.getPath());
+        assertEquals("file:/", resource.getURL().toString());
+        assertEquals("/", resource.getFile().toString());
+        assertEquals(Locale.ROOT, resource.getLocale());
+        resource = new TestApplicationResource("/my/path_en_ZZ.html", new 
URL("file:///"));
+        assertEquals("/my/path_en.html", resource.getLocalePath());
+        assertEquals("/my/path.html", resource.getPath());
+        assertEquals("file:/", resource.getURL().toString());
+        assertEquals("/", resource.getFile().toString());
+        assertEquals(new Locale("en"), resource.getLocale());
+        resource = new TestApplicationResource("/my/path_tiles.html", new 
URL("file:///"));
+        assertEquals("/my/path_tiles.html", resource.getLocalePath());
+        assertEquals("/my/path_tiles.html", resource.getPath());
+        assertEquals("file:/", resource.getURL().toString());
+        assertEquals("/", resource.getFile().toString());
+        assertEquals(Locale.ROOT, resource.getLocale());
+        resource = new 
TestApplicationResource("/my/path_longwordthatbreaksISO639.html", new 
URL("file:///"));
+        assertEquals("/my/path_longwordthatbreaksISO639.html", 
resource.getLocalePath());
+        assertEquals("/my/path_longwordthatbreaksISO639.html", 
resource.getPath());
+        assertEquals("file:/", resource.getURL().toString());
+        assertEquals("/", resource.getFile().toString());
+        assertEquals(Locale.ROOT, resource.getLocale());
+        resource = new TestApplicationResource("/my/path_en_tiles.html", new 
URL("file:///"));
+        assertEquals("/my/path_en.html", resource.getLocalePath());
+        assertEquals("/my/path.html", resource.getPath());
+        assertEquals("file:/", resource.getURL().toString());
+        assertEquals("/", resource.getFile().toString());
+        assertEquals(new Locale("en"), resource.getLocale());
+        resource = new 
TestApplicationResource("/my/path_en_longwordthatbreaksISO3166.html", new 
URL("file:///"));
+        assertEquals("/my/path_en.html", resource.getLocalePath());
+        assertEquals("/my/path.html", resource.getPath());
+        assertEquals("file:/", resource.getURL().toString());
+        assertEquals("/", resource.getFile().toString());
+        assertEquals(new Locale("en"), resource.getLocale());
     }
 
     @Test


Reply via email to