From fd207f947353ca7c3e6e80fe7bf7d7bcf38d47f2 Mon Sep 17 00:00:00 2001 From: Dirk Fauth Date: Wed, 19 Feb 2014 13:43:52 +0100 Subject: Bug 428427 - introduced ResourceBundleProvider to increase extensibility for loading resource bundles Change-Id: I1680710b807ff0d228c5f4bbd7c2e5be92048a3a Signed-off-by: Dirk Fauth --- .../META-INF/MANIFEST.MF | 4 +- .../OSGI-INF/resourcebundleprovider.xml | 8 ++ .../services/BundleTranslationProvider.java | 99 +++------------------- .../services/DefaultResourceBundleProvider.java | 60 +++++++++++++ .../services/MessageFactoryServiceImpl.java | 16 ++-- .../internal/services/ResourceBundleHelper.java | 14 +-- .../services/TranslationObjectSupplier.java | 6 +- .../core/services/nls/IMessageFactoryService.java | 6 +- .../translation/ResourceBundleProvider.java | 43 ++++++++++ .../services/translation/TranslationService.java | 50 ++++++++++- 10 files changed, 191 insertions(+), 115 deletions(-) create mode 100644 bundles/org.eclipse.e4.core.services/OSGI-INF/resourcebundleprovider.xml create mode 100644 bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/internal/services/DefaultResourceBundleProvider.java create mode 100644 bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/translation/ResourceBundleProvider.java diff --git a/bundles/org.eclipse.e4.core.services/META-INF/MANIFEST.MF b/bundles/org.eclipse.e4.core.services/META-INF/MANIFEST.MF index 912c58026..57b3f2147 100644 --- a/bundles/org.eclipse.e4.core.services/META-INF/MANIFEST.MF +++ b/bundles/org.eclipse.e4.core.services/META-INF/MANIFEST.MF @@ -42,5 +42,5 @@ Export-Package: org.eclipse.e4.core.internal.services;x-friends:="org.eclipse.e4 Eclipse-ExtensibleAPI: true Bundle-ClassPath: injection_annotations.jar, . Bundle-Activator: org.eclipse.e4.core.internal.services.ServicesActivator -Service-Component: OSGI-INF/translationsupplier.xml, - OSGI-INF/messagesfactory.xml +Service-Component: OSGI-INF/translationsupplier.xml,OSGI-INF/messagesfactory.xml, + OSGI-INF/resourcebundleprovider.xml diff --git a/bundles/org.eclipse.e4.core.services/OSGI-INF/resourcebundleprovider.xml b/bundles/org.eclipse.e4.core.services/OSGI-INF/resourcebundleprovider.xml new file mode 100644 index 000000000..79e0b6412 --- /dev/null +++ b/bundles/org.eclipse.e4.core.services/OSGI-INF/resourcebundleprovider.xml @@ -0,0 +1,8 @@ + + + + + + + > + diff --git a/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/internal/services/BundleTranslationProvider.java b/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/internal/services/BundleTranslationProvider.java index 848d2a1fd..9b58a573d 100644 --- a/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/internal/services/BundleTranslationProvider.java +++ b/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/internal/services/BundleTranslationProvider.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2011 IBM Corporation and others. + * Copyright (c) 2011, 2014 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -7,107 +7,28 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Dirk Fauth - Bug 428427 ******************************************************************************/ package org.eclipse.e4.core.internal.services; -import java.net.URI; -import java.net.URISyntaxException; -import java.util.MissingResourceException; import java.util.ResourceBundle; +import javax.inject.Inject; +import org.eclipse.e4.core.services.translation.ResourceBundleProvider; import org.eclipse.e4.core.services.translation.TranslationService; -import org.eclipse.osgi.service.localization.BundleLocalization; -import org.osgi.framework.Bundle; -import org.osgi.service.log.LogService; -import org.osgi.service.packageadmin.PackageAdmin; -// There is no replacement for PackageAdmin#getBundles() -@SuppressWarnings("deprecation") public class BundleTranslationProvider extends TranslationService { - /** - * The schema identifier used for Eclipse platform references - */ - final private static String PLATFORM_SCHEMA = "platform"; //$NON-NLS-1$ - final private static String PLUGIN_SEGMENT = "/plugin/"; //$NON-NLS-1$ - final private static String FRAGMENT_SEGMENT = "/fragment/"; //$NON-NLS-1$ - - /** - * Prefix for keys to be translated - */ - private static final String KEY_PREFIX = "%"; //$NON-NLS-1$ - - /** - * Prefix that aborts translation - */ - private static final String KEY_DOUBLE_PREFIX = "%%"; //$NON-NLS-1$ + @Inject + ResourceBundleProvider provider; @Override public String translate(String key, String contributorURI) { - Bundle bundle = getBundle(contributorURI); - if (bundle == null) - return key; - BundleLocalization localizationService = ServicesActivator.getDefault() - .getLocalizationService(); - if (localizationService == null) + if (provider == null) return key; - // TBD locale might contain extra information, such as calendar specification - // that might need to be removed. - ResourceBundle resourceBundle = localizationService.getLocalization(bundle, locale); - return getResourceString(key, resourceBundle); - } - private Bundle getBundle(String contributorURI) { - if (contributorURI == null) - return null; - URI uri; - try { - uri = new URI(contributorURI); - } catch (URISyntaxException e) { - LogService logService = ServicesActivator.getDefault().getLogService(); - if (logService != null) - logService.log(LogService.LOG_ERROR, "Invalid contributor URI: " + contributorURI); //$NON-NLS-1$ - return null; - } - if (!PLATFORM_SCHEMA.equals(uri.getScheme())) - return null; // not implemented - String bundleName = uri.getPath(); - if (bundleName.startsWith(PLUGIN_SEGMENT)) - bundleName = bundleName.substring(PLUGIN_SEGMENT.length()); - else if (bundleName.startsWith(FRAGMENT_SEGMENT)) - bundleName = bundleName.substring(FRAGMENT_SEGMENT.length()); - PackageAdmin packageAdmin = ServicesActivator.getDefault().getPackageAdmin(); - Bundle[] bundles = packageAdmin.getBundles(bundleName, null); - if (bundles == null) - return null; - // Return the first bundle that is not installed or uninstalled - for (int i = 0; i < bundles.length; i++) { - if ((bundles[i].getState() & (Bundle.INSTALLED | Bundle.UNINSTALLED)) == 0) { - return bundles[i]; - } - } - return null; - } - - public String getResourceString(String value, ResourceBundle resourceBundle) { - String s = value.trim(); - if (!s.startsWith(KEY_PREFIX, 0)) - return s; - if (s.startsWith(KEY_DOUBLE_PREFIX, 0)) - return s.substring(1); - - int ix = s.indexOf(' '); - String key = ix == -1 ? s : s.substring(0, ix); - String dflt = ix == -1 ? s : s.substring(ix + 1); - - if (resourceBundle == null) - return dflt; - - try { - return resourceBundle.getString(key.substring(1)); - } catch (MissingResourceException e) { - // this will avoid requiring a bundle access on the next lookup - return dflt; - } + ResourceBundle resourceBundle = ResourceBundleHelper.getResourceBundleForUri( + contributorURI, ResourceBundleHelper.toLocale(locale), provider); + return getResourceString(key, resourceBundle); } } diff --git a/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/internal/services/DefaultResourceBundleProvider.java b/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/internal/services/DefaultResourceBundleProvider.java new file mode 100644 index 000000000..373592552 --- /dev/null +++ b/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/internal/services/DefaultResourceBundleProvider.java @@ -0,0 +1,60 @@ +/******************************************************************************* + * Copyright (c) 2014 Dirk Fauth and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Dirk Fauth - initial API and implementation + ******************************************************************************/ +package org.eclipse.e4.core.internal.services; + +import java.util.ResourceBundle; +import org.eclipse.e4.core.services.translation.ResourceBundleProvider; +import org.eclipse.osgi.service.localization.BundleLocalization; +import org.osgi.framework.Bundle; + +/** + * Default implementation of {@link ResourceBundleProvider} that simply delegates to the + * {@link BundleLocalization} for retrieving the {@link ResourceBundle}. + */ +public class DefaultResourceBundleProvider implements ResourceBundleProvider { + + private BundleLocalization localization; + + @Override + public ResourceBundle getResourceBundle(Bundle bundle, String locale) { + if (localization != null) + return localization.getLocalization(bundle, locale); + + return null; + } + + /** + * Method called by DS to set the {@link BundleLocalization} to this + * {@link ResourceBundleProvider}. + * + * @param localization + * The {@link BundleLocalization} that should be set to this + * {@link ResourceBundleProvider} + */ + public void setBundleLocalization(BundleLocalization localization) { + this.localization = localization; + } + + /** + * Method called by DS to unset the {@link BundleLocalization} from this + * {@link ResourceBundleProvider}. + * + * @param localization + * The {@link BundleLocalization} to remove from this {@link ResourceBundleProvider}. + * If the given {@link BundleLocalization} is not the same that is already set, + * nothing will happen. + */ + public void unsetBundleLocalization(BundleLocalization localization) { + if (this.localization == localization) { + this.localization = null; + } + } +} diff --git a/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/internal/services/MessageFactoryServiceImpl.java b/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/internal/services/MessageFactoryServiceImpl.java index 6175a4945..f45b63935 100644 --- a/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/internal/services/MessageFactoryServiceImpl.java +++ b/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/internal/services/MessageFactoryServiceImpl.java @@ -29,7 +29,7 @@ import javax.annotation.PostConstruct; import org.eclipse.e4.core.services.nls.IMessageFactoryService; import org.eclipse.e4.core.services.nls.Message; import org.eclipse.e4.core.services.nls.Message.ReferenceType; -import org.eclipse.osgi.service.localization.BundleLocalization; +import org.eclipse.e4.core.services.translation.ResourceBundleProvider; import org.osgi.framework.Bundle; import org.osgi.framework.FrameworkUtil; import org.osgi.service.log.LogService; @@ -49,7 +49,7 @@ public class MessageFactoryServiceImpl implements IMessageFactoryService { @Override public M getMessageInstance(final Locale locale, final Class messages, - final BundleLocalization localization) { + final ResourceBundleProvider provider) { String key = messages.getName() + "_" + locale; //$NON-NLS-1$ final Message annotation = messages.getAnnotation(Message.class); @@ -94,12 +94,12 @@ public class MessageFactoryServiceImpl implements IMessageFactoryService { M instance; if (System.getSecurityManager() == null) { - instance = createInstance(locale, messages, annotation, localization); + instance = createInstance(locale, messages, annotation, provider); } else { instance = AccessController.doPrivileged(new PrivilegedAction() { public M run() { - return createInstance(locale, messages, annotation, localization); + return createInstance(locale, messages, annotation, provider); } }); @@ -146,7 +146,7 @@ public class MessageFactoryServiceImpl implements IMessageFactoryService { * @param annotation * The annotation that is used in the message class. If specified it is needed to * retrieve the URI of the location to search for the {@link ResourceBundle}. - * @param localization + * @param rbProvider * The service that is needed to retrieve {@link ResourceBundle} objects from a * bundle with a given locale. * @@ -154,12 +154,12 @@ public class MessageFactoryServiceImpl implements IMessageFactoryService { * null if an error occured on creating the instance. */ private static M createInstance(Locale locale, Class messages, Message annotation, - BundleLocalization localization) { + ResourceBundleProvider rbProvider) { ResourceBundle resourceBundle = null; if (annotation != null && annotation.contributorURI().length() > 0) { resourceBundle = ResourceBundleHelper.getResourceBundleForUri( - annotation.contributorURI(), locale, localization); + annotation.contributorURI(), locale, rbProvider); } if (resourceBundle == null) { @@ -181,7 +181,7 @@ public class MessageFactoryServiceImpl implements IMessageFactoryService { if (resourceBundle == null) { // retrieve the OSGi resource bundle Bundle bundle = FrameworkUtil.getBundle(messages); - resourceBundle = localization.getLocalization(bundle, locale.toString()); + resourceBundle = rbProvider.getResourceBundle(bundle, locale.toString()); } // always create a provider, if there is no resource bundle found, simply the modified keys diff --git a/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/internal/services/ResourceBundleHelper.java b/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/internal/services/ResourceBundleHelper.java index 40f51931e..791d76c0e 100644 --- a/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/internal/services/ResourceBundleHelper.java +++ b/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/internal/services/ResourceBundleHelper.java @@ -25,7 +25,7 @@ import java.util.MissingResourceException; import java.util.PropertyResourceBundle; import java.util.ResourceBundle; import java.util.ResourceBundle.Control; -import org.eclipse.osgi.service.localization.BundleLocalization; +import org.eclipse.e4.core.services.translation.ResourceBundleProvider; import org.osgi.framework.Bundle; import org.osgi.service.log.LogService; import org.osgi.service.packageadmin.PackageAdmin; @@ -82,13 +82,13 @@ public class ResourceBundleHelper { * The URI that points to a {@link ResourceBundle} * @param locale * The {@link Locale} to use for loading the {@link ResourceBundle} - * @param localization + * @param provider * The service for retrieving a {@link ResourceBundle} for a given {@link Locale} out * of the given {@link Bundle} which is specified by URI. * @return */ public static ResourceBundle getResourceBundleForUri(String contributorURI, Locale locale, - BundleLocalization localization) { + ResourceBundleProvider provider) { if (contributorURI == null) return null; @@ -157,10 +157,10 @@ public class ResourceBundleHelper { result = getEquinoxResourceBundle(resourcePath.replace('.', '/'), locale, bundle); } else { - // there is no class and no special resource specified within the URI - // therefore we load the OSGi resource bundle out of the specified Bundle - // for the current Locale - result = localization.getLocalization(bundle, locale.toString()); + // There is no class and no special resource specified within the URI + // therefore we load the OSresource bundle out of the specified Bundle + // for the current Locale. Typically this will be the OSGi ResourceBundle + result = provider.getResourceBundle(bundle, locale.toString()); } } } diff --git a/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/internal/services/TranslationObjectSupplier.java b/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/internal/services/TranslationObjectSupplier.java index 50be79178..0da507f3f 100644 --- a/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/internal/services/TranslationObjectSupplier.java +++ b/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/internal/services/TranslationObjectSupplier.java @@ -29,6 +29,7 @@ import org.eclipse.e4.core.di.suppliers.IObjectDescriptor; import org.eclipse.e4.core.di.suppliers.IRequestor; import org.eclipse.e4.core.services.nls.IMessageFactoryService; import org.eclipse.e4.core.services.nls.Message; +import org.eclipse.e4.core.services.translation.ResourceBundleProvider; import org.eclipse.e4.core.services.translation.TranslationService; import org.eclipse.osgi.service.localization.BundleLocalization; import org.osgi.service.log.LogService; @@ -47,7 +48,7 @@ public class TranslationObjectSupplier extends ExtendedObjectSupplier { * The service that gets {@link ResourceBundle} objects from a bundle with a given locale. */ @Inject - private BundleLocalization localization; + private ResourceBundleProvider provider; /** * The service that creates instances of message classes based on the current active locale, the @@ -125,8 +126,7 @@ public class TranslationObjectSupplier extends ExtendedObjectSupplier { * @return The instance of the requested message class */ private Object getMessageInstance(Class descriptorsClass) { - return this.factoryService.getMessageInstance(this.locale, descriptorsClass, - this.localization); + return this.factoryService.getMessageInstance(this.locale, descriptorsClass, this.provider); } /** diff --git a/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/nls/IMessageFactoryService.java b/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/nls/IMessageFactoryService.java index cc7610c2c..f482cf380 100644 --- a/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/nls/IMessageFactoryService.java +++ b/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/nls/IMessageFactoryService.java @@ -12,7 +12,7 @@ package org.eclipse.e4.core.services.nls; import java.util.Locale; import java.util.ResourceBundle; -import org.eclipse.osgi.service.localization.BundleLocalization; +import org.eclipse.e4.core.services.translation.ResourceBundleProvider; /** * Service that is responsible for creating and managing message class instances. @@ -30,11 +30,11 @@ public interface IMessageFactoryService { * The {@link Locale} for which the message class instance is requested. * @param messages * The type of the message class whose instance is requested. - * @param localization + * @param provider * The service that is needed to retrieve {@link ResourceBundle} objects from a * bundle with a given locale. * @return An instance of the given messages class and {@link Locale}. */ public M getMessageInstance(final Locale locale, final Class messages, - BundleLocalization localization); + ResourceBundleProvider provider); } diff --git a/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/translation/ResourceBundleProvider.java b/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/translation/ResourceBundleProvider.java new file mode 100644 index 000000000..9b847699b --- /dev/null +++ b/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/translation/ResourceBundleProvider.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright (c) 2014 Dirk Fauth and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Dirk Fauth - initial API and implementation + ******************************************************************************/ +package org.eclipse.e4.core.services.translation; + +import java.util.ResourceBundle; +import org.eclipse.osgi.service.localization.BundleLocalization; +import org.osgi.framework.Bundle; + +/** + * The interface of the service that gets {@link ResourceBundle} objects from a given bundle with a + * given locale. + *

