This form avoids superfluous object creation when the logger + * is disabled for the TRACE level.
+ * + * @param format the format string + * @param arg the argument + */ + void trace(String format, Object arg); + + /** + * Log a message at the TRACE level according to the specified format + * and arguments. + * + *This form avoids superfluous object creation when the logger + * is disabled for the TRACE level.
+ * + * @param format the format string + * @param argA the first argument + * @param argB the second argument + */ + void trace(String format, Object argA, Object argB); + + /** + * Log a message at the TRACE level according to the specified format + * and arguments. + * + *This form avoids superfluous string concatenation when the logger + * is disabled for the TRACE level. However, this variant incurs the hidden + * (and relatively small) cost of creating an {@code Object[]} before invoking the method, + * even if this logger is disabled for TRACE. The variants taking {@link #trace(String, Object) one} and + * {@link #trace(String, Object, Object) two} arguments exist solely in order to avoid this hidden cost.
+ * + * @param format the format string + * @param arguments a list of 3 or more arguments + */ + void trace(String format, Object... arguments); + + /** + * Log an exception (throwable) at the TRACE level with an + * accompanying message. + * + * @param msg the message accompanying the exception + * @param t the exception (throwable) to log + */ + void trace(String msg, Throwable t); + + /** + * Is the logger instance enabled for the DEBUG level? + * + * @return True if this Logger is enabled for the DEBUG level, + * false otherwise. + */ + boolean isDebugEnabled(); + + /** + * Log a message at the DEBUG level. + * + * @param msg the message string to be logged + */ + void debug(String msg); + + /** + * Log a message at the DEBUG level according to the specified format + * and argument. + * + *This form avoids superfluous object creation when the logger + * is disabled for the DEBUG level.
+ * + * @param format the format string + * @param arg the argument + */ + void debug(String format, Object arg); + + /** + * Log a message at the DEBUG level according to the specified format + * and arguments. + * + *This form avoids superfluous object creation when the logger + * is disabled for the DEBUG level.
+ * + * @param format the format string + * @param argA the first argument + * @param argB the second argument + */ + void debug(String format, Object argA, Object argB); + + /** + * Log a message at the DEBUG level according to the specified format + * and arguments. + * + *This form avoids superfluous string concatenation when the logger + * is disabled for the DEBUG level. However, this variant incurs the hidden + * (and relatively small) cost of creating an {@code Object[]} before invoking the method, + * even if this logger is disabled for DEBUG. The variants taking + * {@link #debug(String, Object) one} and {@link #debug(String, Object, Object) two} + * arguments exist solely in order to avoid this hidden cost.
+ * + * @param format the format string + * @param arguments a list of 3 or more arguments + */ + void debug(String format, Object... arguments); + + /** + * Log an exception (throwable) at the DEBUG level with an + * accompanying message. + * + * @param msg the message accompanying the exception + * @param t the exception (throwable) to log + */ + void debug(String msg, Throwable t); + + /** + * Is the logger instance enabled for the INFO level? + * + * @return True if this Logger is enabled for the INFO level, + * false otherwise. + */ + boolean isInfoEnabled(); + + /** + * Log a message at the INFO level. + * + * @param msg the message string to be logged + */ + void info(String msg); + + /** + * Log a message at the INFO level according to the specified format + * and argument. + * + *This form avoids superfluous object creation when the logger + * is disabled for the INFO level.
+ * + * @param format the format string + * @param arg the argument + */ + void info(String format, Object arg); + + /** + * Log a message at the INFO level according to the specified format + * and arguments. + * + *This form avoids superfluous object creation when the logger + * is disabled for the INFO level.
+ * + * @param format the format string + * @param argA the first argument + * @param argB the second argument + */ + void info(String format, Object argA, Object argB); + + /** + * Log a message at the INFO level according to the specified format + * and arguments. + * + *This form avoids superfluous string concatenation when the logger + * is disabled for the INFO level. However, this variant incurs the hidden + * (and relatively small) cost of creating an {@code Object[]} before invoking the method, + * even if this logger is disabled for INFO. The variants taking + * {@link #info(String, Object) one} and {@link #info(String, Object, Object) two} + * arguments exist solely in order to avoid this hidden cost.
+ * + * @param format the format string + * @param arguments a list of 3 or more arguments + */ + void info(String format, Object... arguments); + + /** + * Log an exception (throwable) at the INFO level with an + * accompanying message. + * + * @param msg the message accompanying the exception + * @param t the exception (throwable) to log + */ + void info(String msg, Throwable t); + + /** + * Is the logger instance enabled for the WARN level? + * + * @return True if this Logger is enabled for the WARN level, + * false otherwise. + */ + boolean isWarnEnabled(); + + /** + * Log a message at the WARN level. + * + * @param msg the message string to be logged + */ + void warn(String msg); + + /** + * Log a message at the WARN level according to the specified format + * and argument. + * + *This form avoids superfluous object creation when the logger + * is disabled for the WARN level.
+ * + * @param format the format string + * @param arg the argument + */ + void warn(String format, Object arg); + + /** + * Log a message at the WARN level according to the specified format + * and arguments. + * + *This form avoids superfluous string concatenation when the logger + * is disabled for the WARN level. However, this variant incurs the hidden + * (and relatively small) cost of creating an {@code Object[]} before invoking the method, + * even if this logger is disabled for WARN. The variants taking + * {@link #warn(String, Object) one} and {@link #warn(String, Object, Object) two} + * arguments exist solely in order to avoid this hidden cost.
+ * + * @param format the format string + * @param arguments a list of 3 or more arguments + */ + void warn(String format, Object... arguments); + + /** + * Log a message at the WARN level according to the specified format + * and arguments. + * + *This form avoids superfluous object creation when the logger + * is disabled for the WARN level.
+ * + * @param format the format string + * @param argA the first argument + * @param argB the second argument + */ + void warn(String format, Object argA, Object argB); + + /** + * Log an exception (throwable) at the WARN level with an + * accompanying message. + * + * @param msg the message accompanying the exception + * @param t the exception (throwable) to log + */ + void warn(String msg, Throwable t); + + /** + * Is the logger instance enabled for the ERROR level? + * + * @return True if this Logger is enabled for the ERROR level, + * false otherwise. + */ + boolean isErrorEnabled(); + + /** + * Log a message at the ERROR level. + * + * @param msg the message string to be logged + */ + void error(String msg); + + /** + * Log a message at the ERROR level according to the specified format + * and argument. + * + *This form avoids superfluous object creation when the logger + * is disabled for the ERROR level.
+ * + * @param format the format string + * @param arg the argument + */ + void error(String format, Object arg); + + /** + * Log a message at the ERROR level according to the specified format + * and arguments. + * + *This form avoids superfluous object creation when the logger + * is disabled for the ERROR level.
+ * + * @param format the format string + * @param argA the first argument + * @param argB the second argument + */ + void error(String format, Object argA, Object argB); + + /** + * Log a message at the ERROR level according to the specified format + * and arguments. + * + *This form avoids superfluous string concatenation when the logger + * is disabled for the ERROR level. However, this variant incurs the hidden + * (and relatively small) cost of creating an {@code Object[]} before invoking the method, + * even if this logger is disabled for ERROR. The variants taking + * {@link #error(String, Object) one} and {@link #error(String, Object, Object) two} + * arguments exist solely in order to avoid this hidden cost.
+ * + * @param format the format string + * @param arguments a list of 3 or more arguments + */ + void error(String format, Object... arguments); + + /** + * Log an exception (throwable) at the ERROR level with an + * accompanying message. + * + * @param msg the message accompanying the exception + * @param t the exception (throwable) to log + */ + void error(String msg, Throwable t); + + /** + * Is the logger instance enabled for the specified {@code level}? + * + * @return True if this Logger is enabled for the specified {@code level}, + * false otherwise. + */ + boolean isEnabled(InternalLogLevel level); + + /** + * Log a message at the specified {@code level}. + * + * @param msg the message string to be logged + */ + void log(InternalLogLevel level, String msg); + + /** + * Log a message at the specified {@code level} according to the specified format + * and argument. + * + *This form avoids superfluous object creation when the logger + * is disabled for the specified {@code level}.
+ * + * @param format the format string + * @param arg the argument + */ + void log(InternalLogLevel level, String format, Object arg); + + /** + * Log a message at the specified {@code level} according to the specified format + * and arguments. + * + *This form avoids superfluous object creation when the logger + * is disabled for the specified {@code level}.
+ * + * @param format the format string + * @param argA the first argument + * @param argB the second argument + */ + void log(InternalLogLevel level, String format, Object argA, Object argB); + + /** + * Log a message at the specified {@code level} according to the specified format + * and arguments. + * + *This form avoids superfluous string concatenation when the logger + * is disabled for the specified {@code level}. However, this variant incurs the hidden + * (and relatively small) cost of creating an {@code Object[]} before invoking the method, + * even if this logger is disabled for the specified {@code level}. The variants taking + * {@link #log(InternalLogLevel, String, Object) one} and + * {@link #log(InternalLogLevel, String, Object, Object) two} arguments exist solely + * in order to avoid this hidden cost.
+ * + * @param format the format string + * @param arguments a list of 3 or more arguments + */ + void log(InternalLogLevel level, String format, Object... arguments); + + /** + * Log an exception (throwable) at the specified {@code level} with an + * accompanying message. + * + * @param msg the message accompanying the exception + * @param t the exception (throwable) to log + */ + void log(InternalLogLevel level, String msg, Throwable t); +} diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/logging/InternalLoggerFactory.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/logging/InternalLoggerFactory.java new file mode 100644 index 00000000..f29d389b --- /dev/null +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/logging/InternalLoggerFactory.java @@ -0,0 +1,88 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package com.foxinmy.weixin4j.logging; + +/** + * Creates an {@link InternalLogger} or changes the default factory + * implementation. This factory allows you to choose what logging framework + * Netty should use. The default factory is {@link Slf4JLoggerFactory}. If SLF4J + * is not available, {@link JdkLoggerFactory} is used. You can change it to your + * preferred logging framework before other Netty classes are loaded: + * + *
+ * {@link InternalLoggerFactory}.setDefaultFactory(new {@link Log4JLoggerFactory}());
+ *
+ *
+ * Please note that the new default factory is effective only for the classes
+ * which were loaded after the default factory is changed. Therefore,
+ * {@link #setDefaultFactory(InternalLoggerFactory)} should be called as early
+ * as possible and shouldn't be called more than once.
+ */
+public abstract class InternalLoggerFactory {
+ private static volatile InternalLoggerFactory defaultFactory = newDefaultFactory(InternalLoggerFactory.class
+ .getName());
+
+ private static InternalLoggerFactory newDefaultFactory(String name) {
+ InternalLoggerFactory f;
+ try {
+ f = new Slf4JLoggerFactory(true);
+ f.newInstance(name).debug(
+ "Using SLF4J as the default logging framework");
+ } catch (Throwable t1) {
+ f = new JdkLoggerFactory();
+ f.newInstance(name).debug(
+ "Using java.util.logging as the default logging framework");
+ }
+ return f;
+ }
+
+ /**
+ * Returns the default factory. The initial default factory is
+ * {@link JdkLoggerFactory}.
+ */
+ public static InternalLoggerFactory getDefaultFactory() {
+ return defaultFactory;
+ }
+
+ /**
+ * Changes the default factory.
+ */
+ public static void setDefaultFactory(InternalLoggerFactory defaultFactory) {
+ if (defaultFactory == null) {
+ throw new NullPointerException("defaultFactory");
+ }
+ InternalLoggerFactory.defaultFactory = defaultFactory;
+ }
+
+ /**
+ * Creates a new logger instance with the name of the specified class.
+ */
+ public static InternalLogger getInstance(Class> clazz) {
+ return getInstance(clazz.getName());
+ }
+
+ /**
+ * Creates a new logger instance with the specified name.
+ */
+ public static InternalLogger getInstance(String name) {
+ return getDefaultFactory().newInstance(name);
+ }
+
+ /**
+ * Creates a new logger instance with the specified name.
+ */
+ protected abstract InternalLogger newInstance(String name);
+}
diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/logging/JdkLogger.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/logging/JdkLogger.java
new file mode 100644
index 00000000..8813651b
--- /dev/null
+++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/logging/JdkLogger.java
@@ -0,0 +1,647 @@
+/*
+ * Copyright 2012 The Netty Project
+ *
+ * The Netty Project licenses this file to you under the Apache License,
+ * version 2.0 (the "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+/**
+ * Copyright (c) 2004-2011 QOS.ch
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+package com.foxinmy.weixin4j.logging;
+
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
+import java.util.logging.Logger;
+
+/**
+ * java.util.logging
+ * logger.
+ */
+class JdkLogger extends AbstractInternalLogger {
+
+ private static final long serialVersionUID = -1767272577989225979L;
+
+ final transient Logger logger;
+
+ JdkLogger(Logger logger) {
+ super(logger.getName());
+ this.logger = logger;
+ }
+
+ /**
+ * Is this logger instance enabled for the FINEST level?
+ *
+ * @return True if this Logger is enabled for level FINEST, false otherwise.
+ */
+ @Override
+ public boolean isTraceEnabled() {
+ return logger.isLoggable(Level.FINEST);
+ }
+
+ /**
+ * Log a message object at level FINEST.
+ *
+ * @param msg
+ * - the message object to be logged
+ */
+ @Override
+ public void trace(String msg) {
+ if (logger.isLoggable(Level.FINEST)) {
+ log(SELF, Level.FINEST, msg, null);
+ }
+ }
+
+ /**
+ * Log a message at level FINEST according to the specified format and
+ * argument.
+ *
+ * + * This form avoids superfluous object creation when the logger is disabled + * for level FINEST. + *
+ * + * @param format + * the format string + * @param arg + * the argument + */ + @Override + public void trace(String format, Object arg) { + if (logger.isLoggable(Level.FINEST)) { + FormattingTuple ft = MessageFormatter.format(format, arg); + log(SELF, Level.FINEST, ft.getMessage(), ft.getThrowable()); + } + } + + /** + * Log a message at level FINEST according to the specified format and + * arguments. + * + *+ * This form avoids superfluous object creation when the logger is disabled + * for the FINEST level. + *
+ * + * @param format + * the format string + * @param argA + * the first argument + * @param argB + * the second argument + */ + @Override + public void trace(String format, Object argA, Object argB) { + if (logger.isLoggable(Level.FINEST)) { + FormattingTuple ft = MessageFormatter.format(format, argA, argB); + log(SELF, Level.FINEST, ft.getMessage(), ft.getThrowable()); + } + } + + /** + * Log a message at level FINEST according to the specified format and + * arguments. + * + *+ * This form avoids superfluous object creation when the logger is disabled + * for the FINEST level. + *
+ * + * @param format + * the format string + * @param argArray + * an array of arguments + */ + @Override + public void trace(String format, Object... argArray) { + if (logger.isLoggable(Level.FINEST)) { + FormattingTuple ft = MessageFormatter.arrayFormat(format, argArray); + log(SELF, Level.FINEST, ft.getMessage(), ft.getThrowable()); + } + } + + /** + * Log an exception (throwable) at level FINEST with an accompanying message. + * + * @param msg + * the message accompanying the exception + * @param t + * the exception (throwable) to log + */ + @Override + public void trace(String msg, Throwable t) { + if (logger.isLoggable(Level.FINEST)) { + log(SELF, Level.FINEST, msg, t); + } + } + + /** + * Is this logger instance enabled for the FINE level? + * + * @return True if this Logger is enabled for level FINE, false otherwise. + */ + @Override + public boolean isDebugEnabled() { + return logger.isLoggable(Level.FINE); + } + + /** + * Log a message object at level FINE. + * + * @param msg + * - the message object to be logged + */ + @Override + public void debug(String msg) { + if (logger.isLoggable(Level.FINE)) { + log(SELF, Level.FINE, msg, null); + } + } + + /** + * Log a message at level FINE according to the specified format and argument. + * + *+ * This form avoids superfluous object creation when the logger is disabled + * for level FINE. + *
+ * + * @param format + * the format string + * @param arg + * the argument + */ + @Override + public void debug(String format, Object arg) { + if (logger.isLoggable(Level.FINE)) { + FormattingTuple ft = MessageFormatter.format(format, arg); + log(SELF, Level.FINE, ft.getMessage(), ft.getThrowable()); + } + } + + /** + * Log a message at level FINE according to the specified format and + * arguments. + * + *+ * This form avoids superfluous object creation when the logger is disabled + * for the FINE level. + *
+ * + * @param format + * the format string + * @param argA + * the first argument + * @param argB + * the second argument + */ + @Override + public void debug(String format, Object argA, Object argB) { + if (logger.isLoggable(Level.FINE)) { + FormattingTuple ft = MessageFormatter.format(format, argA, argB); + log(SELF, Level.FINE, ft.getMessage(), ft.getThrowable()); + } + } + + /** + * Log a message at level FINE according to the specified format and + * arguments. + * + *+ * This form avoids superfluous object creation when the logger is disabled + * for the FINE level. + *
+ * + * @param format + * the format string + * @param argArray + * an array of arguments + */ + @Override + public void debug(String format, Object... argArray) { + if (logger.isLoggable(Level.FINE)) { + FormattingTuple ft = MessageFormatter.arrayFormat(format, argArray); + log(SELF, Level.FINE, ft.getMessage(), ft.getThrowable()); + } + } + + /** + * Log an exception (throwable) at level FINE with an accompanying message. + * + * @param msg + * the message accompanying the exception + * @param t + * the exception (throwable) to log + */ + @Override + public void debug(String msg, Throwable t) { + if (logger.isLoggable(Level.FINE)) { + log(SELF, Level.FINE, msg, t); + } + } + + /** + * Is this logger instance enabled for the INFO level? + * + * @return True if this Logger is enabled for the INFO level, false otherwise. + */ + @Override + public boolean isInfoEnabled() { + return logger.isLoggable(Level.INFO); + } + + /** + * Log a message object at the INFO level. + * + * @param msg + * - the message object to be logged + */ + @Override + public void info(String msg) { + if (logger.isLoggable(Level.INFO)) { + log(SELF, Level.INFO, msg, null); + } + } + + /** + * Log a message at level INFO according to the specified format and argument. + * + *+ * This form avoids superfluous object creation when the logger is disabled + * for the INFO level. + *
+ * + * @param format + * the format string + * @param arg + * the argument + */ + @Override + public void info(String format, Object arg) { + if (logger.isLoggable(Level.INFO)) { + FormattingTuple ft = MessageFormatter.format(format, arg); + log(SELF, Level.INFO, ft.getMessage(), ft.getThrowable()); + } + } + + /** + * Log a message at the INFO level according to the specified format and + * arguments. + * + *+ * This form avoids superfluous object creation when the logger is disabled + * for the INFO level. + *
+ * + * @param format + * the format string + * @param argA + * the first argument + * @param argB + * the second argument + */ + @Override + public void info(String format, Object argA, Object argB) { + if (logger.isLoggable(Level.INFO)) { + FormattingTuple ft = MessageFormatter.format(format, argA, argB); + log(SELF, Level.INFO, ft.getMessage(), ft.getThrowable()); + } + } + + /** + * Log a message at level INFO according to the specified format and + * arguments. + * + *+ * This form avoids superfluous object creation when the logger is disabled + * for the INFO level. + *
+ * + * @param format + * the format string + * @param argArray + * an array of arguments + */ + @Override + public void info(String format, Object... argArray) { + if (logger.isLoggable(Level.INFO)) { + FormattingTuple ft = MessageFormatter.arrayFormat(format, argArray); + log(SELF, Level.INFO, ft.getMessage(), ft.getThrowable()); + } + } + + /** + * Log an exception (throwable) at the INFO level with an accompanying + * message. + * + * @param msg + * the message accompanying the exception + * @param t + * the exception (throwable) to log + */ + @Override + public void info(String msg, Throwable t) { + if (logger.isLoggable(Level.INFO)) { + log(SELF, Level.INFO, msg, t); + } + } + + /** + * Is this logger instance enabled for the WARNING level? + * + * @return True if this Logger is enabled for the WARNING level, false + * otherwise. + */ + @Override + public boolean isWarnEnabled() { + return logger.isLoggable(Level.WARNING); + } + + /** + * Log a message object at the WARNING level. + * + * @param msg + * - the message object to be logged + */ + @Override + public void warn(String msg) { + if (logger.isLoggable(Level.WARNING)) { + log(SELF, Level.WARNING, msg, null); + } + } + + /** + * Log a message at the WARNING level according to the specified format and + * argument. + * + *+ * This form avoids superfluous object creation when the logger is disabled + * for the WARNING level. + *
+ * + * @param format + * the format string + * @param arg + * the argument + */ + @Override + public void warn(String format, Object arg) { + if (logger.isLoggable(Level.WARNING)) { + FormattingTuple ft = MessageFormatter.format(format, arg); + log(SELF, Level.WARNING, ft.getMessage(), ft.getThrowable()); + } + } + + /** + * Log a message at the WARNING level according to the specified format and + * arguments. + * + *+ * This form avoids superfluous object creation when the logger is disabled + * for the WARNING level. + *
+ * + * @param format + * the format string + * @param argA + * the first argument + * @param argB + * the second argument + */ + @Override + public void warn(String format, Object argA, Object argB) { + if (logger.isLoggable(Level.WARNING)) { + FormattingTuple ft = MessageFormatter.format(format, argA, argB); + log(SELF, Level.WARNING, ft.getMessage(), ft.getThrowable()); + } + } + + /** + * Log a message at level WARNING according to the specified format and + * arguments. + * + *+ * This form avoids superfluous object creation when the logger is disabled + * for the WARNING level. + *
+ * + * @param format + * the format string + * @param argArray + * an array of arguments + */ + @Override + public void warn(String format, Object... argArray) { + if (logger.isLoggable(Level.WARNING)) { + FormattingTuple ft = MessageFormatter.arrayFormat(format, argArray); + log(SELF, Level.WARNING, ft.getMessage(), ft.getThrowable()); + } + } + + /** + * Log an exception (throwable) at the WARNING level with an accompanying + * message. + * + * @param msg + * the message accompanying the exception + * @param t + * the exception (throwable) to log + */ + @Override + public void warn(String msg, Throwable t) { + if (logger.isLoggable(Level.WARNING)) { + log(SELF, Level.WARNING, msg, t); + } + } + + /** + * Is this logger instance enabled for level SEVERE? + * + * @return True if this Logger is enabled for level SEVERE, false otherwise. + */ + @Override + public boolean isErrorEnabled() { + return logger.isLoggable(Level.SEVERE); + } + + /** + * Log a message object at the SEVERE level. + * + * @param msg + * - the message object to be logged + */ + @Override + public void error(String msg) { + if (logger.isLoggable(Level.SEVERE)) { + log(SELF, Level.SEVERE, msg, null); + } + } + + /** + * Log a message at the SEVERE level according to the specified format and + * argument. + * + *+ * This form avoids superfluous object creation when the logger is disabled + * for the SEVERE level. + *
+ * + * @param format + * the format string + * @param arg + * the argument + */ + @Override + public void error(String format, Object arg) { + if (logger.isLoggable(Level.SEVERE)) { + FormattingTuple ft = MessageFormatter.format(format, arg); + log(SELF, Level.SEVERE, ft.getMessage(), ft.getThrowable()); + } + } + + /** + * Log a message at the SEVERE level according to the specified format and + * arguments. + * + *+ * This form avoids superfluous object creation when the logger is disabled + * for the SEVERE level. + *
+ * + * @param format + * the format string + * @param argA + * the first argument + * @param argB + * the second argument + */ + @Override + public void error(String format, Object argA, Object argB) { + if (logger.isLoggable(Level.SEVERE)) { + FormattingTuple ft = MessageFormatter.format(format, argA, argB); + log(SELF, Level.SEVERE, ft.getMessage(), ft.getThrowable()); + } + } + + /** + * Log a message at level SEVERE according to the specified format and + * arguments. + * + *+ * This form avoids superfluous object creation when the logger is disabled + * for the SEVERE level. + *
+ * + * @param format + * the format string + * @param arguments + * an array of arguments + */ + @Override + public void error(String format, Object... arguments) { + if (logger.isLoggable(Level.SEVERE)) { + FormattingTuple ft = MessageFormatter.arrayFormat(format, arguments); + log(SELF, Level.SEVERE, ft.getMessage(), ft.getThrowable()); + } + } + + /** + * Log an exception (throwable) at the SEVERE level with an accompanying + * message. + * + * @param msg + * the message accompanying the exception + * @param t + * the exception (throwable) to log + */ + @Override + public void error(String msg, Throwable t) { + if (logger.isLoggable(Level.SEVERE)) { + log(SELF, Level.SEVERE, msg, t); + } + } + + /** + * Log the message at the specified level with the specified throwable if any. + * This method creates a LogRecord and fills in caller date before calling + * this instance's JDK14 logger. + * + * See bug report #13 for more details. + */ + private void log(String callerFQCN, Level level, String msg, Throwable t) { + // millis and thread are filled by the constructor + LogRecord record = new LogRecord(level, msg); + record.setLoggerName(name()); + record.setThrown(t); + fillCallerData(callerFQCN, record); + logger.log(record); + } + + static final String SELF = JdkLogger.class.getName(); + static final String SUPER = AbstractInternalLogger.class.getName(); + + /** + * Fill in caller data if possible. + * + * @param record + * The record to update + */ + private static void fillCallerData(String callerFQCN, LogRecord record) { + StackTraceElement[] steArray = new Throwable().getStackTrace(); + + int selfIndex = -1; + for (int i = 0; i < steArray.length; i++) { + final String className = steArray[i].getClassName(); + if (className.equals(callerFQCN) || className.equals(SUPER)) { + selfIndex = i; + break; + } + } + + int found = -1; + for (int i = selfIndex + 1; i < steArray.length; i++) { + final String className = steArray[i].getClassName(); + if (!(className.equals(callerFQCN) || className.equals(SUPER))) { + found = i; + break; + } + } + + if (found != -1) { + StackTraceElement ste = steArray[found]; + // setting the class name has the side effect of setting + // the needToInferCaller variable to false. + record.setSourceClassName(ste.getClassName()); + record.setSourceMethodName(ste.getMethodName()); + } + } +} diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/logging/JdkLoggerFactory.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/logging/JdkLoggerFactory.java new file mode 100644 index 00000000..81397cd6 --- /dev/null +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/logging/JdkLoggerFactory.java @@ -0,0 +1,32 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package com.foxinmy.weixin4j.logging; + + +import java.util.logging.Logger; + +/** + * Logger factory which creates a + * java.util.logging + * logger. + */ +public class JdkLoggerFactory extends InternalLoggerFactory { + + @Override + public InternalLogger newInstance(String name) { + return new JdkLogger(Logger.getLogger(name)); + } +} diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/logging/MessageFormatter.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/logging/MessageFormatter.java new file mode 100644 index 00000000..cce05f0b --- /dev/null +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/logging/MessageFormatter.java @@ -0,0 +1,428 @@ +/* + * Copyright 2013 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/** + * Copyright (c) 2004-2011 QOS.ch + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ +package com.foxinmy.weixin4j.logging; + +import java.text.MessageFormat; +import java.util.HashMap; +import java.util.Map; + +// contributors: lizongbo: proposed special treatment of array parameter values +// Joern Huxhorn: pointed out double[] omission, suggested deep array copy + +/** + * Formats messages according to very simple substitution rules. Substitutions + * can be made 1, 2 or more arguments. + * + * + * For example, + * + *
+ * MessageFormatter.format("Hi {}.", "there")
+ *
+ *
+ * will return the string "Hi there.".
+ *
+ * The {} pair is called the formatting anchor. It serves to designate
+ * the location where arguments need to be substituted within the message
+ * pattern.
+ *
+ * In case your message contains the '{' or the '}' character, you do not have
+ * to do anything special unless the '}' character immediately follows '{'. For
+ * example,
+ *
+ *
+ * MessageFormatter.format("Set {1,2,3} is not equal to {}.", "1,2");
+ *
+ *
+ * will return the string "Set {1,2,3} is not equal to 1,2.".
+ *
+ *
+ * If for whatever reason you need to place the string "{}" in the message
+ * without its formatting anchor meaning, then you need to escape the
+ * '{' character with '\', that is the backslash character. Only the '{'
+ * character should be escaped. There is no need to escape the '}' character.
+ * For example,
+ *
+ *
+ * MessageFormatter.format("Set \\{} is not equal to {}.", "1,2");
+ *
+ *
+ * will return the string "Set {} is not equal to 1,2.".
+ *
+ *
+ * The escaping behavior just described can be overridden by escaping the escape
+ * character '\'. Calling
+ *
+ *
+ * MessageFormatter.format("File name is C:\\\\{}.", "file.zip");
+ *
+ *
+ * will return the string "File name is C:\file.zip".
+ *
+ *
+ * The formatting conventions are different than those of {@link MessageFormat}
+ * which ships with the Java platform. This is justified by the fact that
+ * SLF4J's implementation is 10 times faster than that of {@link MessageFormat}.
+ * This local performance difference is both measurable and significant in the
+ * larger context of the complete logging processing chain.
+ *
+ *
+ * See also {@link #format(String, Object)},
+ * {@link #format(String, Object, Object)} and
+ * {@link #arrayFormat(String, Object[])} methods for more details.
+ */
+final class MessageFormatter {
+ static final char DELIM_START = '{';
+ static final char DELIM_STOP = '}';
+ static final String DELIM_STR = "{}";
+ private static final char ESCAPE_CHAR = '\\';
+
+ /**
+ * Performs single argument substitution for the 'messagePattern' passed as
+ * parameter.
+ *
+ * For example,
+ *
+ *
+ * MessageFormatter.format("Hi {}.", "there");
+ *
+ *
+ * will return the string "Hi there.".
+ *
+ *
+ * @param messagePattern The message pattern which will be parsed and formatted
+ * @param arg The argument to be substituted in place of the formatting anchor
+ * @return The formatted message
+ */
+ static FormattingTuple format(String messagePattern, Object arg) {
+ return arrayFormat(messagePattern, new Object[]{arg});
+ }
+
+ /**
+ * Performs a two argument substitution for the 'messagePattern' passed as
+ * parameter.
+ *
+ * For example,
+ *
+ *
+ * MessageFormatter.format("Hi {}. My name is {}.", "Alice", "Bob");
+ *
+ *
+ * will return the string "Hi Alice. My name is Bob.".
+ *
+ * @param messagePattern The message pattern which will be parsed and formatted
+ * @param argA The argument to be substituted in place of the first formatting
+ * anchor
+ * @param argB The argument to be substituted in place of the second formatting
+ * anchor
+ * @return The formatted message
+ */
+ static FormattingTuple format(final String messagePattern,
+ Object argA, Object argB) {
+ return arrayFormat(messagePattern, new Object[]{argA, argB});
+ }
+
+ static Throwable getThrowableCandidate(Object[] argArray) {
+ if (argArray == null || argArray.length == 0) {
+ return null;
+ }
+
+ final Object lastEntry = argArray[argArray.length - 1];
+ if (lastEntry instanceof Throwable) {
+ return (Throwable) lastEntry;
+ }
+ return null;
+ }
+
+ /**
+ * Same principle as the {@link #format(String, Object)} and
+ * {@link #format(String, Object, Object)} methods except that any number of
+ * arguments can be passed in an array.
+ *
+ * @param messagePattern The message pattern which will be parsed and formatted
+ * @param argArray An array of arguments to be substituted in place of formatting
+ * anchors
+ * @return The formatted message
+ */
+ static FormattingTuple arrayFormat(final String messagePattern,
+ final Object[] argArray) {
+
+ Throwable throwableCandidate = getThrowableCandidate(argArray);
+
+ if (messagePattern == null) {
+ return new FormattingTuple(null, argArray, throwableCandidate);
+ }
+
+ if (argArray == null) {
+ return new FormattingTuple(messagePattern);
+ }
+
+ int i = 0;
+ int j;
+ StringBuffer sbuf = new StringBuffer(messagePattern.length() + 50);
+
+ int L;
+ for (L = 0; L < argArray.length; L++) {
+
+ j = messagePattern.indexOf(DELIM_STR, i);
+
+ if (j == -1) {
+ // no more variables
+ if (i == 0) { // this is a simple string
+ return new FormattingTuple(messagePattern, argArray,
+ throwableCandidate);
+ } else { // add the tail string which contains no variables and return
+ // the result.
+ sbuf.append(messagePattern.substring(i, messagePattern.length()));
+ return new FormattingTuple(sbuf.toString(), argArray,
+ throwableCandidate);
+ }
+ } else {
+ if (isEscapedDelimeter(messagePattern, j)) {
+ if (!isDoubleEscaped(messagePattern, j)) {
+ L--; // DELIM_START was escaped, thus should not be incremented
+ sbuf.append(messagePattern.substring(i, j - 1));
+ sbuf.append(DELIM_START);
+ i = j + 1;
+ } else {
+ // The escape character preceding the delimiter start is
+ // itself escaped: "abc x:\\{}"
+ // we have to consume one backward slash
+ sbuf.append(messagePattern.substring(i, j - 1));
+ deeplyAppendParameter(sbuf, argArray[L], new HashMap