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