You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by fm...@apache.org on 2008/03/18 21:22:18 UTC
svn commit: r638552 - in /incubator/sling/trunk/sling/i18n: ./ src/
src/main/ src/main/java/ src/main/java/org/ src/main/java/org/apache/
src/main/java/org/apache/sling/ src/main/java/org/apache/sling/i18n/
src/main/java/org/apache/sling/i18n/impl/ src...
Author: fmeschbe
Date: Tue Mar 18 13:22:14 2008
New Revision: 638552
URL: http://svn.apache.org/viewvc?rev=638552&view=rev
Log:
SLING-335 Add new Internationalization Support Bundle
Added:
incubator/sling/trunk/sling/i18n/ (with props)
incubator/sling/trunk/sling/i18n/pom.xml (with props)
incubator/sling/trunk/sling/i18n/src/
incubator/sling/trunk/sling/i18n/src/main/
incubator/sling/trunk/sling/i18n/src/main/java/
incubator/sling/trunk/sling/i18n/src/main/java/org/
incubator/sling/trunk/sling/i18n/src/main/java/org/apache/
incubator/sling/trunk/sling/i18n/src/main/java/org/apache/sling/
incubator/sling/trunk/sling/i18n/src/main/java/org/apache/sling/i18n/
incubator/sling/trunk/sling/i18n/src/main/java/org/apache/sling/i18n/LocaleResolver.java (with props)
incubator/sling/trunk/sling/i18n/src/main/java/org/apache/sling/i18n/ResourceBundleProvider.java (with props)
incubator/sling/trunk/sling/i18n/src/main/java/org/apache/sling/i18n/impl/
incubator/sling/trunk/sling/i18n/src/main/java/org/apache/sling/i18n/impl/I18NFilter.java (with props)
incubator/sling/trunk/sling/i18n/src/main/java/org/apache/sling/i18n/impl/JcrResourceBundle.java (with props)
incubator/sling/trunk/sling/i18n/src/main/java/org/apache/sling/i18n/impl/JcrResourceBundleProvider.java (with props)
incubator/sling/trunk/sling/i18n/src/main/java/org/apache/sling/i18n/impl/ResourceBundleEnumeration.java (with props)
incubator/sling/trunk/sling/i18n/src/main/resources/
incubator/sling/trunk/sling/i18n/src/main/resources/OSGI-INF/
incubator/sling/trunk/sling/i18n/src/main/resources/OSGI-INF/metatype/
incubator/sling/trunk/sling/i18n/src/main/resources/OSGI-INF/metatype/metatype.properties (with props)
incubator/sling/trunk/sling/i18n/src/main/resources/SLING-INF/
incubator/sling/trunk/sling/i18n/src/main/resources/SLING-INF/nodetypes/
incubator/sling/trunk/sling/i18n/src/main/resources/SLING-INF/nodetypes/language.cnd (with props)
incubator/sling/trunk/sling/i18n/src/main/resources/SLING-INF/nodetypes/message.cnd (with props)
Propchange: incubator/sling/trunk/sling/i18n/
------------------------------------------------------------------------------
--- svn:ignore (added)
+++ svn:ignore Tue Mar 18 13:22:14 2008
@@ -0,0 +1,4 @@
+.classpath
+.project
+.settings
+target
Added: incubator/sling/trunk/sling/i18n/pom.xml
URL: http://svn.apache.org/viewvc/incubator/sling/trunk/sling/i18n/pom.xml?rev=638552&view=auto
==============================================================================
--- incubator/sling/trunk/sling/i18n/pom.xml (added)
+++ incubator/sling/trunk/sling/i18n/pom.xml Tue Mar 18 13:22:14 2008
@@ -0,0 +1,118 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+ 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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.apache.sling</groupId>
+ <artifactId>sling</artifactId>
+ <version>1-incubator-SNAPSHOT</version>
+ <relativePath>../../parent/pom.xml</relativePath>
+ </parent>
+
+ <artifactId>org.apache.sling.i18n</artifactId>
+ <packaging>bundle</packaging>
+ <version>2.0.0-incubator-SNAPSHOT</version>
+
+ <name>Sling Internationalization Support</name>
+ <description>
+ Support for creating Java I18N ResourceBundles from repository
+ resources.
+ </description>
+
+ <scm>
+ <connection>
+ scm:svn:http://svn.apache.org/repos/asf/incubator/sling/trunk/sling/i18n
+ </connection>
+ <developerConnection>
+ scm:svn:https://svn.apache.org/repos/asf/incubator/sling/trunk/sling/i18n
+ </developerConnection>
+ <url>
+ http://svn.apache.org/viewvc/incubator/sling/trunk/sling/i18n
+ </url>
+ </scm>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-scr-plugin</artifactId>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Export-Package>
+ org.apache.sling.i18n
+ </Export-Package>
+ <Private-Package>
+ org.apache.sling.i18n.impl
+ </Private-Package>
+
+ <Sling-Nodetypes>
+ SLING-INF/nodetypes/language.cnd,
+ SLING-INF/nodetypes/message.cnd
+ </Sling-Nodetypes>
+
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.sling</groupId>
+ <artifactId>org.apache.sling.api</artifactId>
+ <version>2.0.0-incubator-SNAPSHOT</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.sling</groupId>
+ <artifactId>org.apache.sling.jcr.api</artifactId>
+ <version>2.0.0-incubator-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.sling</groupId>
+ <artifactId>org.apache.sling.jcr.resource</artifactId>
+ <version>2.0.0-incubator-SNAPSHOT</version>
+</dependency>
+ <dependency>
+ <groupId>javax.jcr</groupId>
+ <artifactId>jcr</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.osgi.compendium</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>servlet-api</artifactId>
+ </dependency>
+ </dependencies>
+
+</project>
Propchange: incubator/sling/trunk/sling/i18n/pom.xml
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/sling/trunk/sling/i18n/src/main/java/org/apache/sling/i18n/LocaleResolver.java
URL: http://svn.apache.org/viewvc/incubator/sling/trunk/sling/i18n/src/main/java/org/apache/sling/i18n/LocaleResolver.java?rev=638552&view=auto
==============================================================================
--- incubator/sling/trunk/sling/i18n/src/main/java/org/apache/sling/i18n/LocaleResolver.java (added)
+++ incubator/sling/trunk/sling/i18n/src/main/java/org/apache/sling/i18n/LocaleResolver.java Tue Mar 18 13:22:14 2008
@@ -0,0 +1,30 @@
+/*
+ * 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;
+
+import java.util.List;
+import java.util.Locale;
+
+import org.apache.sling.api.SlingHttpServletRequest;
+
+public interface LocaleResolver {
+
+ List<Locale> resolveLocale(SlingHttpServletRequest request);
+
+}
Propchange: incubator/sling/trunk/sling/i18n/src/main/java/org/apache/sling/i18n/LocaleResolver.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/sling/trunk/sling/i18n/src/main/java/org/apache/sling/i18n/ResourceBundleProvider.java
URL: http://svn.apache.org/viewvc/incubator/sling/trunk/sling/i18n/src/main/java/org/apache/sling/i18n/ResourceBundleProvider.java?rev=638552&view=auto
==============================================================================
--- incubator/sling/trunk/sling/i18n/src/main/java/org/apache/sling/i18n/ResourceBundleProvider.java (added)
+++ incubator/sling/trunk/sling/i18n/src/main/java/org/apache/sling/i18n/ResourceBundleProvider.java Tue Mar 18 13:22:14 2008
@@ -0,0 +1,44 @@
+/*
+ * 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;
+
+import java.util.Locale;
+import java.util.ResourceBundle;
+
+/**
+ * The <code>ResourceBundleProvider</code> service interface defines the API
+ * for a service, which is capable of returned <code>ResourceBundle</code> for
+ * given any <code>Locale</code>.
+ */
+public interface ResourceBundleProvider {
+
+ /**
+ * Returns a <code>ResourceBundle</code> for the given locale.
+ *
+ * @param locale The <code>Locale</code> for which to return the resource
+ * bundle. If this is <code>null</code> the platform default
+ * locale as returned by <code>Locale.getDefault()</code> is
+ * assumed.
+ * @return The <code>ResourceBundle</code> for the given locale
+ * @throws MissingResourceException If the service is not capable of
+ * returning a <code>ResourceBundle</code>
+ */
+ ResourceBundle getResourceBundle(Locale locale);
+
+}
Propchange: incubator/sling/trunk/sling/i18n/src/main/java/org/apache/sling/i18n/ResourceBundleProvider.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/sling/trunk/sling/i18n/src/main/java/org/apache/sling/i18n/impl/I18NFilter.java
URL: http://svn.apache.org/viewvc/incubator/sling/trunk/sling/i18n/src/main/java/org/apache/sling/i18n/impl/I18NFilter.java?rev=638552&view=auto
==============================================================================
--- incubator/sling/trunk/sling/i18n/src/main/java/org/apache/sling/i18n/impl/I18NFilter.java (added)
+++ incubator/sling/trunk/sling/i18n/src/main/java/org/apache/sling/i18n/impl/I18NFilter.java Tue Mar 18 13:22:14 2008
@@ -0,0 +1,265 @@
+/*
+ * 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.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Locale;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.api.wrappers.SlingHttpServletRequestWrapper;
+import org.apache.sling.i18n.LocaleResolver;
+import org.apache.sling.i18n.ResourceBundleProvider;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The <code>I18NFilter</code> class is a request level filter, which provides
+ * the resource bundle for the current request.
+ *
+ * @scr.component immediate="true" metatype="false"
+ * @scr.property name="service.description" value="Internationalization Support
+ * Filter"
+ * @scr.property name="service.vendor" value="The Apache Software Foundation"
+ * @scr.property name="filter.scope" value="request" private="true"
+ * @scr.property name="filter.order" value="-700" type="Integer" private="true"
+ * @scr.service
+ */
+public class I18NFilter implements Filter {
+
+ /** default log */
+ private static final Logger log = LoggerFactory.getLogger(I18NFilter.class.getName());
+
+ /**
+ * @scr.property value="en_US"
+ */
+ public static final String PAR_DEFAULT_LOCALE = "locale.default";
+
+ private static LocaleResolver DEFAULT_LOCALE_RESOLVER = new LocaleResolver() {
+ public List<Locale> resolveLocale(SlingHttpServletRequest request) {
+
+ // unwrap the request which is a I18NSlingHttpServletRequest
+ request = ((SlingHttpServletRequestWrapper) request).getSlingRequest();
+
+ Enumeration<?> locales = request.getLocales();
+ List<Locale> localeList = new ArrayList<Locale>();
+ while (locales.hasMoreElements()) {
+ localeList.add((Locale) locales.nextElement());
+ }
+
+ return localeList;
+ }
+ };
+
+ /**
+ * @scr.reference cardinality="0..1" policy="dynamic"
+ */
+ private LocaleResolver localeResolver = DEFAULT_LOCALE_RESOLVER;
+
+ /** @scr.reference cardinality="0..1" policy="dynamic" */
+ ResourceBundleProvider resourceBundleProvider;
+
+ private Locale defaultLocale;
+
+ public void init(FilterConfig filterConfig) {
+ // nothing to do
+ }
+
+ public void doFilter(ServletRequest request, ServletResponse response,
+ FilterChain chain) throws IOException, ServletException {
+
+ // wrap with our ResourceBundle provisioning
+ request = new I18NSlingHttpServletRequest(request,
+ resourceBundleProvider, localeResolver, defaultLocale);
+
+ // and forward the request
+ chain.doFilter(request, response);
+ }
+
+ public void destroy() {
+ // nothing to do
+ }
+
+ // ---------- SCR Integration ----------------------------------------------
+
+ protected void activate(org.osgi.service.component.ComponentContext context) {
+ @SuppressWarnings("unchecked")
+ Dictionary<String, Object> configuration = context.getProperties();
+ String localeString = (String) configuration.get(PAR_DEFAULT_LOCALE);
+ this.defaultLocale = this.toLocale(localeString);
+ }
+
+ protected void bindLocaleResolver(LocaleResolver localeResolver) {
+ this.localeResolver = localeResolver;
+ }
+
+ protected void unbindLocaleResolver(LocaleResolver localeResolver) {
+ if (this.localeResolver == localeResolver) {
+ this.localeResolver = DEFAULT_LOCALE_RESOLVER;
+ }
+ }
+
+ // ---------- internal -----------------------------------------------------
+
+ private Locale toLocale(String localeString) {
+ if (localeString == null || localeString.length() == 0) {
+ return Locale.getDefault();
+ }
+
+ // check whether we have an exact match locale
+ Locale[] available = Locale.getAvailableLocales();
+ for (int i = 0; i < available.length; i++) {
+ if (available[i].toString().equals(localeString)) {
+ return available[i];
+ }
+ }
+
+ // check language and country
+ String[] parts = localeString.split("_");
+ if (parts.length == 0) {
+ return Locale.getDefault();
+ }
+
+ // at least language is available
+ String lang = parts[0];
+ String[] langs = Locale.getISOLanguages();
+ for (int i = 0; i < langs.length; i++) {
+ if (langs[i].equals(lang)) {
+ lang = null; // signal ok
+ break;
+ }
+ }
+ if (lang != null) {
+ parts[0] = Locale.getDefault().getLanguage();
+ }
+
+ // only language
+ if (parts.length == 1) {
+ return new Locale(parts[0]);
+ }
+
+ // country is also available
+ String country = parts[1];
+ String[] countries = Locale.getISOCountries();
+ for (int i = 0; i < countries.length; i++) {
+ if (countries[i].equals(lang)) {
+ lang = null; // signal ok
+ break;
+ }
+ }
+ if (country != null) {
+ parts[1] = Locale.getDefault().getCountry();
+ }
+
+ // language and country
+ if (parts.length == 2) {
+ return new Locale(parts[0], parts[1]);
+ }
+
+ // language, country and variant
+ return new Locale(parts[0], parts[1], parts[2]);
+ }
+
+ // ---------- internal class -----------------------------------------------
+
+ private static class I18NSlingHttpServletRequest extends
+ SlingHttpServletRequestWrapper {
+
+ private final ResourceBundleProvider bundleProvider;
+
+ private final LocaleResolver localeResolver;
+
+ private final Locale defaultLocale;
+
+ private Locale locale;
+
+ private List<Locale> localeList;
+
+ I18NSlingHttpServletRequest(ServletRequest delegatee,
+ ResourceBundleProvider bundleProvider,
+ LocaleResolver localeResolver, Locale defaultLocale) {
+ super((SlingHttpServletRequest) delegatee);
+ this.bundleProvider = bundleProvider;
+ this.localeResolver = localeResolver;
+ this.defaultLocale = defaultLocale;
+ }
+
+ @Override
+ public ResourceBundle getResourceBundle(Locale locale) {
+ if (bundleProvider != null) {
+ if (locale == null) {
+ locale = getLocale();
+ }
+
+ try {
+ return bundleProvider.getResourceBundle(locale);
+ } catch (MissingResourceException mre) {
+ log.warn(
+ "getResourceBundle: Cannot get ResourceBundle from provider",
+ mre);
+ }
+ } else {
+ log.info("getResourceBundle: ResourceBundleProvider not available, calling default implementation");
+ }
+
+ return super.getResourceBundle(locale);
+ }
+
+ @Override
+ public Locale getLocale() {
+ if (locale == null) {
+ List<Locale> localeList = getLocaleList();
+ if (localeList.isEmpty()) {
+ locale = defaultLocale;
+ } else {
+ locale = localeList.get(0);
+ }
+ }
+
+ return locale;
+ }
+
+ @Override
+ public Enumeration<?> getLocales() {
+ return Collections.enumeration(getLocaleList());
+ }
+
+ private List<Locale> getLocaleList() {
+ if (localeList == null) {
+ localeList = localeResolver.resolveLocale(this);
+ }
+
+ return localeList;
+ }
+ }
+
+}
Propchange: incubator/sling/trunk/sling/i18n/src/main/java/org/apache/sling/i18n/impl/I18NFilter.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/sling/trunk/sling/i18n/src/main/java/org/apache/sling/i18n/impl/JcrResourceBundle.java
URL: http://svn.apache.org/viewvc/incubator/sling/trunk/sling/i18n/src/main/java/org/apache/sling/i18n/impl/JcrResourceBundle.java?rev=638552&view=auto
==============================================================================
--- incubator/sling/trunk/sling/i18n/src/main/java/org/apache/sling/i18n/impl/JcrResourceBundle.java (added)
+++ incubator/sling/trunk/sling/i18n/src/main/java/org/apache/sling/i18n/impl/JcrResourceBundle.java Tue Mar 18 13:22:14 2008
@@ -0,0 +1,131 @@
+/*
+ * 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.HashMap;
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.Map;
+import java.util.ResourceBundle;
+
+import javax.jcr.query.Query;
+
+import org.apache.sling.api.resource.ResourceResolver;
+
+public class JcrResourceBundle extends ResourceBundle {
+
+ static final String PROP_KEY = "sling:key";
+
+ private static final String PROP_VALUE = "sling:message";
+
+ private static final String QUERY_BASE = "//element(*,mix:language)[@jcr:language='%s']/*";
+
+ private static final String QUERY_LOAD_FULLY = QUERY_BASE + "/(@"
+ + PROP_KEY + "|@" + PROP_VALUE + ")";
+
+ private static final String QUERY_LOAD_RESOURCE = QUERY_BASE + "[@"
+ + PROP_KEY + "='%s']/@" + PROP_VALUE;
+
+ private final ResourceResolver resourceResolver;
+
+ private Map<String, Object> resources;
+
+ private boolean fullyLoaded;
+
+ protected final Locale locale;
+
+ JcrResourceBundle(Locale locale, ResourceResolver resourceResolver) {
+ this.locale = locale;
+ this.resourceResolver = resourceResolver;
+ this.resources = new HashMap<String, Object>();
+ this.fullyLoaded = false;
+ }
+
+ @Override
+ protected void setParent(ResourceBundle parent) {
+ super.setParent(parent);
+ }
+
+ @Override
+ public Locale getLocale() {
+ return locale;
+ }
+
+ @Override
+ public Enumeration<String> getKeys() {
+ // ensure all keys are loaded
+ loadFully();
+
+ Enumeration<String> parentKeys = (parent != null)
+ ? parent.getKeys()
+ : null;
+ return new ResourceBundleEnumeration(resources.keySet(), parentKeys);
+ }
+
+ @Override
+ protected Object handleGetObject(String key) {
+ Object value = resources.get(key);
+ if (value == null && !fullyLoaded) {
+ value = loadResource(key);
+ if (value != null) {
+ resources.put(key, value);
+ }
+ }
+ return value;
+ }
+
+ private void loadFully() {
+ if (!fullyLoaded) {
+ Iterator<Map<String, Object>> bundles = resourceResolver.queryResources(
+ getFullLoadQuery(), Query.XPATH);
+ while (bundles.hasNext()) {
+ Map<String, Object> resource = bundles.next();
+ Object key = resource.get(PROP_KEY);
+ if (key instanceof String && !resources.containsKey(key)) {
+ Object value = resource.get(PROP_VALUE);
+ if (value != null) {
+ resources.put((String) key, value);
+ }
+ }
+ }
+ }
+ }
+
+ private Object loadResource(String key) {
+ // query for the resource
+ Iterator<Map<String, Object>> bundles = resourceResolver.queryResources(
+ getResourceQuery(key), Query.XPATH);
+ if (bundles.hasNext()) {
+ Map<String, Object> resource = bundles.next();
+ return resource.get(PROP_VALUE);
+ }
+
+ return null;
+ }
+
+ private String getFullLoadQuery() {
+ return String.format(QUERY_LOAD_FULLY, getLocale());
+ }
+
+ private String getResourceQuery(String key) {
+ return String.format(QUERY_LOAD_RESOURCE, getLocale(), key);
+ }
+
+}
Propchange: incubator/sling/trunk/sling/i18n/src/main/java/org/apache/sling/i18n/impl/JcrResourceBundle.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/sling/trunk/sling/i18n/src/main/java/org/apache/sling/i18n/impl/JcrResourceBundleProvider.java
URL: http://svn.apache.org/viewvc/incubator/sling/trunk/sling/i18n/src/main/java/org/apache/sling/i18n/impl/JcrResourceBundleProvider.java?rev=638552&view=auto
==============================================================================
--- incubator/sling/trunk/sling/i18n/src/main/java/org/apache/sling/i18n/impl/JcrResourceBundleProvider.java (added)
+++ incubator/sling/trunk/sling/i18n/src/main/java/org/apache/sling/i18n/impl/JcrResourceBundleProvider.java Tue Mar 18 13:22:14 2008
@@ -0,0 +1,241 @@
+/*
+ * 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.Dictionary;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+import javax.jcr.Credentials;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.SimpleCredentials;
+import javax.jcr.observation.EventIterator;
+import javax.jcr.observation.EventListener;
+import javax.jcr.observation.ObservationManager;
+
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.i18n.ResourceBundleProvider;
+import org.apache.sling.jcr.api.SlingRepository;
+import org.apache.sling.jcr.resource.JcrResourceResolverFactory;
+import org.osgi.service.component.ComponentContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The <code>JcrResourceBundleProvider</code> TODO
+ *
+ * @scr.component immediate="true" label="%provider.name"
+ * description="%provider.description"
+ * @scr.service interface="org.apache.sling.i18n.ResourceBundleProvider"
+ */
+public class JcrResourceBundleProvider implements ResourceBundleProvider,
+ EventListener {
+
+ /** default log */
+ private final Logger log = LoggerFactory.getLogger(getClass());
+
+ /** @scr.property value="" */
+ private static final String PROP_USER = "user";
+
+ /** @scr.property value="" */
+ private static final String PROP_PASS = "password";
+
+ /** @scr.reference cardinality="0..1" policy="dynamic" */
+ private SlingRepository repository;
+
+ /** @scr.reference cardinality="0..1" policy="dynamic" */
+ private JcrResourceResolverFactory resourceResolverFactory;
+
+ private Credentials repoCredentials;
+
+ private ResourceResolver resourceResolver;
+
+ private Map<Locale, ResourceBundle> resourceBundleCache = new HashMap<Locale, ResourceBundle>();
+
+ public ResourceBundle getResourceBundle(Locale locale) {
+ if (locale == null) {
+ locale = Locale.getDefault();
+ }
+
+ ResourceResolver resolver = getResourceResolver();
+ if (resolver == null) {
+ log.info("createResourceBundle: Missing Resource Resolver, cannot create Resource Bundle");
+ throw new MissingResourceException(
+ "ResourceResolver not available", getClass().getName(), "");
+ }
+
+ return getResourceBundleInternal(resolver, locale);
+ }
+
+ private ResourceBundle getResourceBundleInternal(ResourceResolver resolver, Locale locale) {
+ ResourceBundle resourceBundle = resourceBundleCache.get(locale);
+ if (resourceBundle == null) {
+ resourceBundle = createResourceBundle(resolver, locale);
+ resourceBundleCache.put(locale, resourceBundle);
+ }
+
+ return resourceBundle;
+ }
+
+ private ResourceBundle createResourceBundle(ResourceResolver resolver, Locale locale) {
+
+ JcrResourceBundle bundle = new JcrResourceBundle(locale, resolver);
+
+ // set parent resource bundle
+ Locale parent = getParentLocale(locale);
+ if (parent != null) {
+ bundle.setParent(getResourceBundleInternal(resolver, parent));
+ }
+
+ return bundle;
+ }
+
+ private Locale getParentLocale(Locale locale) {
+ if (locale.getVariant().length() != 0) {
+ return new Locale(locale.getLanguage(), locale.getCountry());
+ } else if (locale.getCountry().length() != 0) {
+ return new Locale(locale.getLanguage());
+ } else if (!locale.getLanguage().equals(
+ Locale.getDefault().getLanguage())) {
+ return Locale.getDefault();
+ }
+
+ // no more parents
+ return null;
+ }
+
+ private ResourceResolver getResourceResolver() {
+ if (resourceResolver == null) {
+ SlingRepository repo = this.repository;
+ JcrResourceResolverFactory fac = this.resourceResolverFactory;
+ if (repo != null && fac != null) {
+ Session s = null;
+ try {
+ if (repoCredentials == null) {
+ s = repo.login();
+ } else {
+ s = repo.login(repoCredentials);
+ }
+
+ ObservationManager om = s.getWorkspace().getObservationManager();
+ om.addEventListener(this, 255, "/", true, null,
+ new String[] { "mix:language" }, true);
+
+ resourceResolver = fac.getResourceResolver(s);
+
+ } catch (RepositoryException re) {
+ // TODO log
+ } finally {
+ // drop session if we can login but not get the resource resolver
+ if (resourceResolver == null && s != null) {
+ s.logout();
+ }
+ }
+
+ }
+ }
+
+ return resourceResolver;
+ }
+
+ private void releaseRepository() {
+ ResourceResolver resolver = this.resourceResolver;
+
+ this.resourceResolver = null;
+ this.resourceBundleCache.clear();
+
+ if (resolver != null) {
+
+ Session s = resolver.adaptTo(Session.class);
+ if (s != null) {
+
+ try {
+ ObservationManager om = s.getWorkspace().getObservationManager();
+ om.removeEventListener(this);
+ } catch (Throwable t) {
+ // TODO log
+ }
+
+ try {
+ s.logout();
+ } catch (Throwable t) {
+ // TODO log
+ }
+ }
+ }
+ }
+
+ // ---------- EventListener ------------------------------------------------
+
+ public void onEvent(EventIterator events) {
+ // don't care for the concrete events, just drop the cache
+ log.info("onEvent: Got " + events.getSize() + " events");
+ resourceBundleCache.clear();
+ }
+
+ // ---------- SCR Integration ----------------------------------------------
+
+ protected void activate(ComponentContext context) {
+ Dictionary<?, ?> props = context.getProperties();
+
+ String user = (String) props.get(PROP_USER);
+ if (user == null || user.length() == 0) {
+ repoCredentials = null;
+ } else {
+ String pass = (String) props.get(PROP_PASS);
+ char[] pwd = (pass == null) ? new char[0] : pass.toCharArray();
+ repoCredentials = new SimpleCredentials(user, pwd);
+ }
+ }
+
+ protected void bindRepository(SlingRepository repository) {
+ if (this.repository != null) {
+ releaseRepository();
+ }
+ this.repository = repository;
+ }
+
+ protected void unbindRepository(SlingRepository repository) {
+ if (this.repository == repository) {
+ releaseRepository();
+ this.repository = null;
+ }
+ }
+
+ protected void bindResourceResolverFactory(
+ JcrResourceResolverFactory resourceResolverFactory) {
+ if (this.resourceResolverFactory != null) {
+ releaseRepository();
+ }
+ this.resourceResolverFactory = resourceResolverFactory;
+ }
+
+ protected void unbindResourceResolverFactory(
+ JcrResourceResolverFactory resourceResolverFactory) {
+ if (this.resourceResolverFactory == resourceResolverFactory) {
+ releaseRepository();
+ this.resourceResolverFactory = null;
+ }
+ }
+}
Propchange: incubator/sling/trunk/sling/i18n/src/main/java/org/apache/sling/i18n/impl/JcrResourceBundleProvider.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/sling/trunk/sling/i18n/src/main/java/org/apache/sling/i18n/impl/ResourceBundleEnumeration.java
URL: http://svn.apache.org/viewvc/incubator/sling/trunk/sling/i18n/src/main/java/org/apache/sling/i18n/impl/ResourceBundleEnumeration.java?rev=638552&view=auto
==============================================================================
--- incubator/sling/trunk/sling/i18n/src/main/java/org/apache/sling/i18n/impl/ResourceBundleEnumeration.java (added)
+++ incubator/sling/trunk/sling/i18n/src/main/java/org/apache/sling/i18n/impl/ResourceBundleEnumeration.java Tue Mar 18 13:22:14 2008
@@ -0,0 +1,82 @@
+/*
+ * 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.Iterator;
+import java.util.NoSuchElementException;
+import java.util.Set;
+
+public class ResourceBundleEnumeration implements Enumeration<String> {
+
+ private final Set<String> keys;
+ private Enumeration<String> parentKeys;
+
+ private Iterator<String> keysIterator;
+ private String next;
+
+ public ResourceBundleEnumeration(Set<String> keys, Enumeration<String> parentKeys) {
+ this.keys = keys;
+ this.parentKeys = parentKeys;
+ this.keysIterator = keys.iterator();
+
+ next = seek();
+ }
+
+ public boolean hasMoreElements() {
+ return next != null;
+ }
+
+ public String nextElement() {
+ if (!hasMoreElements()) {
+ throw new NoSuchElementException();
+ }
+
+ String result = next;
+ next = seek();
+ return result;
+ }
+
+ private String seek() {
+ if (keysIterator != null) {
+
+ if (keysIterator.hasNext()) {
+ return keysIterator.next();
+ }
+
+ // my keys are exhausted, set iterator to null
+ keysIterator = null;
+ }
+
+ if (parentKeys != null) {
+ while (parentKeys.hasMoreElements()) {
+ String parentKey = parentKeys.nextElement();
+ if (!keys.contains(parentKey)) {
+ return parentKey;
+ }
+ }
+
+ // no more parent keys, set enumeration to null
+ parentKeys = null;
+ }
+
+ // parentKeys are also exhausted, nothing more to return
+ return null;
+ }
+}
Propchange: incubator/sling/trunk/sling/i18n/src/main/java/org/apache/sling/i18n/impl/ResourceBundleEnumeration.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/sling/trunk/sling/i18n/src/main/resources/OSGI-INF/metatype/metatype.properties
URL: http://svn.apache.org/viewvc/incubator/sling/trunk/sling/i18n/src/main/resources/OSGI-INF/metatype/metatype.properties?rev=638552&view=auto
==============================================================================
--- incubator/sling/trunk/sling/i18n/src/main/resources/OSGI-INF/metatype/metatype.properties (added)
+++ incubator/sling/trunk/sling/i18n/src/main/resources/OSGI-INF/metatype/metatype.properties Tue Mar 18 13:22:14 2008
@@ -0,0 +1,48 @@
+#
+# 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.
+#
+
+#
+# (Default) Locale Resolver Filter
+locale.name = Locale Resolver Filter
+locale.description = Request Level filter which extracts the primary locale \
+ from the Request, which has been transferred from the client in the HTTP \
+ Accept-Language header. If a LocaleResolver service has been registered, that \
+ service is called instead of getting the HTTP header value for the locale.
+locale.default.name = Default Locale
+locale.default.description = The default locale to assume if none can be \
+ resolved from a LocalResolver service or the HTTP Accept-Language header. This \
+ value must be in the form acceptable to the =java.util.Locale= class.
+
+
+provider.name = JCR ResourceBundle Provider
+provider.description = ResourceBundleProvider service which loads the messages \
+ from the repository. You may configure how the provider accesses the \
+ repository if the user name field is left empty, the provider accesses the \
+ repository anonymously. Otherwise the given user name and password are used \
+ to access the repository. Failing to access the repository, effectively \
+ disables the provider.
+
+user.name = User Name
+user.description = The name of the user to log in to the repository to get the \
+ resources. If this field is empty, the provider accesses the repository as \
+ the anonymous user.
+
+password.name = Password
+password.description = The password used to log in to the repository to get \
+ the resources. This field is only used if the user name field is not empty.
\ No newline at end of file
Propchange: incubator/sling/trunk/sling/i18n/src/main/resources/OSGI-INF/metatype/metatype.properties
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/sling/trunk/sling/i18n/src/main/resources/SLING-INF/nodetypes/language.cnd
URL: http://svn.apache.org/viewvc/incubator/sling/trunk/sling/i18n/src/main/resources/SLING-INF/nodetypes/language.cnd?rev=638552&view=auto
==============================================================================
--- incubator/sling/trunk/sling/i18n/src/main/resources/SLING-INF/nodetypes/language.cnd (added)
+++ incubator/sling/trunk/sling/i18n/src/main/resources/SLING-INF/nodetypes/language.cnd Tue Mar 18 13:22:14 2008
@@ -0,0 +1,27 @@
+//
+// 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.
+//
+
+<mix = 'http://www.jcp.org/jcr/mix/1.0'>
+
+// Mixin node type for I18N resources
+// This mixin node type is defined in the JSR-283 specification and is
+// listed here to backport this node type into JSR-170 repositories
+[mix:language]
+ mixin
+ - jcr:language (string)
Propchange: incubator/sling/trunk/sling/i18n/src/main/resources/SLING-INF/nodetypes/language.cnd
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/sling/trunk/sling/i18n/src/main/resources/SLING-INF/nodetypes/message.cnd
URL: http://svn.apache.org/viewvc/incubator/sling/trunk/sling/i18n/src/main/resources/SLING-INF/nodetypes/message.cnd?rev=638552&view=auto
==============================================================================
--- incubator/sling/trunk/sling/i18n/src/main/resources/SLING-INF/nodetypes/message.cnd (added)
+++ incubator/sling/trunk/sling/i18n/src/main/resources/SLING-INF/nodetypes/message.cnd Tue Mar 18 13:22:14 2008
@@ -0,0 +1,30 @@
+//
+// 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.
+//
+
+<sling = 'http://sling.apache.org/jcr/sling/1.0'>
+
+// Mixin node type for a single key to message mapping
+// This mixin node type may be applied to any node such, that mappings
+// may be located just inside some existing node hierarchy
+[sling:message]
+ mixin
+ - sling:key (string)
+ - sling:message (undefined)
+
+[sling:messageEntry] > nt:unstructured, sling:message
\ No newline at end of file
Propchange: incubator/sling/trunk/sling/i18n/src/main/resources/SLING-INF/nodetypes/message.cnd
------------------------------------------------------------------------------
svn:eol-style = native