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 *
029 * @deprecated Methods introduced in Java 8 Logging API renders this class obsolete.
030 */
031@Deprecated
032public class JuneauLogger extends java.util.logging.Logger {
033
034   private static final WriterSerializer serializer = JsonSerializer.create().ssq().build();
035
036   private static final ConcurrentHashMap<Class<?>,String> rbMap = new ConcurrentHashMap<>();
037
038   private final ResourceBundle rb;
039   private final java.util.logging.Logger innerLogger;
040
041   /**
042    * Get logger for specified class.
043    *
044    * @param forClass The class to create a logger for.
045    * @return A new <l>BasicLogger</l>.
046    */
047   public static JuneauLogger getLogger(Class<?> forClass) {
048      return getLogger(forClass.getName());
049   }
050
051   /**
052    * Get logger for specified class.
053    *
054    * @param loggerName The logger name.
055    * @return A new <l>BasicLogger</l>.
056    */
057   public static JuneauLogger getLogger(String loggerName) {
058      return new JuneauLogger(java.util.logging.Logger.getLogger(loggerName));
059   }
060
061   /**
062    * Get logger for specified class using the specified resource bundle name.
063    *
064    * @param forClass The class to create a logger for.
065    * @param resourceBundleName
066    *    The name of the resource bundle.
067    *    Can be any of the following formats:
068    *    <ol>
069    *       <li>An absolute path.  E.g. <js>"com/foo/nls/Messages"</js>.
070    *       <li>A path relative to the package of the class.  E.g. <js>"nls/Messages"</js>.
071    *    </ol>
072    *    Both <js>'.'</js> and <js>'/'</js> can be used as path delimiters.
073    * @return A new <l>BasicLogger</l>.
074    */
075   public static JuneauLogger getLogger(Class<?> forClass, String resourceBundleName) {
076      return new JuneauLogger(java.util.logging.Logger.getLogger(forClass.getName(), resolveResourceBundleName(forClass, resourceBundleName)));
077   }
078
079   /**
080    * Get logger with specified name using the specified resource bundle name.
081    *
082    * @param name The name of the logger to use.
083    * @param resourceBundleName
084    *    The name of the resource bundle.
085    *    Can be any of the following formats:
086    *    <ol>
087    *       <li>An absolute path.  E.g. <js>"com/foo/nls/Messages"</js>.
088    *       <li>A path relative to the package of the class.  E.g. <js>"nls/Messages"</js>.
089    *    </ol>
090    *    Both <js>'.'</js> and <js>'/'</js> can be used as path delimiters.
091    * @return A new <l>BasicLogger</l>.
092    */
093   public static synchronized JuneauLogger getLogger(String name, String resourceBundleName) {
094      return new JuneauLogger(java.util.logging.Logger.getLogger(name, resourceBundleName));
095   }
096
097   /**
098    * Wrap the specified logger
099    *
100    * @param logger The java logger to use for logging.
101    * @return A new <l>BasicLogger</l>.
102    */
103   public static synchronized JuneauLogger getLogger(java.util.logging.Logger logger) {
104      return new JuneauLogger(logger);
105   }
106
107   /**
108    * Constructor.
109    *
110    * @param innerLogger The wrapped logger.
111    */
112   public JuneauLogger(java.util.logging.Logger innerLogger) {
113      super(innerLogger.getName(), innerLogger.getResourceBundleName());
114      this.innerLogger = innerLogger;
115      this.rb = getResourceBundle();
116   }
117
118   /**
119    * Logs a message with the specified {@link MessageFormat}-style arguments at {@link Level#SEVERE} level.
120    *
121    * @param msg The message to log.
122    * @param args Optional {@link MessageFormat}-style arguments.
123    */
124   public void severe(String msg, Object...args) {
125      if (isLoggable(SEVERE))
126         log(SEVERE, msg, args);
127   }
128
129   /**
130    * Logs a message with the specified {@link MessageFormat}-style arguments at {@link Level#WARNING} level.
131    *
132    * @param msg The message to log.
133    * @param args Optional {@link MessageFormat}-style arguments.
134    */
135   public void warning(String msg, Object...args) {
136      if (isLoggable(WARNING))
137         log(WARNING, msg, args);
138   }
139
140   /**
141    * Logs a message with the specified {@link MessageFormat}-style arguments at {@link Level#INFO} level.
142    *
143    * @param msg The message to log.
144    * @param args Optional {@link MessageFormat}-style arguments.
145    */
146   public void info(String msg, Object...args) {
147      if (isLoggable(INFO))
148         log(INFO, msg, args);
149   }
150
151   /**
152    * Logs a message with the specified {@link MessageFormat}-style arguments at {@link Level#CONFIG} level.
153    *
154    * @param msg The message to log.
155    * @param args Optional {@link MessageFormat}-style arguments.
156    */
157   public void config(String msg, Object...args) {
158      if (isLoggable(CONFIG))
159         log(CONFIG, msg, args);
160   }
161
162   /**
163    * Logs a message with the specified {@link MessageFormat}-style arguments at {@link Level#FINE} level.
164    *
165    * @param msg The message to log.
166    * @param args Optional {@link MessageFormat}-style arguments.
167    */
168   public void fine(String msg, Object...args) {
169      if (isLoggable(FINE))
170         log(FINE, msg, args);
171   }
172
173   /**
174    * Logs a message with the specified {@link MessageFormat}-style arguments at {@link Level#FINER} level.
175    *
176    * @param msg The message to log.
177    * @param args Optional {@link MessageFormat}-style arguments.
178    */
179   public void finer(String msg, Object...args) {
180      if (isLoggable(FINER))
181         log(FINER, msg, args);
182   }
183
184   /**
185    * Logs a message with the specified {@link MessageFormat}-style arguments at {@link Level#FINEST} level.
186    *
187    * @param msg The message to log.
188    * @param args Optional {@link MessageFormat}-style arguments.
189    */
190   public void finest(String msg, Object...args) {
191      if (isLoggable(FINEST))
192         log(FINEST, msg, args);
193   }
194
195   /**
196    * Logs an exception as {@link Level#SEVERE} level.
197    *
198    * @param t The Throwable object to log.
199    */
200   public void severe(Throwable t) {
201      if (isLoggable(SEVERE))
202         log(SEVERE, t.getLocalizedMessage(), t);
203   }
204
205   /**
206    * Logs an exception as {@link Level#WARNING} level.
207    *
208    * @param t The Throwable object to log.
209    */
210   public void warning(Throwable t) {
211      if (isLoggable(WARNING))
212         log(WARNING, t.getLocalizedMessage(), t);
213   }
214
215   /**
216    * Logs a message with the specified {@link MessageFormat}-style arguments at {@link Level#SEVERE} level.
217    *
218    * @param t The Throwable object associated with the event that needs to be logged.
219    * @param msg The message to log.
220    * @param args Optional {@link MessageFormat}-style arguments.
221    */
222   public void severe(Throwable t, String msg, Object...args) {
223      if (isLoggable(SEVERE))
224         log(SEVERE, getMessage(msg, args), t);
225   }
226
227   /**
228    * Logs a message with the specified {@link MessageFormat}-style arguments at {@link Level#WARNING} level.
229    *
230    * @param t The Throwable object associated with the event that needs to be logged.
231    * @param msg The message to log.
232    * @param args Optional {@link MessageFormat}-style arguments.
233    */
234   public void warning(Throwable t, String msg, Object...args) {
235      if (isLoggable(WARNING))
236         log(WARNING, getMessage(msg, args), t);
237   }
238
239   /**
240    * Logs a message with the specified {@link MessageFormat}-style arguments at {@link Level#INFO} level.
241    *
242    * @param t The Throwable object associated with the event that needs to be logged.
243    * @param msg The message to log.
244    * @param args Optional {@link MessageFormat}-style arguments.
245    */
246   public void info(Throwable t, String msg, Object...args) {
247      if (isLoggable(INFO))
248         log(INFO, getMessage(msg, args), t);
249   }
250
251   @Override /* Logger */
252   public void log(LogRecord record) {
253      innerLogger.log(record);
254   }
255
256   /**
257    * Logs a message with the specified {@link MessageFormat}-style arguments at the specified level.
258    *
259    * @param level The log level.
260    * @param cause The Throwable object associated with the event that needs to be logged.
261    * @param msg The message to log.
262    * @param args Optional {@link MessageFormat}-style arguments.
263    */
264   public void log(Level level, Throwable cause, String msg, Object...args) {
265      if (isLoggable(level))
266         log(level, getMessage(msg, args), cause);
267   }
268
269   @Override /* Logger */
270   public boolean isLoggable(Level level) {
271      return innerLogger.isLoggable(level);
272   }
273
274   /**
275    * Similar to {@link #log(Level, String, Object[])}, except arguments are converted to objects
276    * that are serialized using the {@link JsonSerializer#toStringObject(Object)} method.
277    *
278    * <p>
279    * This allows arbitrary POJOs to be serialized as message parameters.
280    *
281    * @param level The level of the given message.
282    * @param msg The message to log.
283    * @param args The POJO arguments.
284    */
285   public void logObjects(Level level, String msg, Object...args) {
286      if (isLoggable(level)) {
287         for (int i = 0; i < args.length; i++)
288            args[i] = serializer.toStringObject(args[i]);
289         log(level, msg, args);
290      }
291   }
292
293   private String getMessage(String msg, Object...args) {
294      if (args.length == 0)
295         return msg;
296      if (rb != null && rb.containsKey(msg))
297         msg = rb.getString(msg);
298      return format(msg, args);
299   }
300
301   private static String resolveResourceBundleName(Class<?> forClass, String path) {
302      if (isEmpty(path))
303         return null;
304      String rb = rbMap.get(forClass);
305      if (rb == null) {
306         path = path.replace('/', '.');
307         if (path.startsWith("."))
308            path = path.substring(1);
309         ClassLoader cl = forClass.getClassLoader();
310         try {
311            ResourceBundle.getBundle(path, Locale.getDefault(), cl);
312            rbMap.putIfAbsent(forClass, path);
313         } catch (MissingResourceException e) {
314            try {
315               path = forClass.getPackage().getName() + '.' + path;
316               ResourceBundle.getBundle(path, Locale.getDefault(), cl);
317               rbMap.putIfAbsent(forClass, path);
318            } catch (MissingResourceException e2) {
319               rbMap.putIfAbsent(forClass, "");
320            }
321         }
322         rb = rbMap.get(forClass);
323      }
324      return ("".equals(rb) ? null : rb);
325   }
326}