1 /* 2 * Copyright (c) MuleSoft, Inc. All rights reserved. http://www.mulesoft.com 3 * The software in this package is published under the terms of the CPAL v1.0 4 * license, a copy of which has been included with this distribution in the 5 * LICENSE.txt file. 6 */ 7 package org.mule.config.i18n; 8 9 import java.text.MessageFormat; 10 import java.util.Locale; 11 import java.util.MissingResourceException; 12 import java.util.ResourceBundle; 13 14 import org.apache.commons.logging.Log; 15 import org.apache.commons.logging.LogFactory; 16 17 18 public abstract class MessageFactory 19 { 20 /** 21 * This error code is used for {@link Message} instances that are not read from a 22 * resource bundles but are created only with a string. 23 */ 24 private static final int STATIC_ERROR_CODE = -1; 25 private static final transient Object[] EMPTY_ARGS = new Object[]{}; 26 27 protected transient Log logger = LogFactory.getLog(getClass()); 28 // since java 6 only 29 //protected final ReloadControl control = new ReloadControl(); 30 31 /** 32 * Computes the bundle's full path 33 * (<code>META-INF/services/org/mule/i18n/<bundleName>-messages.properties</code>) from 34 * <code>bundleName</code>. 35 * 36 * @param bundleName Name of the bundle without the "messages" suffix and without 37 * file extension. 38 */ 39 protected static String getBundlePath(String bundleName) 40 { 41 return "META-INF.services.org.mule.i18n." + bundleName + "-messages"; 42 } 43 44 /** 45 * Factory method to create a new {@link Message} instance that is filled with the formatted 46 * message with id <code>code</code> from the resource bundle <code>bundlePath</code>. 47 * 48 * @param bundlePath complete path to the resource bundle for lookup 49 * @param code numeric code of the message 50 * @param arg 51 * @see #getBundlePath(String) 52 */ 53 protected Message createMessage(String bundlePath, int code, Object arg) 54 { 55 return createMessage(bundlePath, code, new Object[] {arg}); 56 } 57 58 /** 59 * Factory method to create a new {@link Message} instance that is filled with the formatted 60 * message with id <code>code</code> from the resource bundle <code>bundlePath</code>. 61 * 62 * @param bundlePath complete path to the resource bundle for lookup 63 * @param code numeric code of the message 64 * @param arg1 65 * @param arg2 66 * @see #getBundlePath(String) 67 */ 68 protected Message createMessage(String bundlePath, int code, Object arg1, Object arg2) 69 { 70 return createMessage(bundlePath, code, new Object[] {arg1, arg2}); 71 } 72 73 /** 74 * Factory method to create a new {@link Message} instance that is filled with the formatted 75 * message with id <code>code</code> from the resource bundle <code>bundlePath</code>. 76 * 77 * @param bundlePath complete path to the resource bundle for lookup 78 * @param code numeric code of the message 79 * @param arg1 80 * @param arg2 81 * @param arg3 82 * @see #getBundlePath(String) 83 */ 84 protected Message createMessage(String bundlePath, int code, Object arg1, Object arg2, 85 Object arg3) 86 { 87 return createMessage(bundlePath, code, new Object[] {arg1, arg2, arg3}); 88 } 89 90 /** 91 * Factory method to create a new {@link Message} instance that is filled with the formatted 92 * message with id <code>code</code> from the resource bundle <code>bundlePath</code>. 93 * 94 * <b>Attention:</b> do not confuse this method with 95 * <code>createMessage(String, int, Object)</code>. 96 * 97 * @param bundlePath complete path to the resource bundle for lookup 98 * @param code numeric code of the message 99 * @param arguments 100 * @see #getBundlePath(String) 101 */ 102 protected Message createMessage(String bundlePath, int code, Object... arguments) 103 { 104 String messageString = getString(bundlePath, code, arguments); 105 return new Message(messageString, code, arguments); 106 } 107 108 /** 109 * Factory method to create a new {@link Message} instance that is filled with the formatted 110 * message with id <code>code</code> from the resource bundle <code>bundlePath</code>. 111 * 112 * @param bundlePath complete path to the resource bundle for lookup 113 * @param code numeric code of the message 114 */ 115 protected Message createMessage(String bundlePath, int code) 116 { 117 String messageString = getString(bundlePath, code, null); 118 return new Message(messageString, code, EMPTY_ARGS); 119 } 120 121 /** 122 * Factory method to create a {@link Message} instance that is not read from a resource bundle. 123 * 124 * @param message Message's message text 125 * @return a Messsage instance that has an error code of -1 and no arguments. 126 */ 127 public static Message createStaticMessage(String message) 128 { 129 return new Message(message, STATIC_ERROR_CODE, EMPTY_ARGS); 130 } 131 132 /** 133 * Factory method to read the message with code <code>code</code> from the resource bundle. 134 * 135 * @param bundlePath complete path to the resource bundle for lookup 136 * @param code numeric code of the message 137 * @return formatted error message as {@link String} 138 */ 139 protected String getString(String bundlePath, int code) 140 { 141 return getString(bundlePath, code, null); 142 } 143 144 /** 145 * Factory method to read the message with code <code>code</code> from the resource bundle. 146 * 147 * @param bundlePath complete path to the resource bundle for lookup 148 * @param code numeric code of the message 149 * @param arg 150 * @return formatted error message as {@link String} 151 */ 152 protected String getString(String bundlePath, int code, Object arg) 153 { 154 Object[] arguments = new Object[] {arg}; 155 return getString(bundlePath, code, arguments); 156 } 157 158 /** 159 * Factory method to read the message with code <code>code</code> from the resource bundle. 160 * 161 * @param bundlePath complete path to the resource bundle for lookup 162 * @param code numeric code of the message 163 * @param arg1 164 * @param arg2 165 * @return formatted error message as {@link String} 166 */ 167 protected String getString(String bundlePath, int code, Object arg1, Object arg2) 168 { 169 Object[] arguments = new Object[] {arg1, arg2}; 170 return getString(bundlePath, code, arguments); 171 } 172 173 protected String getString(String bundlePath, int code, Object[] args) 174 { 175 // We will throw a MissingResourceException if the bundle name is invalid 176 // This happens if the code references a bundle name that just doesn't exist 177 ResourceBundle bundle = getBundle(bundlePath); 178 179 try 180 { 181 String m = bundle.getString(String.valueOf(code)); 182 if (m == null) 183 { 184 logger.error("Failed to find message for id " + code + " in resource bundle " + bundlePath); 185 return ""; 186 } 187 188 return MessageFormat.format(m, args); 189 } 190 catch (MissingResourceException e) 191 { 192 logger.error("Failed to find message for id " + code + " in resource bundle " + bundlePath); 193 return ""; 194 } 195 } 196 197 /** 198 * @throws MissingResourceException if resource is missing 199 */ 200 private ResourceBundle getBundle(String bundlePath) 201 { 202 Locale locale = Locale.getDefault(); 203 if (logger.isTraceEnabled()) 204 { 205 logger.trace("Loading resource bundle: " + bundlePath + " for locale " + locale); 206 } 207 ResourceBundle bundle = ResourceBundle.getBundle(bundlePath, locale, getClassLoader()); 208 return bundle; 209 } 210 211 /** 212 * Override this method to return the classloader for the bundle/module which 213 * contains the needed resource files. 214 */ 215 protected ClassLoader getClassLoader() 216 { 217 final ClassLoader ccl = Thread.currentThread().getContextClassLoader(); 218 // if there's a deployment classloader present, use it for finding resources 219 return ccl == null ? getClass().getClassLoader() : ccl; 220 } 221 222 // since java 6 only 223 /*static class ReloadControl extends ResourceBundle.Control 224 { 225 boolean needsReload = true; 226 227 @Override 228 public boolean needsReload(String baseName, Locale locale, String format, ClassLoader loader, ResourceBundle bundle, long loadTime) 229 { 230 // TODO always for now 231 return true; 232 } 233 234 @Override 235 public long getTimeToLive(String baseName, Locale locale) 236 { 237 if (needsReload) 238 { 239 // must be zero, as other 'DONT_CACHE' constant doesn't work here, and is -1 240 return 0; 241 } 242 243 return ResourceBundle.Control.TTL_NO_EXPIRATION_CONTROL; 244 } 245 }*/ 246 } 247 248