incubator-sling-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From bdelacre...@apache.org
Subject svn commit: r832918 - in /sling/trunk/contrib/extensions/i18n: ./ src/main/java/org/apache/sling/i18n/impl/ src/test/ src/test/java/ src/test/java/org/ src/test/java/org/apache/ src/test/java/org/apache/sling/ src/test/java/org/apache/sling/i18n/ src/t...
Date Wed, 04 Nov 2009 23:53:43 GMT
Author: bdelacretaz
Date: Wed Nov  4 23:53:42 2009
New Revision: 832918

URL: http://svn.apache.org/viewvc?rev=832918&view=rev
Log:
SLING-1131 - i18n: do not enforce a flat node hierarchy below mix:language. Contributed by
Alex Klimetschek, thanks!

Added:
    sling/trunk/contrib/extensions/i18n/src/test/
    sling/trunk/contrib/extensions/i18n/src/test/java/
    sling/trunk/contrib/extensions/i18n/src/test/java/org/
    sling/trunk/contrib/extensions/i18n/src/test/java/org/apache/
    sling/trunk/contrib/extensions/i18n/src/test/java/org/apache/sling/
    sling/trunk/contrib/extensions/i18n/src/test/java/org/apache/sling/i18n/
    sling/trunk/contrib/extensions/i18n/src/test/java/org/apache/sling/i18n/impl/
    sling/trunk/contrib/extensions/i18n/src/test/java/org/apache/sling/i18n/impl/JcrResourceBundleTest.java
  (with props)
    sling/trunk/contrib/extensions/i18n/src/test/resources/
    sling/trunk/contrib/extensions/i18n/src/test/resources/log4j.properties   (with props)
Modified:
    sling/trunk/contrib/extensions/i18n/pom.xml
    sling/trunk/contrib/extensions/i18n/src/main/java/org/apache/sling/i18n/impl/JcrResourceBundle.java

Modified: sling/trunk/contrib/extensions/i18n/pom.xml
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/i18n/pom.xml?rev=832918&r1=832917&r2=832918&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/i18n/pom.xml (original)
+++ sling/trunk/contrib/extensions/i18n/pom.xml Wed Nov  4 23:53:42 2009
@@ -113,6 +113,39 @@
             <groupId>javax.servlet</groupId>
             <artifactId>servlet-api</artifactId>
         </dependency>
+        
+        <!-- Testing -->
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.commons.testing</artifactId>
+            <version>2.0.5-SNAPSHOT</version>
+            <scope>test</scope>
+            <exclusions>
+                <!-- slf4j simple implementation logs INFO + higher to stdout (we don't
want that behaviour) -->
+                <exclusion>
+                    <groupId>org.slf4j</groupId>
+                    <artifactId>slf4j-simple</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <!-- using log4j under slf4j to allow fine-grained logging config (see src/test/resources/log4j.properties)
-->
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-log4j12</artifactId>
+            <version>1.5.0</version>            
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>log4j</groupId>
+            <artifactId>log4j</artifactId>
+            <version>1.2.13</version>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 
 </project>

Modified: sling/trunk/contrib/extensions/i18n/src/main/java/org/apache/sling/i18n/impl/JcrResourceBundle.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/i18n/src/main/java/org/apache/sling/i18n/impl/JcrResourceBundle.java?rev=832918&r1=832917&r2=832918&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/i18n/src/main/java/org/apache/sling/i18n/impl/JcrResourceBundle.java
(original)
+++ sling/trunk/contrib/extensions/i18n/src/main/java/org/apache/sling/i18n/impl/JcrResourceBundle.java
Wed Nov  4 23:53:42 2009
@@ -29,10 +29,15 @@
 
 import javax.jcr.query.Query;
 
