/container/src/main/java/com/atlassian/plugin/remotable/container/service/sal/ContainerI18nResolver.java

https://bitbucket.org/rodogu/remotable-plugins · Java · 243 lines · 214 code · 24 blank · 5 comment · 17 complexity · 6eab9c0dda15850e040798cab7c15602 MD5 · raw file

  1. package com.atlassian.plugin.remotable.container.service.sal;
  2. import java.io.Serializable;
  3. import java.text.MessageFormat;
  4. import java.util.Enumeration;
  5. import java.util.HashMap;
  6. import java.util.LinkedList;
  7. import java.util.List;
  8. import java.util.Locale;
  9. import java.util.Map;
  10. import java.util.Map.Entry;
  11. import java.util.MissingResourceException;
  12. import java.util.ResourceBundle;
  13. import java.util.concurrent.ConcurrentHashMap;
  14. import java.util.concurrent.locks.ReentrantReadWriteLock;
  15. import com.atlassian.plugin.Plugin;
  16. import com.atlassian.plugin.PluginAccessor;
  17. import com.atlassian.plugin.elements.ResourceDescriptor;
  18. import com.atlassian.plugin.event.PluginEventListener;
  19. import com.atlassian.plugin.event.PluginEventManager;
  20. import com.atlassian.plugin.event.events.PluginDisabledEvent;
  21. import com.atlassian.plugin.event.events.PluginEnabledEvent;
  22. import com.atlassian.sal.core.message.AbstractI18nResolver;
  23. import com.atlassian.util.concurrent.ManagedLock;
  24. import com.atlassian.util.concurrent.ManagedLocks;
  25. import com.atlassian.util.concurrent.Supplier;
  26. /**
  27. * Returns the key with args as a string
  28. */
  29. public class ContainerI18nResolver extends AbstractI18nResolver
  30. {
  31. private ManagedLock.ReadWrite locks = ManagedLocks.manageReadWrite(new ReentrantReadWriteLock());
  32. private final Map<Plugin, Iterable<String>> pluginResourceBundleNames = new ConcurrentHashMap<Plugin, Iterable<String>>();
  33. private final ResourceBundleResolver resolver;
  34. public ContainerI18nResolver(final PluginAccessor pluginAccessor,
  35. PluginEventManager pluginEventManager,
  36. ResourceBundleResolver resolver)
  37. {
  38. pluginEventManager.register(this);
  39. this.resolver = assertNotNull(resolver, "resolver");
  40. locks.write().withLock(new Runnable()
  41. {
  42. public void run()
  43. {
  44. addPluginResourceBundles(pluginAccessor.getPlugins());
  45. }
  46. });
  47. }
  48. public String getRawText(String key)
  49. {
  50. String pattern = getPattern(key);
  51. if (pattern == null)
  52. {
  53. pattern = key;
  54. }
  55. return pattern;
  56. }
  57. public String resolveText(String key, Serializable[] arguments)
  58. {
  59. String pattern = getPattern(key);
  60. if (pattern == null)
  61. {
  62. return key;
  63. }
  64. return MessageFormat.format(pattern, (Object[]) arguments);
  65. }
  66. private String getPattern(final String key)
  67. {
  68. return locks.read().withLock(new Supplier<String>()
  69. {
  70. public String get()
  71. {
  72. String bundleString = null;
  73. for (Entry<Plugin, Iterable<String>> pluginBundleNames : pluginResourceBundleNames.entrySet())
  74. {
  75. for (String bundleName : pluginBundleNames.getValue())
  76. {
  77. try
  78. {
  79. ResourceBundle bundle = getBundle(bundleName, Locale.getDefault(), pluginBundleNames.getKey());
  80. bundleString = bundle.getString(key);
  81. }
  82. catch (MissingResourceException e)
  83. {
  84. // ignore, try next bundle
  85. }
  86. }
  87. }
  88. return bundleString;
  89. }
  90. });
  91. }
  92. public Map<String, String> getAllTranslationsForPrefix(final String prefix)
  93. {
  94. assertNotNull(prefix, "prefix");
  95. return locks.read().withLock(new Supplier<Map<String, String>>()
  96. {
  97. public Map<String, String> get()
  98. {
  99. Map<String, String> translationsWithPrefix = new HashMap<String, String>();
  100. for (Entry<Plugin, Iterable<String>> pluginBundleNames : pluginResourceBundleNames.entrySet())
  101. {
  102. addMatchingTranslationsToMap(
  103. prefix, Locale.getDefault(), pluginBundleNames.getKey(), pluginBundleNames.getValue(), translationsWithPrefix);
  104. }
  105. return translationsWithPrefix;
  106. }
  107. });
  108. }
  109. public Map<String, String> getAllTranslationsForPrefix(final String prefix, final Locale locale)
  110. {
  111. assertNotNull(prefix, "prefix");
  112. assertNotNull(locale, "locale");
  113. return locks.read().withLock(new Supplier<Map<String, String>>()
  114. {
  115. public Map<String, String> get()
  116. {
  117. Map<String, String> translationsWithPrefix = new HashMap<String, String>();
  118. for (Entry<Plugin, Iterable<String>> pluginBundleNames : pluginResourceBundleNames.entrySet())
  119. {
  120. addMatchingTranslationsToMap(
  121. prefix, locale, pluginBundleNames.getKey(), pluginBundleNames.getValue(), translationsWithPrefix);
  122. }
  123. return translationsWithPrefix;
  124. }
  125. });
  126. }
  127. private void addMatchingTranslationsToMap(String prefix, Locale locale, Plugin plugin,
  128. Iterable<String> bundleNames,
  129. Map<String, String> translationsWithPrefix)
  130. {
  131. for (String bundleName : bundleNames)
  132. {
  133. try
  134. {
  135. ResourceBundle bundle = getBundle(bundleName, locale, plugin);
  136. if (bundle != null)
  137. {
  138. addMatchingTranslationsToMap(prefix, bundle, translationsWithPrefix);
  139. }
  140. }
  141. catch (MissingResourceException e)
  142. {
  143. // OK, just ignore
  144. }
  145. }
  146. }
  147. private void addMatchingTranslationsToMap(String prefix, ResourceBundle bundle,
  148. Map<String, String> translationsWithPrefix)
  149. {
  150. Enumeration enumeration = bundle.getKeys();
  151. while (enumeration.hasMoreElements())
  152. {
  153. String key = (String) enumeration.nextElement();
  154. if (key.startsWith(prefix))
  155. {
  156. translationsWithPrefix.put(key, bundle.getString(key));
  157. }
  158. }
  159. }
  160. @PluginEventListener
  161. public void pluginEnabled(final PluginEnabledEvent event)
  162. {
  163. locks.write().withLock(new Runnable()
  164. {
  165. public void run()
  166. {
  167. addPluginResourceBundles(event.getPlugin());
  168. }
  169. });
  170. }
  171. @PluginEventListener
  172. public void pluginDisabled(final PluginDisabledEvent event)
  173. {
  174. locks.write().withLock(new Runnable()
  175. {
  176. public void run()
  177. {
  178. removePluginResourceBundles(event.getPlugin());
  179. }
  180. });
  181. }
  182. private void addPluginResourceBundles(Iterable<Plugin> plugins)
  183. {
  184. for (Plugin plugin : plugins)
  185. {
  186. addPluginResourceBundles(plugin);
  187. }
  188. }
  189. private void addPluginResourceBundles(Plugin plugin)
  190. {
  191. List<String> bundleNames = new LinkedList<String>();
  192. Iterable<ResourceDescriptor> descriptors = plugin.getResourceDescriptors("i18n");
  193. for (ResourceDescriptor descriptor : descriptors)
  194. {
  195. bundleNames.add(descriptor.getLocation());
  196. }
  197. addPluginResourceBundles(plugin, bundleNames);
  198. }
  199. private void addPluginResourceBundles(Plugin plugin, List<String> bundleNames)
  200. {
  201. pluginResourceBundleNames.put(plugin, bundleNames);
  202. }
  203. private void removePluginResourceBundles(Plugin plugin)
  204. {
  205. pluginResourceBundleNames.remove(plugin);
  206. }
  207. private ResourceBundle getBundle(String bundleName, Locale locale, Plugin plugin)
  208. {
  209. return resolver.getBundle(bundleName, locale, plugin.getClassLoader());
  210. }
  211. private static <T> T assertNotNull(T object, String name)
  212. {
  213. if (object == null)
  214. {
  215. throw new NullPointerException(name + " must not be null");
  216. }
  217. return object;
  218. }
  219. }