View Javadoc
1   /*******************************************************************************
2    * Portions created by Sebastian Thomschke are copyright (c) 2005-2015 Sebastian
3    * Thomschke.
4    *
5    * All Rights Reserved. This program and the accompanying materials
6    * are made available under the terms of the Eclipse Public License v1.0
7    * which accompanies this distribution, and is available at
8    * http://www.eclipse.org/legal/epl-v10.html
9    *
10   * Contributors:
11   *     Sebastian Thomschke - initial implementation.
12   *******************************************************************************/
13  package net.sf.oval.localization.message;
14  
15  import static net.sf.oval.Validator.*;
16  
17  import java.util.ArrayList;
18  import java.util.Enumeration;
19  import java.util.List;
20  import java.util.Locale;
21  import java.util.Map;
22  import java.util.MissingResourceException;
23  import java.util.ResourceBundle;
24  
25  import net.sf.oval.Validator;
26  import net.sf.oval.internal.Log;
27  import net.sf.oval.internal.util.Assert;
28  
29  /**
30   * Default implementation that resolves messages based
31   * on the registered resource bundles.
32   *
33   * @author Sebastian Thomschke
34   */
35  public class ResourceBundleMessageResolver implements MessageResolver
36  {
37  	private static final Log LOG = Log.getLog(ResourceBundleMessageResolver.class);
38  
39  	public static final ResourceBundleMessageResolver INSTANCE = new ResourceBundleMessageResolver();
40  
41  	public static final Locale ROOT_LOCALE = new Locale("", "", "");
42  
43  	private final Map<ResourceBundle, List<String>> messageBundleKeys = getCollectionFactory().createMap(8);
44  	private final Map<Locale, ArrayList<ResourceBundle>> messageBundlesByLocale = getCollectionFactory().createMap(8);
45  
46  	/**
47  	 * Adds a message bundle
48  	 *
49  	 * @return true if the bundle was registered and false if it was already registered
50  	 */
51  	public boolean addMessageBundle(final ResourceBundle mb)
52  	{
53  		return addMessageBundle(mb, mb.getLocale());
54  	}
55  
56  	protected boolean addMessageBundle(final ResourceBundle bundle, final Locale locale)
57  	{
58  		final ArrayList<ResourceBundle> bundles = getMessageBundlesForLocale(locale);
59  
60  		if (bundles.contains(bundle)) return false;
61  
62  		bundles.add(0, bundle);
63  
64  		if (!messageBundleKeys.containsKey(bundle))
65  		{
66  			final List<String> keys = getCollectionFactory().createList();
67  			for (final Enumeration<String> keysEnum = bundle.getKeys(); keysEnum.hasMoreElements();)
68  			{
69  				keys.add(keysEnum.nextElement());
70  			}
71  			messageBundleKeys.put(bundle, keys);
72  		}
73  
74  		return true;
75  	}
76  
77  	public String getMessage(final String key)
78  	{
79  		final Locale l = Validator.getLocaleProvider().getLocale();
80  		String msg = getMessage(key, l);
81  		if (msg == null && !l.equals(Locale.getDefault()))
82  		{
83  			msg = getMessage(key, Locale.getDefault());
84  		}
85  		return msg;
86  	}
87  
88  	protected String getMessage(final String key, final Locale locale)
89  	{
90  		final List<ResourceBundle> bundles = getMessageBundlesForLocale(locale);
91  
92  		for (final ResourceBundle bundle : bundles)
93  		{
94  			final List<String> keys = messageBundleKeys.get(bundle);
95  			if (keys.contains(key)) return bundle.getString(key);
96  		}
97  
98  		// fallback from 'en_US' to 'en' locale
99  		if (locale.getCountry().length() > 0) return getMessage(key, new Locale(locale.getLanguage(), "", ""));
100 		if (locale.getLanguage().length() > 0) return getMessage(key, ROOT_LOCALE);
101 
102 		return null;
103 	}
104 
105 	private ArrayList<ResourceBundle> getMessageBundlesForLocale(final Locale locale)
106 	{
107 		Assert.argumentNotNull("locale", locale);
108 
109 		ArrayList<ResourceBundle> bundles = messageBundlesByLocale.get(locale);
110 		if (bundles == null)
111 		{
112 			bundles = new ArrayList<ResourceBundle>();
113 			messageBundlesByLocale.put(locale, bundles);
114 			try
115 			{
116 				// add the message bundle for the pre-built constraints
117 				addMessageBundle(ResourceBundle.getBundle("net/sf/oval/Messages", locale), locale);
118 			}
119 			catch (final MissingResourceException ex)
120 			{
121 				LOG.debug("No message bundle net.sf.oval.Messages for locale %s found.", ex, locale);
122 			}
123 		}
124 		return bundles;
125 	}
126 
127 	/**
128 	 * Removes the message bundle
129 	 *
130 	 * @return true if the bundle was registered and false if it wasn't registered
131 	 */
132 	public boolean removeMessageBundle(final ResourceBundle bundle)
133 	{
134 		final List<ResourceBundle> bundles = getMessageBundlesForLocale(bundle.getLocale());
135 
136 		if (!bundles.contains(bundle)) return false;
137 
138 		bundles.remove(bundle);
139 		messageBundleKeys.remove(bundle);
140 		return true;
141 	}
142 }