+ * This service abstracts out the reference to the {@link BundleLocalization} and enables the + * possibility to load {@link ResourceBundle}s from different locations than the default OSGi + * context. + *

+ * + * @since 1.2 + */ +public interface ResourceBundleProvider { + + /** + * Returns a ResourceBundle object for the given bundle and locale. + * + * @param bundle + * the bundle to get localization for + * @param locale + * the name of the locale to get, or null if the default locale is to be + * used + * + * @return A ResourceBundle object for the given bundle and locale, or + * null is returned if no ResourceBundle object can be loaded. + */ + ResourceBundle getResourceBundle(Bundle bundle, String locale); +} diff --git a/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/translation/TranslationService.java b/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/translation/TranslationService.java index f51705922..9ff0c9833 100644 --- a/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/translation/TranslationService.java +++ b/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/translation/TranslationService.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2011 IBM Corporation and others. + * Copyright (c) 2011, 2014 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -7,21 +7,32 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Dirk Fauth - Bug 428427 ******************************************************************************/ package org.eclipse.e4.core.services.translation; +import java.util.MissingResourceException; +import java.util.ResourceBundle; import javax.inject.Inject; import javax.inject.Named; /** * Provides localization service. */ -abstract public class TranslationService { +public abstract class TranslationService { /** * The name of the context variable with locale information */ - static public final String LOCALE = "org.eclipse.e4.core.locale"; //$NON-NLS-1$ + public static final String LOCALE = "org.eclipse.e4.core.locale"; //$NON-NLS-1$ + /** + * Prefix for keys to be translated + */ + private static final String KEY_PREFIX = "%"; //$NON-NLS-1$ + /** + * Prefix that aborts translation + */ + private static final String KEY_DOUBLE_PREFIX = "%%"; //$NON-NLS-1$ @Inject @Named(LOCALE) @@ -48,4 +59,37 @@ abstract public class TranslationService { public String translate(String key, String contributorURI) { return key; } + + /** + * Returns the value out of the given ResourceBundle for the given translation key. Note that + * this method will only work correctly if the key matches the specification of a translation + * key in the application model. That means, it needs to start with a % character. + * + * @param key + * The value that is set as key in the application model. + * @param resourceBundle + * The ResourceBundle that should be used to retrieve the translation. + * @return The value value out of the given ResourceBundle for the given translation key. + */ + protected String getResourceString(String key, ResourceBundle resourceBundle) { + String s = key.trim(); + if (!s.startsWith(KEY_PREFIX, 0)) + return s; + if (s.startsWith(KEY_DOUBLE_PREFIX, 0)) + return s.substring(1); + + int ix = s.indexOf(' '); + String rbKey = ix == -1 ? s : s.substring(0, ix); + String dflt = ix == -1 ? s : s.substring(ix + 1); + + if (resourceBundle == null) + return dflt; + + try { + return resourceBundle.getString(rbKey.substring(1)); + } catch (MissingResourceException e) { + // this will avoid requiring a bundle access on the next lookup + return dflt; + } + } } -- cgit v1.2.3