+import org.apache.jackrabbit.util.Text;
 import org.apache.sling.api.resource.ResourceResolver;
 import org.apache.sling.api.resource.ResourceUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 public class JcrResourceBundle extends ResourceBundle {
+    
+    private static final Logger log = LoggerFactory.getLogger(JcrResourceBundle.class);
 
     private static final String JCR_PATH = "jcr:path";
 
@@ -46,21 +51,22 @@
      * Search the tree below a mix:language node matching a given language...
      */
     private static final String QUERY_BASE =
-        "//element(*,mix:language)[@jcr:language='%s'%s]//*";
+        "//element(*,mix:language)[@jcr:language='%s'%s]//element(*,sling:Message)";
 
     /**
      * ... and find all nodes with a sling:message property set
      * (typically with mixin sling:Message).
      */
     private static final String QUERY_LOAD_FULLY = QUERY_BASE
-        + "[@" + PROP_VALUE + "]/@" + PROP_VALUE;
+        + "[@" + PROP_VALUE + "]/(@" + PROP_KEY + "|@" + PROP_VALUE + ")";
 
     /**
      * ... or find a node with the message (sling:message property) for
-     * a given key (sling:key property).
+     * a given key (sling:key property). Also find nodes without sling:key
+     * property and examine their node name.
      */
     private static final String QUERY_LOAD_RESOURCE = QUERY_BASE + "[@"
-        + PROP_KEY + "='%s']/@" + PROP_VALUE;
+        + PROP_KEY + "='%s' or not(@" + PROP_KEY + ")]/(@" + PROP_KEY + "|@" + PROP_VALUE
+ ")";
 
     private final ResourceResolver resourceResolver;
 
@@ -120,8 +126,12 @@
     private void loadFully() {
         if (!fullyLoaded) {
 
+            final String fullLoadQuery = getFullLoadQuery();
+            if (log.isDebugEnabled()) {
+                log.debug("Executing full load query {}", fullLoadQuery);
+            }
             Iterator<Map<String, Object>> bundles = resourceResolver.queryResources(
-                getFullLoadQuery(), Query.XPATH);
+                fullLoadQuery, Query.XPATH);
 
             String[] path = getSearchPath();
 
@@ -162,9 +172,12 @@
     }
 
     private Object loadResource(String key) {
-        // query for the resource
-        Iterator<Map<String, Object>> bundles = resourceResolver.queryResources(
-            getResourceQuery(key), Query.XPATH);
+        final String resourceQuery = getResourceQuery(key);
+        if (log.isDebugEnabled()) {
+            log.debug("Executing resource query {}", resourceQuery);
+        }
+        Iterator<Map<String, Object>> bundles = resourceResolver
+                .queryResources(resourceQuery, Query.XPATH);
         if (bundles.hasNext()) {
 
             String[] path = getSearchPath();
@@ -175,6 +188,13 @@
             while (bundles.hasNext() && currentWeight > 0) {
                 Map<String, Object> resource = bundles.next();
                 String jcrPath = (String) resource.get(JCR_PATH);
+                
+                // skip resources without sling:key and non-matching nodename
+                if (resource.get(PROP_KEY) == null) {
+                    if (!key.equals(Text.getName(jcrPath))) {
+                        continue;
+                    }
+                }
 
                 for (int i = 0; i < currentWeight; i++) {
                     if (jcrPath.startsWith(path[i])) {
@@ -190,8 +210,10 @@
                     currentValue = resource;
                 }
             }
-
-            return currentValue.get(PROP_VALUE);
+            
+            if (currentValue != null) {
+                return currentValue.get(PROP_VALUE);
+            }
         }
 
         return null;

Added: sling/trunk/contrib/extensions/i18n/src/test/java/org/apache/sling/i18n/impl/JcrResourceBundleTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/i18n/src/test/java/org/apache/sling/i18n/impl/JcrResourceBundleTest.java?rev=832918&view=auto
==============================================================================
--- sling/trunk/contrib/extensions/i18n/src/test/java/org/apache/sling/i18n/impl/JcrResourceBundleTest.java
(added)
+++ sling/trunk/contrib/extensions/i18n/src/test/java/org/apache/sling/i18n/impl/JcrResourceBundleTest.java
Wed Nov  4 23:53:42 2009
@@ -0,0 +1,278 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.i18n.impl;
+
+import java.util.Enumeration;
+import java.util.LinkedHashMap;
+import java.util.Locale;
+import java.util.Map;
+
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.RepositoryException;
+
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.commons.testing.SlingTestHelper;
+import org.apache.sling.commons.testing.jcr.RepositoryTestBase;
+import org.apache.sling.commons.testing.jcr.RepositoryUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Tests the {@link JcrResourceBundle} class.
+ */
+public class JcrResourceBundleTest extends RepositoryTestBase {
+    
+    private static final Logger log = LoggerFactory.getLogger(JcrResourceBundleTest.class);
+
+    protected ResourceResolver resolver;
+    
+    public void setUp() throws Exception {
+        super.setUp();
+        
+        cleanRepository();
+        
+        SlingTestHelper.registerSlingNodeTypes(getSession());
+        RepositoryUtil.registerNodeType(getSession(), getClass()
+                .getResourceAsStream("/SLING-INF/nodetypes/jcrlanguage.cnd"));
+        RepositoryUtil.registerNodeType(getSession(), getClass()
+                .getResourceAsStream("/SLING-INF/nodetypes/message.cnd"));
+
+        resolver = SlingTestHelper.getResourceResolver(getRepository(),
+                getSession());
+        
+        createTestContent();
+    }
+    
+    public void cleanRepository() throws Exception {
+        NodeIterator nodes = getSession().getRootNode().getNodes();
+        while (nodes.hasNext()) {
+            Node node = nodes.nextNode();
+            if (!node.getDefinition().isProtected() && !node.getDefinition().isMandatory())
{
+                try {
+                    node.remove();
+                } catch (RepositoryException e) {
+                    log.error("Test clean repo: Cannot remove node: " + node.getPath(), e);
+                }
+            }
+        }
+        getSession().save();
+    }
+    
+    // ---------------------------------------------------------------< test data helper
>
+    
+    /**
+     * Helper class for creating test data in a generic way.
+     */
+    public static class Message {
+        public String key;
+        public String message;
+        public boolean useNodeName;
+        public String path;
+        
+        public Message(String path, String key, String message, boolean useNodeName) {
+            this.path = path;
+            this.key = key;
+            this.message = message;
+            this.useNodeName = useNodeName;
+        }
+        
+        private static int nodeNameCounter = 0;
+        
+        public void add(Node languageNode) throws RepositoryException {
+            Node node = languageNode;
+            String[] pathElements = path.split("/");
+            for (String pathStep : pathElements) {
+                if (pathStep != null && pathStep.length() > 0) {
+                    node = node.addNode(pathStep, "nt:folder");
+                }
+            }
+            if (useNodeName) {
+                node = node.addNode(key, "sling:MessageEntry");
+            } else {
+                node = node.addNode("node" + nodeNameCounter, "sling:MessageEntry");
+                nodeNameCounter++;
+                node.setProperty("sling:key", key);
+            }
+            node.setProperty("sling:message", message);
+        }
+    }
+    
+    // test data to add to the repository (use linked hash map for insertion order)
+    public static final Map<String, Message> MESSAGES_DE = new LinkedHashMap<String,
Message>();
+    public static final Map<String, Message> MESSAGES_EN = new LinkedHashMap<String,
Message>();
+    public static final Map<String, Message> MESSAGES_DE_APPS = new LinkedHashMap<String,
Message>();
+    public static final Map<String, Message> MESSAGES_DE_BASENAME = new LinkedHashMap<String,
Message>();
+    
+    public static void add(Map<String, Message> map, Message msg) {
+        map.put(msg.key, msg);
+    }
+    
+    public static final Message PARENT_MSG = new Message("", "untranslated", "means: not
translated", false);
+    
+    // create test data
+    static {
+        // 1. direct child node of language node, using sling:key
+        add(MESSAGES_DE, new Message("", "kitchen", "KŸche", false));
+        // 2. direct child node of language node, using nodename
+        add(MESSAGES_DE, new Message("", "plate", "Teller", true));
+        // 3. nested node, using sling:key
+        add(MESSAGES_DE, new Message("f", "fork", "Gabel", false));
+        // 4. nested node, using nodename
+        add(MESSAGES_DE, new Message("s/p/o", "spoon", "Lšffel", true));
+        
+        // 5. not present in DE
+        add(MESSAGES_DE, PARENT_MSG);
+
+        // 6. same as 1.-4., but different translations for overwriting into apps
+        for (Message msg : MESSAGES_DE.values()) {
+            add(MESSAGES_DE_APPS, new Message(msg.path, msg.key, "OTHER", msg.useNodeName));
+        }
+
+        // 7. same as 1.-4., but different translations for different sling:basename
+        for (Message msg : MESSAGES_DE.values()) {
+            add(MESSAGES_DE_BASENAME, new Message(msg.path, msg.key, "BASENAME", msg.useNodeName));
+        }
+    }
+    
+    public void createTestContent() throws Exception {
+        Node i18n = getSession().getRootNode().addNode("libs", "nt:unstructured").addNode("i18n",
"nt:unstructured");
+        
+        // some DE content
+        Node de = i18n.addNode("de", "nt:folder");
+        de.addMixin("mix:language");
+        de.setProperty("jcr:language", "de");
+        for (Message msg : MESSAGES_DE.values()) {
+            msg.add(de);
+        }
+        getSession().save();
+        
+        // some EN content (for parent bundling)
+        Node en = i18n.addNode("en", "nt:folder");
+        en.addMixin("mix:language");
+        en.setProperty("jcr:language", "en");
+        for (Message msg : MESSAGES_EN.values()) {
+            msg.add(en);
+        }
+        getSession().save();
+        
+        //SlingTestHelper.printJCR(getSession());
+    }
+    
+    // ---------------------------------------------------------------< tests >
+    
+    public void test_getString() {
+        JcrResourceBundle bundle = new JcrResourceBundle(new Locale("de"), null, resolver);
+        for (Message msg : MESSAGES_DE.values()) {
+            assertEquals(msg.message, bundle.getString(msg.key));
+        }
+    }
+    
+    public void test_getObject() {
+        JcrResourceBundle bundle = new JcrResourceBundle(new Locale("de"), null, resolver);
+        for (Message msg : MESSAGES_DE.values()) {
+            assertEquals(msg.message, (String) bundle.getObject(msg.key));
+        }
+    }
+    
+    public void test_handle_missing_key() {
+        // test if key is returned if no entry found in repo
+        JcrResourceBundle bundle = new JcrResourceBundle(new Locale("de"), null, resolver);
+        assertEquals("missing", bundle.getString("missing"));
+    }
+    
+    public void test_getKeys() {
+        JcrResourceBundle bundle = new JcrResourceBundle(new Locale("de"), null, resolver);
+        Enumeration<String> keys = bundle.getKeys();
+        int counter = 0;
+        while (keys.hasMoreElements()) {
+            counter++;
+            String key = keys.nextElement();
+            assertTrue("bundle returned key that is not supposed to be there: " + key, MESSAGES_DE.containsKey(key));
+        }
+        assertEquals(MESSAGES_DE.size(), counter);
+    }
+    
+    public void test_bundle_parenting() {
+        // set parent of resource bundle, test if passed through
+        JcrResourceBundle bundle = new JcrResourceBundle(new Locale("de"), null, resolver);
+        JcrResourceBundle parentBundle = new JcrResourceBundle(new Locale("en"), null, resolver);
+        bundle.setParent(parentBundle);
+        
+        assertEquals(PARENT_MSG.message, bundle.getObject(PARENT_MSG.key));
+    }
+
+    public void test_search_path() throws Exception {
+        // overwrite stuff in apps
+        Node appsI18n = getSession().getRootNode().addNode("apps").addNode("i18n", "nt:unstructured");
+        Node de = appsI18n.addNode("de", "nt:folder");
+        de.addMixin("mix:language");
+        de.setProperty("jcr:language", "de");
+        for (Message msg : MESSAGES_DE_APPS.values()) {
+            msg.add(de);
+        }
+        getSession().save();
+        
+        // test getString
+        JcrResourceBundle bundle = new JcrResourceBundle(new Locale("de"), null, resolver);
+        for (Message msg : MESSAGES_DE_APPS.values()) {
+            assertEquals(msg.message, bundle.getString(msg.key));
+        }
+        
+        // test getKeys
+        Enumeration<String> keys = bundle.getKeys();
+        int counter = 0;
+        while (keys.hasMoreElements()) {
+            counter++;
+            String key = keys.nextElement();
+            assertTrue("bundle returned key that is not supposed to be there: " + key, MESSAGES_DE_APPS.containsKey(key));
+        }
+        assertEquals(MESSAGES_DE.size(), counter);
+    }
+    
+
+    public void test_basename() throws Exception {
+        // create another de lib with a basename set
+        Node appsI18n = getSession().getRootNode().getNode("libs/i18n");
+        Node de = appsI18n.addNode("de_basename", "nt:unstructured");
+        de.addMixin("mix:language");
+        de.setProperty("jcr:language", "de");
+        de.setProperty("sling:basename", "FOO");
+        for (Message msg : MESSAGES_DE_BASENAME.values()) {
+            msg.add(de);
+        }
+        getSession().save();
+        
+        // test getString
+        JcrResourceBundle bundle = new JcrResourceBundle(new Locale("de"), "FOO", resolver);
+        for (Message msg : MESSAGES_DE_BASENAME.values()) {
+            assertEquals(msg.message, bundle.getString(msg.key));
+        }
+        
+        // test getKeys
+        Enumeration<String> keys = bundle.getKeys();
+        int counter = 0;
+        while (keys.hasMoreElements()) {
+            counter++;
+            String key = keys.nextElement();
+            assertTrue("bundle returned key that is not supposed to be there: " + key, MESSAGES_DE_BASENAME.containsKey(key));
+        }
+        assertEquals(MESSAGES_DE.size(), counter);
+    }
+}

Propchange: sling/trunk/contrib/extensions/i18n/src/test/java/org/apache/sling/i18n/impl/JcrResourceBundleTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/trunk/contrib/extensions/i18n/src/test/java/org/apache/sling/i18n/impl/JcrResourceBundleTest.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision Rev URL

Added: sling/trunk/contrib/extensions/i18n/src/test/resources/log4j.properties
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/i18n/src/test/resources/log4j.properties?rev=832918&view=auto
==============================================================================
--- sling/trunk/contrib/extensions/i18n/src/test/resources/log4j.properties (added)
+++ sling/trunk/contrib/extensions/i18n/src/test/resources/log4j.properties Wed Nov  4 23:53:42
2009
@@ -0,0 +1,25 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+log4j.rootLogger=WARN, stdout
+
+log4j.logger.org.apache.sling.i18n=DEBUG
+
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+#log4j.appender.stdout.layout.ConversionPattern=%d{dd.MM.yyyy HH:mm:ss} *%-5p* [%t] %c{1}:
%m (%F, line %L)\n
+log4j.appender.stdout.layout.ConversionPattern=%d{dd.MM.yyyy HH:mm:ss} *%-5p* [%t] %c{1}:
%m\n

Propchange: sling/trunk/contrib/extensions/i18n/src/test/resources/log4j.properties
------------------------------------------------------------------------------
    svn:eol-style = native



Mime
View raw message