001// *************************************************************************************************************************** 002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * 003// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * 004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * 005// * with the License. You may obtain a copy of the License at * 006// * * 007// * http://www.apache.org/licenses/LICENSE-2.0 * 008// * * 009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * 010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * 011// * specific language governing permissions and limitations under the License. * 012// *************************************************************************************************************************** 013package org.apache.juneau.internal; 014 015import static java.util.logging.Level.*; 016import static org.apache.juneau.internal.StringUtils.*; 017 018import java.text.*; 019import java.util.*; 020import java.util.concurrent.*; 021import java.util.logging.*; 022 023import org.apache.juneau.json.*; 024import org.apache.juneau.serializer.*; 025 026/** 027 * Wraps and extends the {@link java.util.logging.Logger} class to provide some additional convenience methods. 028 */ 029public class JuneauLogger extends java.util.logging.Logger { 030 031 private static final WriterSerializer serializer = JsonSerializer.create().ssq().build(); 032 033 private static final ConcurrentHashMap<Class<?>,String> rbMap = new ConcurrentHashMap<>(); 034 035 private final ResourceBundle rb; 036 private final java.util.logging.Logger innerLogger; 037 038 /** 039 * Get logger for specified class. 040 * 041 * @param forClass The class to create a logger for. 042 * @return A new <l>Logger</l>. 043 */ 044 public static JuneauLogger getLogger(Class<?> forClass) { 045 return getLogger(forClass.getName()); 046 } 047 048 /** 049 * Get logger for specified class. 050 * 051 * @param loggerName The logger name. 052 * @return A new <l>Logger</l>. 053 */ 054 public static JuneauLogger getLogger(String loggerName) { 055 return new JuneauLogger(java.util.logging.Logger.getLogger(loggerName)); 056 } 057 058 /** 059 * Get logger for specified class using the specified resource bundle name. 060 * 061 * @param forClass The class to create a logger for. 062 * @param resourceBundleName 063 * The name of the resource bundle. 064 * Can be any of the following formats: 065 * <ol> 066 * <li>An absolute path. E.g. <js>"com/foo/nls/Messages"</js>. 067 * <li>A path relative to the package of the class. E.g. <js>"nls/Messages"</js>. 068 * </ol> 069 * Both <js>'.'</js> and <js>'/'</js> can be used as path delimiters. 070 * @return A new <l>Logger</l>. 071 */ 072 public static JuneauLogger getLogger(Class<?> forClass, String resourceBundleName) { 073 return new JuneauLogger(java.util.logging.Logger.getLogger(forClass.getName(), resolveResourceBundleName(forClass, resourceBundleName))); 074 } 075 076 /** 077 * Get logger with specified name using the specified resource bundle name. 078 * 079 * @param name The name of the logger to use. 080 * @param resourceBundleName 081 * The name of the resource bundle. 082 * Can be any of the following formats: 083 * <ol> 084 * <li>An absolute path. E.g. <js>"com/foo/nls/Messages"</js>. 085 * <li>A path relative to the package of the class. E.g. <js>"nls/Messages"</js>. 086 * </ol> 087 * Both <js>'.'</js> and <js>'/'</js> can be used as path delimiters. 088 * @return A new <l>Logger</l>. 089 */ 090 public static synchronized JuneauLogger getLogger(String name, String resourceBundleName) { 091 return new JuneauLogger(java.util.logging.Logger.getLogger(name, resourceBundleName)); 092 } 093 094 /** 095 * Constructor. 096 * 097 * @param innerLogger The wrapped logger. 098 */ 099 protected JuneauLogger(java.util.logging.Logger innerLogger) { 100 super(innerLogger.getName(), innerLogger.getResourceBundleName()); 101 this.innerLogger = innerLogger; 102 this.rb = getResourceBundle(); 103 } 104 105 /** 106 * Logs a message with the specified {@link MessageFormat}-style arguments at {@link Level#SEVERE} level. 107 * 108 * @param msg The message to log. 109 * @param args Optional {@link MessageFormat}-style arguments. 110 */ 111 public void severe(String msg, Object...args) { 112 if (isLoggable(SEVERE)) 113 log(SEVERE, msg, args); 114 } 115 116 /** 117 * Logs a message with the specified {@link MessageFormat}-style arguments at {@link Level#WARNING} level. 118 * 119 * @param msg The message to log. 120 * @param args Optional {@link MessageFormat}-style arguments. 121 */ 122 public void warning(String msg, Object...args) { 123 if (isLoggable(WARNING)) 124 log(WARNING, msg, args); 125 } 126 127 /** 128 * Logs a message with the specified {@link MessageFormat}-style arguments at {@link Level#INFO} level. 129 * 130 * @param msg The message to log. 131 * @param args Optional {@link MessageFormat}-style arguments. 132 */ 133 public void info(String msg, Object...args) { 134 if (isLoggable(INFO)) 135 log(INFO, msg, args); 136 } 137 138 /** 139 * Logs a message with the specified {@link MessageFormat}-style arguments at {@link Level#CONFIG} level. 140 * 141 * @param msg The message to log. 142 * @param args Optional {@link MessageFormat}-style arguments. 143 */ 144 public void config(String msg, Object...args) { 145 if (isLoggable(CONFIG)) 146 log(CONFIG, msg, args); 147 } 148 149 /** 150 * Logs a message with the specified {@link MessageFormat}-style arguments at {@link Level#FINE} level. 151 * 152 * @param msg The message to log. 153 * @param args Optional {@link MessageFormat}-style arguments. 154 */ 155 public void fine(String msg, Object...args) { 156 if (isLoggable(FINE)) 157 log(FINE, msg, args); 158 } 159 160 /** 161 * Logs a message with the specified {@link MessageFormat}-style arguments at {@link Level#FINER} level. 162 * 163 * @param msg The message to log. 164 * @param args Optional {@link MessageFormat}-style arguments. 165 */ 166 public void finer(String msg, Object...args) { 167 if (isLoggable(FINER)) 168 log(FINER, msg, args); 169 } 170 171 /** 172 * Logs a message with the specified {@link MessageFormat}-style arguments at {@link Level#FINEST} level. 173 * 174 * @param msg The message to log. 175 * @param args Optional {@link MessageFormat}-style arguments. 176 */ 177 public void finest(String msg, Object...args) { 178 if (isLoggable(FINEST)) 179 log(FINEST, msg, args); 180 } 181 182 /** 183 * Logs an exception as {@link Level#SEVERE} level. 184 * 185 * @param t The Throwable object to log. 186 */ 187 public void severe(Throwable t) { 188 if (isLoggable(SEVERE)) 189 log(SEVERE, t.getLocalizedMessage(), t); 190 } 191 192 /** 193 * Logs an exception as {@link Level#WARNING} level. 194 * 195 * @param t The Throwable object to log. 196 */ 197 public void warning(Throwable t) { 198 if (isLoggable(WARNING)) 199 log(WARNING, t.getLocalizedMessage(), t); 200 } 201 202 /** 203 * Logs a message with the specified {@link MessageFormat}-style arguments at {@link Level#SEVERE} level. 204 * 205 * @param t The Throwable object associated with the event that needs to be logged. 206 * @param msg The message to log. 207 * @param args Optional {@link MessageFormat}-style arguments. 208 */ 209 public void severe(Throwable t, String msg, Object...args) { 210 if (isLoggable(SEVERE)) 211 log(SEVERE, getMessage(msg, args), t); 212 } 213 214 /** 215 * Logs a message with the specified {@link MessageFormat}-style arguments at {@link Level#WARNING} level. 216 * 217 * @param t The Throwable object associated with the event that needs to be logged. 218 * @param msg The message to log. 219 * @param args Optional {@link MessageFormat}-style arguments. 220 */ 221 public void warning(Throwable t, String msg, Object...args) { 222 if (isLoggable(WARNING)) 223 log(WARNING, getMessage(msg, args), t); 224 } 225 226 /** 227 * Logs a message with the specified {@link MessageFormat}-style arguments at {@link Level#INFO} level. 228 * 229 * @param t The Throwable object associated with the event that needs to be logged. 230 * @param msg The message to log. 231 * @param args Optional {@link MessageFormat}-style arguments. 232 */ 233 public void info(Throwable t, String msg, Object...args) { 234 if (isLoggable(INFO)) 235 log(INFO, getMessage(msg, args), t); 236 } 237 238 @Override /* Logger */ 239 public void log(LogRecord record) { 240 innerLogger.log(record); 241 } 242 243 /** 244 * Logs a message with the specified {@link MessageFormat}-style arguments at the specified level. 245 * 246 * @param level The log level. 247 * @param cause The Throwable object associated with the event that needs to be logged. 248 * @param msg The message to log. 249 * @param args Optional {@link MessageFormat}-style arguments. 250 */ 251 public void log(Level level, Throwable cause, String msg, Object...args) { 252 if (isLoggable(level)) 253 log(level, getMessage(msg, args), cause); 254 } 255 256 @Override /* Logger */ 257 public boolean isLoggable(Level level) { 258 return innerLogger.isLoggable(level); 259 } 260 261 /** 262 * Similar to {@link #log(Level, String, Object[])}, except arguments are converted to objects 263 * that are serialized using the {@link JsonSerializer#toStringObject(Object)} method. 264 * 265 * <p> 266 * This allows arbitrary POJOs to be serialized as message parameters. 267 * 268 * @param level The level of the given message. 269 * @param msg The message to log. 270 * @param args The POJO arguments. 271 */ 272 public void logObjects(Level level, String msg, Object...args) { 273 if (isLoggable(level)) { 274 for (int i = 0; i < args.length; i++) 275 args[i] = serializer.toStringObject(args[i]); 276 log(level, msg, args); 277 } 278 } 279 280 private String getMessage(String msg, Object...args) { 281 if (args.length == 0) 282 return msg; 283 if (rb != null && rb.containsKey(msg)) 284 msg = rb.getString(msg); 285 return format(msg, args); 286 } 287 288 private static String resolveResourceBundleName(Class<?> forClass, String path) { 289 if (isEmpty(path)) 290 return null; 291 String rb = rbMap.get(forClass); 292 if (rb == null) { 293 path = path.replace('/', '.'); 294 if (path.startsWith(".")) 295 path = path.substring(1); 296 ClassLoader cl = forClass.getClassLoader(); 297 try { 298 ResourceBundle.getBundle(path, Locale.getDefault(), cl); 299 rbMap.putIfAbsent(forClass, path); 300 } catch (MissingResourceException e) { 301 try { 302 path = forClass.getPackage().getName() + '.' + path; 303 ResourceBundle.getBundle(path, Locale.getDefault(), cl); 304 rbMap.putIfAbsent(forClass, path); 305 } catch (MissingResourceException e2) { 306 rbMap.putIfAbsent(forClass, ""); 307 } 308 } 309 rb = rbMap.get(forClass); 310 } 311 return ("".equals(rb) ? null : rb); 312 } 313}