View Javadoc
1   /*
2    * Copyright (c) 2002-2026 Gargoyle Software Inc.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * https://www.apache.org/licenses/LICENSE-2.0
8    *
9    * Unless required by applicable law or agreed to in writing, software
10   * distributed under the License is distributed on an "AS IS" BASIS,
11   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12   * See the License for the specific language governing permissions and
13   * limitations under the License.
14   */
15  package org.htmlunit;
16  
17  import java.io.IOException;
18  import java.io.ObjectInputStream;
19  import java.io.Serializable;
20  
21  import org.apache.commons.logging.Log;
22  import org.apache.commons.logging.LogFactory;
23  import org.htmlunit.corejs.javascript.Context;
24  import org.htmlunit.corejs.javascript.NativeConsole;
25  import org.htmlunit.corejs.javascript.NativeConsole.ConsolePrinter;
26  import org.htmlunit.corejs.javascript.NativeConsole.Level;
27  import org.htmlunit.corejs.javascript.ScriptStackElement;
28  import org.htmlunit.corejs.javascript.VarScope;
29  
30  /**
31   * This class can be used to print messages to the logger. The first parameter
32   * can be a message-object containing format specifiers such as ("%o", "%s",
33   * "%d", "%i", "%f"). The logging methods are null-safe, so if the number of
34   * format specifiers and the numbers of parameters don't match, no exception is thrown.
35   * <p>
36   * The default logger uses Apache Commons Logging.
37   * </p>
38   *
39   * @author Andrea Martino
40   * @author Ronald Brill
41   */
42  public class WebConsole implements ConsolePrinter, Serializable {
43  
44      private static final Log LOG = LogFactory.getLog(WebConsole.class);
45  
46      private transient Logger logger_ = new DefaultLogger(LOG);
47  
48      /**
49       * A simple logging interface abstracting logging APIs.
50       */
51      public interface Logger {
52  
53          /**
54           * Is trace logging currently enabled?.
55           * <p>
56           * Call this method to prevent having to perform expensive operations
57           * (for example, <code>String</code> concatenation)
58           * when the log level is more than trace.
59           * </p>
60           *
61           * @return true if trace is enabled in the underlying logger.
62           */
63          boolean isTraceEnabled();
64  
65          /**
66           * Logs a message with trace log level.
67           *
68           * @param message log this message
69           */
70          void trace(Object message);
71  
72          /**
73           * Is debug logging currently enabled?.
74           * <p>
75           * Call this method to prevent having to perform expensive operations
76           * (for example, <code>String</code> concatenation)
77           * when the log level is more than debug.
78           * </p>
79           *
80           * @return true if debug is enabled in the underlying logger.
81           */
82          boolean isDebugEnabled();
83  
84          /**
85           * Logs a message with debug log level.
86           *
87           * @param message log this message
88           */
89          void debug(Object message);
90  
91          /**
92           * Is info logging currently enabled?.
93           * <p>
94           * Call this method to prevent having to perform expensive operations
95           * (for example, <code>String</code> concatenation)
96           * when the log level is more than info.
97           * </p>
98           *
99           * @return true if info is enabled in the underlying logger.
100          */
101         boolean isInfoEnabled();
102 
103         /**
104          * Logs a message with info log level.
105          *
106          * @param message log this message
107          */
108         void info(Object message);
109 
110         /**
111          * Is warn logging currently enabled?.
112          * <p>
113          * Call this method to prevent having to perform expensive operations
114          * (for example, <code>String</code> concatenation)
115          * when the log level is more than warn.
116          * </p>
117          *
118          * @return true if warn is enabled in the underlying logger.
119          */
120         boolean isWarnEnabled();
121 
122         /**
123          * Logs a message with warn log level.
124          *
125          * @param message log this message
126          */
127         void warn(Object message);
128 
129         /**
130          * Is error logging currently enabled?.
131          * <p>
132          * Call this method to prevent having to perform expensive operations
133          * (for example, <code>String</code> concatenation)
134          * when the log level is more than error.
135          * </p>
136          *
137          * @return true if error is enabled in the underlying logger.
138          */
139         boolean isErrorEnabled();
140 
141         /**
142          * Logs a message with error log level.
143          *
144          * @param message log this message
145          */
146         void error(Object message);
147     }
148 
149     /**
150      * Sets the Logger_.
151      * @param logger the logger
152      */
153     public void setLogger(final Logger logger) {
154         logger_ = logger;
155     }
156 
157     /**
158      * Returns the current Logger.
159      * @return the logger
160      */
161     public Logger getLogger() {
162         return logger_;
163     }
164 
165     @Override
166     public void print(final Context cx, final VarScope scope, final Level level,
167             final Object[] args, final ScriptStackElement[] stack) {
168         switch (level) {
169             case TRACE:
170                 if (logger_.isInfoEnabled()) {
171                     String msg = format(cx, scope, args);
172                     if (stack != null) {
173                         final StringBuilder scriptStack = new StringBuilder();
174                         scriptStack.append(msg);
175 
176                         for (final ScriptStackElement scriptStackElement : stack) {
177                             if (scriptStack.length() > 0) {
178                                 scriptStack.append('\n');
179                             }
180                             scriptStack.append(scriptStackElement);
181                         }
182 
183                         msg = scriptStack.toString();
184                     }
185                     logger_.info(msg);
186                 }
187                 break;
188             case DEBUG:
189                 if (logger_.isDebugEnabled()) {
190                     logger_.debug(format(cx, scope, args));
191                 }
192                 break;
193             case INFO:
194                 if (logger_.isInfoEnabled()) {
195                     logger_.info(format(cx, scope, args));
196                 }
197                 break;
198             case WARN:
199                 if (logger_.isWarnEnabled()) {
200                     logger_.warn(format(cx, scope, args));
201                 }
202                 break;
203             case ERROR:
204                 if (logger_.isErrorEnabled()) {
205                     logger_.error(format(cx, scope, args));
206                 }
207                 break;
208 
209             default:
210                 break;
211         }
212     }
213 
214     private static String format(final Context cx, final VarScope scope, final Object[] args) {
215         String msg = NativeConsole.format(cx, scope, args);
216         msg = msg.replaceAll("\\r?\\n", "\n");
217         return msg;
218     }
219 
220     private void readObject(final ObjectInputStream ois) throws ClassNotFoundException, IOException {
221         ois.defaultReadObject();
222         setLogger(new DefaultLogger(LOG));
223     }
224 
225     /**
226      * This class is the default logger used by WebConsole.
227      */
228     private static class DefaultLogger implements Logger {
229 
230         private final Log webConsoleLogger_;
231 
232         /**
233          * Ctor.
234          */
235         DefaultLogger(final Log logger) {
236             super();
237             webConsoleLogger_ = logger;
238         }
239 
240         @Override
241         public boolean isTraceEnabled() {
242             return webConsoleLogger_.isTraceEnabled();
243         }
244 
245         @Override
246         public void trace(final Object message) {
247             webConsoleLogger_.trace(message);
248         }
249 
250         @Override
251         public boolean isDebugEnabled() {
252             return webConsoleLogger_.isDebugEnabled();
253         }
254 
255         @Override
256         public void debug(final Object message) {
257             webConsoleLogger_.debug(message);
258         }
259 
260         @Override
261         public boolean isInfoEnabled() {
262             return webConsoleLogger_.isInfoEnabled();
263         }
264 
265         @Override
266         public void info(final Object message) {
267             webConsoleLogger_.info(message);
268         }
269 
270         @Override
271         public boolean isWarnEnabled() {
272             return webConsoleLogger_.isWarnEnabled();
273         }
274 
275         @Override
276         public void warn(final Object message) {
277             webConsoleLogger_.warn(message);
278         }
279 
280         @Override
281         public boolean isErrorEnabled() {
282             return webConsoleLogger_.isErrorEnabled();
283         }
284 
285         @Override
286         public void error(final Object message) {
287             webConsoleLogger_.error(message);
288         }
289     }
290 }