View Javadoc
1   /*
2    * Copyright (c) 2002-2025 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.Scriptable;
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   *
38   * @author Andrea Martino
39   * @author Ronald Brill
40   */
41  public class WebConsole implements ConsolePrinter, Serializable {
42  
43      private static final Log LOG = LogFactory.getLog(WebConsole.class);
44  
45      private transient Logger logger_ = new DefaultLogger(LOG);
46  
47      /**
48       * A simple logging interface abstracting logging APIs.
49       */
50      public interface Logger {
51  
52          /**
53           * Is trace logging currently enabled?
54           * <p>
55           * Call this method to prevent having to perform expensive operations
56           * (for example, <code>String</code> concatenation)
57           * when the log level is more than trace.
58           *
59           * @return true if trace is enabled in the underlying logger.
60           */
61          boolean isTraceEnabled();
62  
63          /**
64           * Logs a message with trace log level.
65           *
66           * @param message log this message
67           */
68          void trace(Object message);
69  
70          /**
71           * Is debug logging currently enabled?
72           * <p>
73           * Call this method to prevent having to perform expensive operations
74           * (for example, <code>String</code> concatenation)
75           * when the log level is more than debug.
76           *
77           * @return true if debug is enabled in the underlying logger.
78           */
79          boolean isDebugEnabled();
80  
81          /**
82           * Logs a message with debug log level.
83           *
84           * @param message log this message
85           */
86          void debug(Object message);
87  
88          /**
89           * Is info logging currently enabled?
90           * <p>
91           * Call this method to prevent having to perform expensive operations
92           * (for example, <code>String</code> concatenation)
93           * when the log level is more than info.
94           *
95           * @return true if info is enabled in the underlying logger.
96           */
97          boolean isInfoEnabled();
98  
99          /**
100          * Logs a message with info log level.
101          *
102          * @param message log this message
103          */
104         void info(Object message);
105 
106         /**
107          * Is warn logging currently enabled?
108          * <p>
109          * Call this method to prevent having to perform expensive operations
110          * (for example, <code>String</code> concatenation)
111          * when the log level is more than warn.
112          *
113          * @return true if warn is enabled in the underlying logger.
114          */
115         boolean isWarnEnabled();
116 
117         /**
118          * Logs a message with warn log level.
119          *
120          * @param message log this message
121          */
122         void warn(Object message);
123 
124         /**
125          * Is error logging currently enabled?
126          * <p>
127          * Call this method to prevent having to perform expensive operations
128          * (for example, <code>String</code> concatenation)
129          * when the log level is more than error.
130          *
131          * @return true if error is enabled in the underlying logger.
132          */
133         boolean isErrorEnabled();
134 
135         /**
136          * Logs a message with error log level.
137          *
138          * @param message log this message
139          */
140         void error(Object message);
141     }
142 
143     /**
144      * Sets the Logger_.
145      * @param logger the logger
146      */
147     public void setLogger(final Logger logger) {
148         logger_ = logger;
149     }
150 
151     /**
152      * Returns the current Logger.
153      * @return the logger
154      */
155     public Logger getLogger() {
156         return logger_;
157     }
158 
159     @Override
160     public void print(final Context cx, final Scriptable scope, final Level level,
161             final Object[] args, final ScriptStackElement[] stack) {
162         switch (level) {
163             case TRACE:
164                 if (logger_.isInfoEnabled()) {
165                     String msg = format(cx, scope, args);
166                     if (stack != null) {
167                         final StringBuilder scriptStack = new StringBuilder();
168                         scriptStack.append(msg);
169 
170                         for (final ScriptStackElement scriptStackElement : stack) {
171                             if (scriptStack.length() > 0) {
172                                 scriptStack.append('\n');
173                             }
174                             scriptStack.append(scriptStackElement);
175                         }
176 
177                         msg = scriptStack.toString();
178                     }
179                     logger_.info(msg);
180                 }
181                 break;
182             case DEBUG:
183                 if (logger_.isDebugEnabled()) {
184                     logger_.debug(format(cx, scope, args));
185                 }
186                 break;
187             case INFO:
188                 if (logger_.isInfoEnabled()) {
189                     logger_.info(format(cx, scope, args));
190                 }
191                 break;
192             case WARN:
193                 if (logger_.isWarnEnabled()) {
194                     logger_.warn(format(cx, scope, args));
195                 }
196                 break;
197             case ERROR:
198                 if (logger_.isErrorEnabled()) {
199                     logger_.error(format(cx, scope, args));
200                 }
201                 break;
202 
203             default:
204                 break;
205         }
206     }
207 
208     private static String format(final Context cx, final Scriptable scope, final Object[] args) {
209         String msg = NativeConsole.format(cx, scope, args);
210         msg = msg.replaceAll("\\r?\\n", "\n");
211         return msg;
212     }
213 
214     private void readObject(final ObjectInputStream ois) throws ClassNotFoundException, IOException {
215         ois.defaultReadObject();
216         setLogger(new DefaultLogger(LOG));
217     }
218 
219     /**
220      * This class is the default logger used by WebConsole.
221      */
222     private static class DefaultLogger implements Logger {
223 
224         private final Log webConsoleLogger_;
225 
226         /**
227          * Ctor.
228          */
229         DefaultLogger(final Log logger) {
230             super();
231             webConsoleLogger_ = logger;
232         }
233 
234         @Override
235         public boolean isTraceEnabled() {
236             return webConsoleLogger_.isTraceEnabled();
237         }
238 
239         @Override
240         public void trace(final Object message) {
241             webConsoleLogger_.trace(message);
242         }
243 
244         @Override
245         public boolean isDebugEnabled() {
246             return webConsoleLogger_.isDebugEnabled();
247         }
248 
249         @Override
250         public void debug(final Object message) {
251             webConsoleLogger_.debug(message);
252         }
253 
254         @Override
255         public boolean isInfoEnabled() {
256             return webConsoleLogger_.isInfoEnabled();
257         }
258 
259         @Override
260         public void info(final Object message) {
261             webConsoleLogger_.info(message);
262         }
263 
264         @Override
265         public boolean isWarnEnabled() {
266             return webConsoleLogger_.isWarnEnabled();
267         }
268 
269         @Override
270         public void warn(final Object message) {
271             webConsoleLogger_.warn(message);
272         }
273 
274         @Override
275         public boolean isErrorEnabled() {
276             return webConsoleLogger_.isErrorEnabled();
277         }
278 
279         @Override
280         public void error(final Object message) {
281             webConsoleLogger_.error(message);
282         }
283     }
284 }