001    /*
002     * CDDL HEADER START
003     *
004     * The contents of this file are subject to the terms of the
005     * Common Development and Distribution License, Version 1.0 only
006     * (the "License").  You may not use this file except in compliance
007     * with the License.
008     *
009     * You can obtain a copy of the license at
010     * trunk/opends/resource/legal-notices/OpenDS.LICENSE
011     * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
012     * See the License for the specific language governing permissions
013     * and limitations under the License.
014     *
015     * When distributing Covered Code, include this CDDL HEADER in each
016     * file and include the License file at
017     * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
018     * add the following below this CDDL HEADER, with the fields enclosed
019     * by brackets "[]" replaced with your own identifying information:
020     *      Portions Copyright [yyyy] [name of copyright owner]
021     *
022     * CDDL HEADER END
023     *
024     *
025     *      Copyright 2008 Sun Microsystems, Inc.
026     */
027    
028    package org.opends.server.admin;
029    import org.opends.messages.Message;
030    
031    
032    
033    import java.text.MessageFormat;
034    import java.util.HashMap;
035    import java.util.Locale;
036    import java.util.Map;
037    import java.util.MissingResourceException;
038    import java.util.ResourceBundle;
039    
040    
041    
042    /**
043     * A class for retrieving internationalized resource properties
044     * associated with a managed object definition.
045     * <p>
046     * I18N resource properties are not available for the
047     * {@link TopCfgDefn}.
048     */
049    public final class ManagedObjectDefinitionI18NResource {
050    
051      // Application-wide set of instances.
052      private static final Map<String, ManagedObjectDefinitionI18NResource>
053        INSTANCES = new HashMap<String, ManagedObjectDefinitionI18NResource>();
054    
055    
056    
057      /**
058       * Gets the internationalized resource instance which can be used to
059       * retrieve the localized descriptions for the managed objects and
060       * their associated properties and relations.
061       *
062       * @return Returns the I18N resource instance.
063       */
064      public static ManagedObjectDefinitionI18NResource getInstance() {
065        return getInstance("admin.messages");
066      }
067    
068    
069    
070      /**
071       * Gets the internationalized resource instance for the named
072       * profile.
073       *
074       * @param profile
075       *          The name of the profile.
076       * @return Returns the I18N resource instance for the named profile.
077       */
078      public static ManagedObjectDefinitionI18NResource getInstanceForProfile(
079          String profile) {
080        return getInstance("admin.profiles." + profile);
081      }
082    
083    
084    
085      // Get a resource instance creating it if necessary.
086      private synchronized static ManagedObjectDefinitionI18NResource getInstance(
087          String prefix) {
088        ManagedObjectDefinitionI18NResource instance = INSTANCES
089            .get(prefix);
090    
091        if (instance == null) {
092          instance = new ManagedObjectDefinitionI18NResource(prefix);
093          INSTANCES.put(prefix, instance);
094        }
095    
096        return instance;
097      }
098    
099    
100    
101      // Mapping from definition to locale-based resource bundle.
102      private final Map<AbstractManagedObjectDefinition<?, ?>,
103        Map<Locale, ResourceBundle>> resources;
104    
105    
106    
107      // The resource name prefix.
108      private final String prefix;
109    
110    
111    
112      // Private constructor.
113      private ManagedObjectDefinitionI18NResource(String prefix) {
114        this.resources = new HashMap<AbstractManagedObjectDefinition<?, ?>,
115          Map<Locale, ResourceBundle>>();
116        this.prefix = prefix;
117      }
118    
119    
120    
121      /**
122       * Get the internationalized message associated with the specified
123       * key in the default locale.
124       *
125       * @param d
126       *          The managed object definition.
127       * @param key
128       *          The resource key.
129       * @return Returns the internationalized message associated with the
130       *         specified key in the default locale.
131       * @throws MissingResourceException
132       *           If the key was not found.
133       * @throws UnsupportedOperationException
134       *           If the provided managed object definition was the
135       *           {@link TopCfgDefn}.
136       */
137      public Message getMessage(AbstractManagedObjectDefinition<?, ?> d, String key)
138          throws MissingResourceException, UnsupportedOperationException {
139        return getMessage(d, key, Locale.getDefault(), (String[]) null);
140      }
141    
142    
143    
144      /**
145       * Get the internationalized message associated with the specified
146       * key and locale.
147       *
148       * @param d
149       *          The managed object definition.
150       * @param key
151       *          The resource key.
152       * @param locale
153       *          The locale.
154       * @return Returns the internationalized message associated with the
155       *         specified key and locale.
156       * @throws MissingResourceException
157       *           If the key was not found.
158       * @throws UnsupportedOperationException
159       *           If the provided managed object definition was the
160       *           {@link TopCfgDefn}.
161       */
162      public Message getMessage(AbstractManagedObjectDefinition<?, ?> d,
163          String key, Locale locale) throws MissingResourceException,
164          UnsupportedOperationException {
165        return getMessage(d, key, locale, (String[]) null);
166      }
167    
168    
169    
170      /**
171       * Get the parameterized internationalized message associated with
172       * the specified key and locale.
173       *
174       * @param d
175       *          The managed object definition.
176       * @param key
177       *          The resource key.
178       * @param locale
179       *          The locale.
180       * @param args
181       *          Arguments that should be inserted into the retrieved
182       *          message.
183       * @return Returns the internationalized message associated with the
184       *         specified key and locale.
185       * @throws MissingResourceException
186       *           If the key was not found.
187       * @throws UnsupportedOperationException
188       *           If the provided managed object definition was the
189       *           {@link TopCfgDefn}.
190       */
191      public Message getMessage(AbstractManagedObjectDefinition<?, ?> d,
192          String key, Locale locale, String... args)
193          throws MissingResourceException, UnsupportedOperationException {
194        ResourceBundle resource = getResourceBundle(d, locale);
195    
196        // TODO: use message framework directly
197        if (args == null) {
198          return Message.raw(resource.getString(key));
199        } else {
200          MessageFormat mf = new MessageFormat(resource.getString(key));
201          return Message.raw(mf.format(args));
202        }
203      }
204    
205    
206    
207      /**
208       * Get the parameterized internationalized message associated with
209       * the specified key in the default locale.
210       *
211       * @param d
212       *          The managed object definition.
213       * @param key
214       *          The resource key.
215       * @param args
216       *          Arguments that should be inserted into the retrieved
217       *          message.
218       * @return Returns the internationalized message associated with the
219       *         specified key in the default locale.
220       * @throws MissingResourceException
221       *           If the key was not found.
222       * @throws UnsupportedOperationException
223       *           If the provided managed object definition was the
224       *           {@link TopCfgDefn}.
225       */
226      public Message getMessage(AbstractManagedObjectDefinition<?, ?> d,
227          String key, String... args) throws MissingResourceException,
228          UnsupportedOperationException {
229        return getMessage(d, key, Locale.getDefault(), args);
230      }
231    
232    
233    
234      /**
235       * Forcefully removes any resource bundles associated with the
236       * provided definition and using the default locale.
237       * <p>
238       * This method is intended for internal testing only.
239       *
240       * @param d
241       *          The managed object definition.
242       */
243      synchronized void removeResourceBundle(
244          AbstractManagedObjectDefinition<?, ?> d) {
245        removeResourceBundle(d, Locale.getDefault());
246      }
247    
248    
249    
250      /**
251       * Forcefully removes any resource bundles associated with the
252       * provided definition and locale.
253       * <p>
254       * This method is intended for internal testing only.
255       *
256       * @param d
257       *          The managed object definition.
258       * @param locale
259       *          The locale.
260       */
261      synchronized void removeResourceBundle(
262          AbstractManagedObjectDefinition<?, ?> d, Locale locale) {
263        // Get the locale resource mapping.
264        Map<Locale, ResourceBundle> map = resources.get(d);
265        if (map != null) {
266          map.remove(locale);
267        }
268      }
269    
270    
271    
272      /**
273       * Forcefully adds the provided resource bundle to this I18N
274       * resource for the default locale.
275       * <p>
276       * This method is intended for internal testing only.
277       *
278       * @param d
279       *          The managed object definition.
280       * @param resoureBundle
281       *          The resource bundle to be used.
282       */
283      synchronized void setResourceBundle(AbstractManagedObjectDefinition<?, ?> d,
284          ResourceBundle resoureBundle) {
285        setResourceBundle(d, Locale.getDefault(), resoureBundle);
286      }
287    
288    
289    
290      /**
291       * Forcefully adds the provided resource bundle to this I18N
292       * resource.
293       * <p>
294       * This method is intended for internal testing only.
295       *
296       * @param d
297       *          The managed object definition.
298       * @param locale
299       *          The locale.
300       * @param resoureBundle
301       *          The resource bundle to be used.
302       */
303      synchronized void setResourceBundle(AbstractManagedObjectDefinition<?, ?> d,
304          Locale locale, ResourceBundle resoureBundle) {
305        // First get the locale-resource mapping, creating it if
306        // necessary.
307        Map<Locale, ResourceBundle> map = resources.get(d);
308        if (map == null) {
309          map = new HashMap<Locale, ResourceBundle>();
310          resources.put(d, map);
311        }
312    
313        // Add the resource bundle.
314        map.put(locale, resoureBundle);
315      }
316    
317    
318    
319      // Retrieve the resource bundle associated with a managed object and
320      // locale, lazily loading it if necessary.
321      private synchronized ResourceBundle getResourceBundle(
322          AbstractManagedObjectDefinition<?, ?> d, Locale locale)
323          throws MissingResourceException, UnsupportedOperationException {
324        if (d.isTop()) {
325          throw new UnsupportedOperationException(
326              "I18n resources are not available for the "
327                  + "Top configuration definition");
328        }
329    
330        // First get the locale-resource mapping, creating it if
331        // necessary.
332        Map<Locale, ResourceBundle> map = resources.get(d);
333        if (map == null) {
334          map = new HashMap<Locale, ResourceBundle>();
335          resources.put(d, map);
336        }
337    
338        // Now get the resource based on the locale, loading it if
339        // necessary.
340        ResourceBundle resourceBundle = map.get(locale);
341        if (resourceBundle == null) {
342          String baseName = prefix + "." + d.getClass().getName();
343          resourceBundle = ResourceBundle.getBundle(baseName, locale,
344              ClassLoaderProvider.getInstance().getClassLoader());
345          map.put(locale, resourceBundle);
346        }
347    
348        return resourceBundle;
349      }
350    }