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