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