You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by ma...@apache.org on 2014/05/18 20:40:54 UTC

svn commit: r1595653 [5/11] - in /logging/log4j/log4j2/branches/experimental: ./ log4j-1.2-api/src/main/java/org/apache/log4j/ log4j-1.2-api/src/test/java/org/apache/log4j/ log4j-api/ log4j-api/src/main/java/org/apache/logging/log4j/ log4j-api/src/main...

Modified: logging/log4j/log4j2/branches/experimental/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxy.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/branches/experimental/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxy.java?rev=1595653&r1=1595652&r2=1595653&view=diff
==============================================================================
--- logging/log4j/log4j2/branches/experimental/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxy.java (original)
+++ logging/log4j/log4j2/branches/experimental/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableProxy.java Sun May 18 18:40:48 2014
@@ -17,42 +17,68 @@
 package org.apache.logging.log4j.core.impl;
 
 import java.io.Serializable;
-import java.lang.reflect.Method;
 import java.net.URL;
 import java.security.CodeSource;
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Stack;
 
 import org.apache.logging.log4j.Logger;
-import org.apache.logging.log4j.core.helpers.Loader;
+import org.apache.logging.log4j.core.util.Loader;
+import org.apache.logging.log4j.core.util.Throwables;
 import org.apache.logging.log4j.status.StatusLogger;
+import org.apache.logging.log4j.util.Strings;
 
 /**
  * Wraps a Throwable to add packaging information about each stack trace element.
+ *
+ * <p>
+ * A proxy is used to represent a throwable that may not exist in a different class loader or JVM. When an application deserializes a
+ * ThrowableProxy, the throwable may not be set, but the throwable's information is preserved in other fields of the proxy like the message
+ * and stack trace.
+ * </p>
+ *
+ * TODO: Move this class to org.apache.logging.log4j.core because it is used from LogEvent.
+ * TODO: Deserialize: Try to rebuild Throwable if the target exception is in this class loader?
  */
 public class ThrowableProxy implements Serializable {
 
-    private static final long serialVersionUID = -2752771578252251910L;
-
-    private static final Logger LOGGER = StatusLogger.getLogger();
-
-    private static final PrivateSecurityManager SECURITY_MANAGER;
+    /**
+     * Cached StackTracePackageElement and ClassLoader.
+     * <p>
+     * Consider this class private.
+     * </p>
+     */
+    static class CacheEntry {
+        private final ExtendedStackTraceElement element;
+        private final ClassLoader loader;
 
-    private static final Method GET_SUPPRESSED;
+        public CacheEntry(final ExtendedStackTraceElement element, final ClassLoader loader) {
+            this.element = element;
+            this.loader = loader;
+        }
+    }
 
-    private static final Method ADD_SUPPRESSED;
+    /**
+     * Security Manager for accessing the call stack.
+     */
+    private static class PrivateSecurityManager extends SecurityManager {
+        public Class<?>[] getClasses() {
+            return this.getClassContext();
+        }
+    }
 
-    private final ThrowableProxy proxyCause;
+    private static final ThrowableProxy[] EMPTY_THROWABLE_PROXY_ARRAY = new ThrowableProxy[0];
 
-    private final transient Throwable throwable;
+    private static final char EOL = '\n';
 
-    private final String name;
+    private static final Logger LOGGER = StatusLogger.getLogger();
 
-    private final StackTracePackageElement[] callerPackageData;
+    private static final PrivateSecurityManager SECURITY_MANAGER;
 
-    private int commonElementCount;
+    private static final long serialVersionUID = -2752771578252251910L;
 
     static {
         if (ReflectiveCallerClassUtility.isSupported()) {
@@ -72,240 +98,364 @@ public class ThrowableProxy implements S
             }
             SECURITY_MANAGER = securityManager;
         }
+    }
 
-        Method getSuppressed = null, addSuppressed = null;
-        final Method[] methods = Throwable.class.getMethods();
-        for (final Method method : methods) {
-            if (method.getName().equals("getSuppressed")) {
-                getSuppressed = method;
-            } else if (method.getName().equals("addSuppressed")) {
-                addSuppressed = method;
-            }
-        }
-        GET_SUPPRESSED = getSuppressed;
-        ADD_SUPPRESSED = addSuppressed;
+    private final ThrowableProxy causeProxy;
+
+    private int commonElementCount;
+
+    private final ExtendedStackTraceElement[] extendedStackTrace;
+
+    private final String localizedMessage;
+
+    private final String message;
+
+    private final String name;
+
+    private final ThrowableProxy[] suppressedProxies;
+
+    private final transient Throwable throwable;
+
+    /**
+     * For JSON and XML IO via Jackson.
+     */
+    @SuppressWarnings("unused")
+    private ThrowableProxy() {
+        this.throwable = null;
+        this.name = null;
+        this.extendedStackTrace = null;
+        this.causeProxy = null;
+        this.message = null;
+        this.localizedMessage = null;
+        this.suppressedProxies = EMPTY_THROWABLE_PROXY_ARRAY;
     }
 
     /**
-     * Construct the wrapper for the Throwable that includes packaging data.
-     * @param throwable The Throwable to wrap.
+     * Constructs the wrapper for the Throwable that includes packaging data.
+     *
+     * @param throwable The Throwable to wrap, must not be null.
      */
     public ThrowableProxy(final Throwable throwable) {
         this.throwable = throwable;
         this.name = throwable.getClass().getName();
+        this.message = throwable.getMessage();
+        this.localizedMessage = throwable.getLocalizedMessage();
         final Map<String, CacheEntry> map = new HashMap<String, CacheEntry>();
-        final Stack<Class<?>> stack = getCurrentStack();
-        callerPackageData = resolvePackageData(stack, map, null, throwable.getStackTrace());
-        this.proxyCause = throwable.getCause() == null ? null :
-            new ThrowableProxy(throwable, stack, map, throwable.getCause());
-        setSuppressed(throwable);
+        final Stack<Class<?>> stack = this.getCurrentStack();
+        this.extendedStackTrace = this.toExtendedStackTrace(stack, map, null, throwable.getStackTrace());
+        final Throwable throwableCause = throwable.getCause();
+        this.causeProxy = throwableCause == null ? null : new ThrowableProxy(throwable, stack, map, throwableCause);
+        this.suppressedProxies = this.toSuppressedProxies(throwable);
     }
 
     /**
-     * Constructs the wrapper for a Throwable that is referenced as the cause by another
-     * Throwable.
+     * Constructs the wrapper for a Throwable that is referenced as the cause by another Throwable.
+     *
      * @param parent The Throwable referencing this Throwable.
      * @param stack The Class stack.
      * @param map The cache containing the packaging data.
      * @param cause The Throwable to wrap.
      */
-    private ThrowableProxy(final Throwable parent, final Stack<Class<?>> stack, final Map<String, CacheEntry> map,
-                           final Throwable cause) {
+    private ThrowableProxy(final Throwable parent, final Stack<Class<?>> stack, final Map<String, CacheEntry> map, final Throwable cause) {
         this.throwable = cause;
         this.name = cause.getClass().getName();
-        callerPackageData = resolvePackageData(stack, map, parent.getStackTrace(), cause.getStackTrace());
-        this.proxyCause = cause.getCause() == null ? null :
-            new ThrowableProxy(parent, stack, map, cause.getCause());
-        setSuppressed(cause);
+        this.message = this.throwable.getMessage();
+        this.localizedMessage = this.throwable.getLocalizedMessage();
+        this.extendedStackTrace = this.toExtendedStackTrace(stack, map, parent.getStackTrace(), cause.getStackTrace());
+        this.causeProxy = cause.getCause() == null ? null : new ThrowableProxy(parent, stack, map, cause.getCause());
+        this.suppressedProxies = this.toSuppressedProxies(cause);
     }
 
-    public Throwable getThrowable() {
-        return throwable;
+    @Override
+    public boolean equals(final Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (this.getClass() != obj.getClass()) {
+            return false;
+        }
+        final ThrowableProxy other = (ThrowableProxy) obj;
+        if (this.causeProxy == null) {
+            if (other.causeProxy != null) {
+                return false;
+            }
+        } else if (!this.causeProxy.equals(other.causeProxy)) {
+            return false;
+        }
+        if (this.commonElementCount != other.commonElementCount) {
+            return false;
+        }
+        if (this.name == null) {
+            if (other.name != null) {
+                return false;
+            }
+        } else if (!this.name.equals(other.name)) {
+            return false;
+        }
+        if (!Arrays.equals(this.extendedStackTrace, other.extendedStackTrace)) {
+            return false;
+        }
+        if (!Arrays.equals(this.suppressedProxies, other.suppressedProxies)) {
+            return false;
+        }
+        return true;
     }
 
-    public ThrowableProxy getCause() {
-        return proxyCause;
+    @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
+    private void formatCause(final StringBuilder sb, final ThrowableProxy cause, final List<String> packages) {
+        sb.append("Caused by: ").append(cause).append(EOL);
+        this.formatElements(sb, cause.commonElementCount, cause.getThrowable().getStackTrace(), cause.extendedStackTrace, packages);
+        if (cause.getCauseProxy() != null) {
+            this.formatCause(sb, cause.causeProxy, packages);
+        }
     }
 
-    /**
-     * Return the FQCN of the Throwable.
-     * @return The FQCN of the Throwable.
-     */
-    public String getName() {
-        return name;
+    private void formatElements(final StringBuilder sb, final int commonCount, final StackTraceElement[] causedTrace,
+            final ExtendedStackTraceElement[] packageData, final List<String> packages) {
+        if (packages == null || packages.size() == 0) {
+            for (int i = 0; i < packageData.length; ++i) {
+                this.formatEntry(causedTrace[i], packageData[i], sb);
+            }
+        } else {
+            int count = 0;
+            for (int i = 0; i < packageData.length; ++i) {
+                if (!this.isSuppressed(causedTrace[i], packages)) {
+                    if (count > 0) {
+                        if (count == 1) {
+                            sb.append("\t....\n");
+                        } else {
+                            sb.append("\t... suppressed ").append(count).append(" lines\n");
+                        }
+                        count = 0;
+                    }
+                    this.formatEntry(causedTrace[i], packageData[i], sb);
+                } else {
+                    ++count;
+                }
+            }
+            if (count > 0) {
+                if (count == 1) {
+                    sb.append("\t...\n");
+                } else {
+                    sb.append("\t... suppressed ").append(count).append(" lines\n");
+                }
+            }
+        }
+        if (commonCount != 0) {
+            sb.append("\t... ").append(commonCount).append(" more").append('\n');
+        }
+    }
+
+    private void formatEntry(final StackTraceElement element, final ExtendedStackTraceElement packageData, final StringBuilder sb) {
+        sb.append("\tat ");
+        sb.append(element);
+        sb.append(' ');
+        sb.append(packageData);
+        sb.append('\n');
     }
 
     /**
-     * Return the number of elements that are being ommitted because they are common with the parent Throwable's
-     * stack trace.
-     * @return The number of elements ommitted from the stack trace.
+     * Formats the specified Throwable.
+     *
+     * @param sb StringBuilder to contain the formatted Throwable.
+     * @param cause The Throwable to format.
      */
-    public int getCommonElementCount() {
-        return commonElementCount;
+    public void formatWrapper(final StringBuilder sb, final ThrowableProxy cause) {
+        this.formatWrapper(sb, cause, null);
     }
 
     /**
-     * Return the package data associated with the stack trace.
-     * @return The package data associated with the stack trace.
+     * Formats the specified Throwable.
+     *
+     * @param sb StringBuilder to contain the formatted Throwable.
+     * @param cause The Throwable to format.
+     * @param packages The List of packages to be suppressed from the trace.
      */
-    public StackTracePackageElement[] getPackageData() {
-        return callerPackageData;
+    @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
+    public void formatWrapper(final StringBuilder sb, final ThrowableProxy cause, final List<String> packages) {
+        final Throwable caused = cause.getCauseProxy() != null ? cause.getCauseProxy().getThrowable() : null;
+        if (caused != null) {
+            this.formatWrapper(sb, cause.causeProxy);
+            sb.append("Wrapped by: ");
+        }
+        sb.append(cause).append('\n');
+        this.formatElements(sb, cause.commonElementCount, cause.getThrowable().getStackTrace(), cause.extendedStackTrace, packages);
     }
 
-    @Override
-    public String toString() {
-        final String msg = throwable.getMessage();
-        return msg != null ? name + ": " + msg : name;
+    public ThrowableProxy getCauseProxy() {
+        return this.causeProxy;
     }
 
     /**
      * Format the Throwable that is the cause of this Throwable.
+     *
      * @return The formatted Throwable that caused this Throwable.
      */
-    public String getRootCauseStackTrace() {
-        return getRootCauseStackTrace(null);
+    public String getCauseStackTraceAsString() {
+        return this.getCauseStackTraceAsString(null);
     }
 
     /**
      * Format the Throwable that is the cause of this Throwable.
+     *
      * @param packages The List of packages to be suppressed from the trace.
      * @return The formatted Throwable that caused this Throwable.
      */
-    public String getRootCauseStackTrace(final List<String> packages) {
+    public String getCauseStackTraceAsString(final List<String> packages) {
         final StringBuilder sb = new StringBuilder();
-        if (proxyCause != null) {
-            formatWrapper(sb, proxyCause);
+        if (this.causeProxy != null) {
+            this.formatWrapper(sb, this.causeProxy);
             sb.append("Wrapped by: ");
         }
-        sb.append(toString());
+        sb.append(this.toString());
         sb.append('\n');
-        formatElements(sb, 0, throwable.getStackTrace(), callerPackageData, packages);
+        this.formatElements(sb, 0, this.throwable.getStackTrace(), this.extendedStackTrace, packages);
         return sb.toString();
     }
 
     /**
-     * Formats the specified Throwable.
-     * @param sb StringBuilder to contain the formatted Throwable.
-     * @param cause The Throwable to format.
+     * Return the number of elements that are being omitted because they are common with the parent Throwable's stack trace.
+     *
+     * @return The number of elements omitted from the stack trace.
      */
-    public void formatWrapper(final StringBuilder sb, final ThrowableProxy cause) {
-        formatWrapper(sb, cause, null);
+    public int getCommonElementCount() {
+        return this.commonElementCount;
     }
 
     /**
-     * Formats the specified Throwable.
-     * @param sb StringBuilder to contain the formatted Throwable.
-     * @param cause The Throwable to format.
-     * @param packages The List of packages to be suppressed from the trace.
+     * Initialize the cache by resolving everything in the current stack trace via Reflection.getCallerClass or via the SecurityManager if
+     * either are available. These are the only Classes that can be trusted to be accurate.
+     *
+     * @return A Stack containing the current stack of Class objects.
      */
-    @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
-    public void formatWrapper(final StringBuilder sb, final ThrowableProxy cause, final List<String> packages) {
-        final Throwable caused = cause.getCause() != null ? cause.getCause().getThrowable() : null;
-        if (caused != null) {
-            formatWrapper(sb, cause.proxyCause);
-            sb.append("Wrapped by: ");
+    private Stack<Class<?>> getCurrentStack() {
+        if (ReflectiveCallerClassUtility.isSupported()) {
+            final Stack<Class<?>> classes = new Stack<Class<?>>();
+            int index = 1;
+            Class<?> clazz = ReflectiveCallerClassUtility.getCaller(index);
+            while (clazz != null) {
+                classes.push(clazz);
+                clazz = ReflectiveCallerClassUtility.getCaller(++index);
+            }
+            return classes;
+        } else if (SECURITY_MANAGER != null) {
+            final Class<?>[] array = SECURITY_MANAGER.getClasses();
+            final Stack<Class<?>> classes = new Stack<Class<?>>();
+            for (final Class<?> clazz : array) {
+                classes.push(clazz);
+            }
+            return classes;
         }
-        sb.append(cause).append('\n');
-        formatElements(sb, cause.commonElementCount, cause.getThrowable().getStackTrace(), cause.callerPackageData,
-            packages);
+        return new Stack<Class<?>>();
+    }
+
+    /**
+     * Gets the stack trace including packaging information.
+     *
+     * @return The stack trace including packaging information.
+     */
+    public ExtendedStackTraceElement[] getExtendedStackTrace() {
+        return this.extendedStackTrace;
     }
 
     /**
      * Format the stack trace including packaging information.
+     *
      * @return The formatted stack trace including packaging information.
      */
-    public String getExtendedStackTrace() {
-        return getExtendedStackTrace(null);
+    public String getExtendedStackTraceAsString() {
+        return this.getExtendedStackTraceAsString(null);
     }
 
     /**
      * Format the stack trace including packaging information.
+     *
      * @param packages List of packages to be suppressed from the trace.
      * @return The formatted stack trace including packaging information.
      */
-    public String getExtendedStackTrace(final List<String> packages) {
-        final StringBuilder sb = new StringBuilder(name);
-        final String msg = throwable.getMessage();
+    public String getExtendedStackTraceAsString(final List<String> packages) {
+        final StringBuilder sb = new StringBuilder(this.name);
+        final String msg = this.message;
         if (msg != null) {
-            sb.append(": ").append(throwable.getMessage());
+            sb.append(": ").append(msg);
         }
         sb.append('\n');
-        formatElements(sb, 0, throwable.getStackTrace(), callerPackageData, packages);
-        if (proxyCause != null) {
-            formatCause(sb, proxyCause, packages);
+        this.formatElements(sb, 0, this.throwable.getStackTrace(), this.extendedStackTrace, packages);
+        if (this.causeProxy != null) {
+            this.formatCause(sb, this.causeProxy, packages);
         }
         return sb.toString();
     }
 
+    public String getLocalizedMessage() {
+        return this.localizedMessage;
+    }
+
+    public String getMessage() {
+        return this.message;
+    }
+
+    /**
+     * Return the FQCN of the Throwable.
+     *
+     * @return The FQCN of the Throwable.
+     */
+    public String getName() {
+        return this.name;
+    }
+
+    public StackTraceElement[] getStackTrace() {
+        return this.throwable == null ? null : this.throwable.getStackTrace();
+    }
+
+    /**
+     * Gets proxies for suppressed exceptions.
+     *
+     * @return proxies for suppressed exceptions.
+     */
+    public ThrowableProxy[] getSuppressedProxies() {
+        return this.suppressedProxies;
+    }
+
     /**
      * Format the suppressed Throwables.
+     *
      * @return The formatted suppressed Throwables.
      */
     public String getSuppressedStackTrace() {
-        final ThrowableProxy[] suppressed = getSuppressed();
+        final ThrowableProxy[] suppressed = this.getSuppressedProxies();
         if (suppressed == null || suppressed.length == 0) {
-            return "";
+            return Strings.EMPTY;
         }
         final StringBuilder sb = new StringBuilder("Suppressed Stack Trace Elements:\n");
         for (final ThrowableProxy proxy : suppressed) {
-            sb.append(proxy.getExtendedStackTrace());
+            sb.append(proxy.getExtendedStackTraceAsString());
         }
         return sb.toString();
     }
 
-    @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
-    private void formatCause(final StringBuilder sb, final ThrowableProxy cause, final List<String> packages) {
-        sb.append("Caused by: ").append(cause).append('\n');
-        formatElements(sb, cause.commonElementCount, cause.getThrowable().getStackTrace(), cause.callerPackageData,
-            packages);
-        if (cause.getCause() != null) {
-            formatCause(sb, cause.proxyCause, packages);
-        }
-    }
-
-    private void formatElements(final StringBuilder sb, final int commonCount, final StackTraceElement[] causedTrace,
-                                final StackTracePackageElement[] packageData, final List<String> packages) {
-        if (packages == null || packages.size() == 0) {
-            for (int i = 0; i < packageData.length; ++i) {
-                formatEntry(causedTrace[i], packageData[i], sb);
-            }
-        } else {
-            int count = 0;
-            for (int i = 0; i < packageData.length; ++i) {
-                if (!isSuppressed(causedTrace[i], packages)) {
-                    if (count > 0) {
-                        if (count == 1) {
-                            sb.append("\t....\n");
-                        } else {
-                            sb.append("\t... suppressed ").append(count).append(" lines\n");
-                        }
-                        count = 0;
-                    }
-                    formatEntry(causedTrace[i], packageData[i], sb);
-                } else {
-                    ++count;
-                }
-            }
-            if (count > 0) {
-                if (count == 1) {
-                    sb.append("\t...\n");
-                } else {
-                    sb.append("\t... suppressed ").append(count).append(" lines\n");
-                }
-            }
-        }
-        if (commonCount != 0) {
-            sb.append("\t... ").append(commonCount).append(" more").append('\n');
-        }
+    /**
+     * The throwable or null if this object is deserialized from XML or JSON.
+     *
+     * @return The throwable or null if this object is deserialized from XML or JSON.
+     */
+    public Throwable getThrowable() {
+        return this.throwable;
     }
 
-    private void formatEntry(final StackTraceElement element, final StackTracePackageElement packageData,
-                             final StringBuilder sb) {
-        sb.append("\tat ");
-        sb.append(element);
-        sb.append(' ');
-        sb.append(packageData);
-        sb.append('\n');
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + (this.causeProxy == null ? 0 : this.causeProxy.hashCode());
+        result = prime * result + this.commonElementCount;
+        result = prime * result + (this.extendedStackTrace == null ? 0 : Arrays.hashCode(this.extendedStackTrace));
+        result = prime * result + (this.suppressedProxies == null ? 0 : Arrays.hashCode(this.suppressedProxies));
+        result = prime * result + (this.name == null ? 0 : this.name.hashCode());
+        return result;
     }
 
     private boolean isSuppressed(final StackTraceElement element, final List<String> packages) {
@@ -319,44 +469,92 @@ public class ThrowableProxy implements S
     }
 
     /**
-     * Initialize the cache by resolving everything in the current stack trace via Reflection.getCallerClass
-     * or via the SecurityManager if either are available. These are the only Classes that can be trusted
-     * to be accurate.
-     * @return A Deque containing the current stack of Class objects.
+     * Loads classes not located via Reflection.getCallerClass.
+     *
+     * @param lastLoader The ClassLoader that loaded the Class that called this Class.
+     * @param className The name of the Class.
+     * @return The Class object for the Class or null if it could not be located.
      */
-    private Stack<Class<?>> getCurrentStack() {
-        if (ReflectiveCallerClassUtility.isSupported()) {
-            final Stack<Class<?>> classes = new Stack<Class<?>>();
-            int index = 1;
-            Class<?> clazz = ReflectiveCallerClassUtility.getCaller(index);
-            while (clazz != null) {
-                classes.push(clazz);
-                clazz = ReflectiveCallerClassUtility.getCaller(++index);
+    private Class<?> loadClass(final ClassLoader lastLoader, final String className) {
+        // XXX: this is overly complicated
+        Class<?> clazz;
+        if (lastLoader != null) {
+            try {
+                clazz = Loader.initializeClass(className, lastLoader);
+                if (clazz != null) {
+                    return clazz;
+                }
+            } catch (final Exception ignore) {
+                // Ignore exception.
             }
-            return classes;
-        } else if (SECURITY_MANAGER != null) {
-            final Class<?>[] array = SECURITY_MANAGER.getClasses();
-            final Stack<Class<?>> classes = new Stack<Class<?>>();
-            for (final Class<?> clazz : array) {
-                classes.push(clazz);
+        }
+        try {
+            clazz = Loader.loadClass(className);
+        } catch (final ClassNotFoundException ignored) {
+            try {
+                clazz = Loader.initializeClass(className, this.getClass().getClassLoader());
+            } catch (final ClassNotFoundException ignore) {
+                return null;
             }
-            return classes;
         }
-        return new Stack<Class<?>>();
+        return clazz;
+    }
+
+    /**
+     * Construct the CacheEntry from the Class's information.
+     *
+     * @param stackTraceElement The stack trace element
+     * @param callerClass The Class.
+     * @param exact True if the class was obtained via Reflection.getCallerClass.
+     *
+     * @return The CacheEntry.
+     */
+    private CacheEntry resolvePackageElement(final StackTraceElement stackTraceElement, final Class<?> callerClass, final boolean exact) {
+        String location = "?";
+        String version = "?";
+        ClassLoader lastLoader = null;
+        if (callerClass != null) {
+            try {
+                final CodeSource source = callerClass.getProtectionDomain().getCodeSource();
+                if (source != null) {
+                    final URL locationURL = source.getLocation();
+                    if (locationURL != null) {
+                        final String str = locationURL.toString().replace('\\', '/');
+                        int index = str.lastIndexOf("/");
+                        if (index >= 0 && index == str.length() - 1) {
+                            index = str.lastIndexOf("/", index - 1);
+                            location = str.substring(index + 1);
+                        } else {
+                            location = str.substring(index + 1);
+                        }
+                    }
+                }
+            } catch (final Exception ex) {
+                // Ignore the exception.
+            }
+            final Package pkg = callerClass.getPackage();
+            if (pkg != null) {
+                final String ver = pkg.getImplementationVersion();
+                if (ver != null) {
+                    version = ver;
+                }
+            }
+            lastLoader = callerClass.getClassLoader();
+        }
+        return new CacheEntry(new ExtendedStackTraceElement(stackTraceElement, exact, location, version), lastLoader);
     }
 
     /**
      * Resolve all the stack entries in this stack trace that are not common with the parent.
+     *
      * @param stack The callers Class stack.
      * @param map The cache of CacheEntry objects.
      * @param rootTrace The first stack trace resolve or null.
      * @param stackTrace The stack trace being resolved.
      * @return The StackTracePackageElement array.
      */
-    StackTracePackageElement[] resolvePackageData(final Stack<Class<?>> stack, final Map<String,
-                                                          CacheEntry> map,
-                                                          final StackTraceElement[] rootTrace,
-                                                          final StackTraceElement[] stackTrace) {
+    ExtendedStackTraceElement[] toExtendedStackTrace(final Stack<Class<?>> stack, final Map<String, CacheEntry> map,
+            final StackTraceElement[] rootTrace, final StackTraceElement[] stackTrace) {
         int stackLength;
         if (rootTrace != null) {
             int rootIndex = rootTrace.length - 1;
@@ -365,22 +563,23 @@ public class ThrowableProxy implements S
                 --rootIndex;
                 --stackIndex;
             }
-            commonElementCount = stackTrace.length - 1 - stackIndex;
+            this.commonElementCount = stackTrace.length - 1 - stackIndex;
             stackLength = stackIndex + 1;
         } else {
-            commonElementCount = 0;
+            this.commonElementCount = 0;
             stackLength = stackTrace.length;
         }
-        final StackTracePackageElement[] packageArray = new StackTracePackageElement[stackLength];
+        final ExtendedStackTraceElement[] packageArray = new ExtendedStackTraceElement[stackLength];
         Class<?> clazz = stack.isEmpty() ? null : stack.peek();
         ClassLoader lastLoader = null;
         for (int i = stackLength - 1; i >= 0; --i) {
-            final String className = stackTrace[i].getClassName();
-            // The stack returned from getCurrentStack will be missing entries for  java.lang.reflect.Method.invoke()
+            final StackTraceElement stackTraceElement = stackTrace[i];
+            final String className = stackTraceElement.getClassName();
+            // The stack returned from getCurrentStack will be missing entries for java.lang.reflect.Method.invoke()
             // and its implementation. The Throwable might also contain stack entries that are no longer
             // present as those methods have returned.
             if (clazz != null && className.equals(clazz.getName())) {
-                final CacheEntry entry = resolvePackageElement(clazz, true);
+                final CacheEntry entry = this.resolvePackageElement(stackTraceElement, clazz, true);
                 packageArray[i] = entry.element;
                 lastLoader = entry.loader;
                 stack.pop();
@@ -393,7 +592,7 @@ public class ThrowableProxy implements S
                         lastLoader = entry.loader;
                     }
                 } else {
-                    final CacheEntry entry = resolvePackageElement(loadClass(lastLoader, className), false);
+                    final CacheEntry entry = this.resolvePackageElement(stackTraceElement, this.loadClass(lastLoader, className), false);
                     packageArray[i] = entry.element;
                     map.put(className, entry);
                     if (entry.loader != null) {
@@ -405,122 +604,26 @@ public class ThrowableProxy implements S
         return packageArray;
     }
 
-
-    /**
-     * Construct the CacheEntry from the Class's information.
-     * @param callerClass The Class.
-     * @param exact True if the class was obtained via Reflection.getCallerClass.
-     * @return The CacheEntry.
-     */
-    private CacheEntry resolvePackageElement(final Class<?> callerClass, final boolean exact) {
-        String location = "?";
-        String version = "?";
-        ClassLoader lastLoader = null;
-        if (callerClass != null) {
-            try {
-                final CodeSource source = callerClass.getProtectionDomain().getCodeSource();
-                if (source != null) {
-                    final URL locationURL = source.getLocation();
-                    if (locationURL != null) {
-                        final String str = locationURL.toString().replace('\\', '/');
-                        int index = str.lastIndexOf("/");
-                        if (index >= 0 && index == str.length() - 1) {
-                            index = str.lastIndexOf("/", index - 1);
-                            location = str.substring(index + 1);
-                        } else {
-                            location = str.substring(index + 1);
-                        }
-                    }
-                }
-            } catch (final Exception ex) {
-                // Ignore the exception.
-            }
-            final Package pkg = callerClass.getPackage();
-            if (pkg != null) {
-                final String ver = pkg.getImplementationVersion();
-                if (ver != null) {
-                    version = ver;
-                }
-            }
-            lastLoader = callerClass.getClassLoader();
-        }
-        return new CacheEntry(new StackTracePackageElement(location, version, exact), lastLoader);
+    @Override
+    public String toString() {
+        final String msg = this.message;
+        return msg != null ? this.name + ": " + msg : this.name;
     }
 
-    /**
-     * Loads classes not located via Reflection.getCallerClass.
-     * @param lastLoader The ClassLoader that loaded the Class that called this Class.
-     * @param className The name of the Class.
-     * @return The Class object for the Class or null if it could not be located.
-     */
-    private Class<?> loadClass(final ClassLoader lastLoader, final String className) {
-        // XXX: this is overly complicated
-        Class<?> clazz;
-        if (lastLoader != null) {
-            try {
-                clazz = Loader.initializeClass(className, lastLoader);
-                if (clazz != null) {
-                    return clazz;
-                }
-            } catch (final Exception ignore) {
-                // Ignore exception.
-            }
-        }
+    private ThrowableProxy[] toSuppressedProxies(final Throwable thrown) {
         try {
-            clazz = Loader.loadClass(className);
-        } catch (final ClassNotFoundException ignored) {
-            try {
-                clazz = Loader.initializeClass(className, getClass().getClassLoader());
-            } catch (final ClassNotFoundException ignore) {
-                return null;
-            }
-        }
-        return clazz;
-    }
-
-    public ThrowableProxy[] getSuppressed() {
-        if (GET_SUPPRESSED != null) {
-            try {
-                return (ThrowableProxy[]) GET_SUPPRESSED.invoke(throwable);
-            } catch (final Exception ignore) {
-                return null;
-            }
+            final Throwable[] suppressed = Throwables.getSuppressed(thrown);
+            if (suppressed == null) {
+                return EMPTY_THROWABLE_PROXY_ARRAY;
+            }
+            final ThrowableProxy[] proxies = new ThrowableProxy[suppressed.length];
+            for (int i = 0; i < suppressed.length; i++) {
+                proxies[i] = new ThrowableProxy(suppressed[i]);
+            }
+            return proxies;
+        } catch (final Exception e) {
+            StatusLogger.getLogger().error(e);
         }
         return null;
     }
-
-    private void setSuppressed(final Throwable throwable) {
-        if (GET_SUPPRESSED != null && ADD_SUPPRESSED != null) {
-            try {
-                final Throwable[] array = (Throwable[]) GET_SUPPRESSED.invoke(throwable);
-                for (final Throwable t : array) {
-                    ADD_SUPPRESSED.invoke(this, new ThrowableProxy(t));
-                }
-            } catch (final Exception ignore) {
-                //
-            }
-        }
-    }
-
-    /**
-     * Cached StackTracePackageElement and the ClassLoader.
-     */
-    class CacheEntry {
-        private final StackTracePackageElement element;
-        private final ClassLoader loader;
-
-        public CacheEntry(final StackTracePackageElement element, final ClassLoader loader) {
-            this.element = element;
-            this.loader = loader;
-        }
-    }
-
-    /**
-     * Security Manager for accessing the call stack.
-     */
-    private static class PrivateSecurityManager extends SecurityManager {
-        public Class<?>[] getClasses() {
-            return getClassContext();
-        }
-    }
 }

Modified: logging/log4j/log4j2/branches/experimental/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/AppenderAdmin.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/branches/experimental/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/AppenderAdmin.java?rev=1595653&r1=1595652&r2=1595653&view=diff
==============================================================================
--- logging/log4j/log4j2/branches/experimental/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/AppenderAdmin.java (original)
+++ logging/log4j/log4j2/branches/experimental/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/AppenderAdmin.java Sun May 18 18:40:48 2014
@@ -20,7 +20,7 @@ import javax.management.ObjectName;
 
 import org.apache.logging.log4j.core.Appender;
 import org.apache.logging.log4j.core.filter.AbstractFilterable;
-import org.apache.logging.log4j.core.helpers.Assert;
+import org.apache.logging.log4j.core.util.Assert;
 
 /**
  * Implementation of the {@code AppenderAdminMBean} interface.

Modified: logging/log4j/log4j2/branches/experimental/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/AsyncAppenderAdmin.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/branches/experimental/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/AsyncAppenderAdmin.java?rev=1595653&r1=1595652&r2=1595653&view=diff
==============================================================================
--- logging/log4j/log4j2/branches/experimental/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/AsyncAppenderAdmin.java (original)
+++ logging/log4j/log4j2/branches/experimental/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/AsyncAppenderAdmin.java Sun May 18 18:40:48 2014
@@ -19,7 +19,7 @@ package org.apache.logging.log4j.core.jm
 import javax.management.ObjectName;
 
 import org.apache.logging.log4j.core.appender.AsyncAppender;
-import org.apache.logging.log4j.core.helpers.Assert;
+import org.apache.logging.log4j.core.util.Assert;
 
 /**
  * Implementation of the {@code AsyncAppenderAdminMBean} interface.

Modified: logging/log4j/log4j2/branches/experimental/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/ContextSelectorAdmin.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/branches/experimental/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/ContextSelectorAdmin.java?rev=1595653&r1=1595652&r2=1595653&view=diff
==============================================================================
--- logging/log4j/log4j2/branches/experimental/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/ContextSelectorAdmin.java (original)
+++ logging/log4j/log4j2/branches/experimental/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/ContextSelectorAdmin.java Sun May 18 18:40:48 2014
@@ -18,8 +18,8 @@ package org.apache.logging.log4j.core.jm
 
 import javax.management.ObjectName;
 
-import org.apache.logging.log4j.core.helpers.Assert;
 import org.apache.logging.log4j.core.selector.ContextSelector;
+import org.apache.logging.log4j.core.util.Assert;
 
 /**
  * Implementation of the {@code ContextSelectorAdminMBean} interface.

Modified: logging/log4j/log4j2/branches/experimental/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/LoggerConfigAdmin.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/branches/experimental/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/LoggerConfigAdmin.java?rev=1595653&r1=1595652&r2=1595653&view=diff
==============================================================================
--- logging/log4j/log4j2/branches/experimental/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/LoggerConfigAdmin.java (original)
+++ logging/log4j/log4j2/branches/experimental/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/LoggerConfigAdmin.java Sun May 18 18:40:48 2014
@@ -17,12 +17,13 @@
 package org.apache.logging.log4j.core.jmx;
 
 import java.util.List;
+
 import javax.management.ObjectName;
 
 import org.apache.logging.log4j.Level;
 import org.apache.logging.log4j.core.config.AppenderRef;
 import org.apache.logging.log4j.core.config.LoggerConfig;
-import org.apache.logging.log4j.core.helpers.Assert;
+import org.apache.logging.log4j.core.util.Assert;
 
 /**
  * Implementation of the {@code LoggerConfigAdminMBean} interface.

Modified: logging/log4j/log4j2/branches/experimental/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/LoggerContextAdmin.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/branches/experimental/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/LoggerContextAdmin.java?rev=1595653&r1=1595652&r2=1595653&view=diff
==============================================================================
--- logging/log4j/log4j2/branches/experimental/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/LoggerContextAdmin.java (original)
+++ logging/log4j/log4j2/branches/experimental/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/LoggerContextAdmin.java Sun May 18 18:40:48 2014
@@ -42,11 +42,12 @@ import org.apache.logging.log4j.core.Log
 import org.apache.logging.log4j.core.config.Configuration;
 import org.apache.logging.log4j.core.config.ConfigurationFactory;
 import org.apache.logging.log4j.core.config.ConfigurationFactory.ConfigurationSource;
-import org.apache.logging.log4j.core.helpers.Assert;
-import org.apache.logging.log4j.core.helpers.Charsets;
-import org.apache.logging.log4j.core.helpers.Closer;
-import org.apache.logging.log4j.core.helpers.FileUtils;
+import org.apache.logging.log4j.core.util.Assert;
+import org.apache.logging.log4j.core.util.Charsets;
+import org.apache.logging.log4j.core.util.Closer;
+import org.apache.logging.log4j.core.util.FileUtils;
 import org.apache.logging.log4j.status.StatusLogger;
+import org.apache.logging.log4j.util.Strings;
 
 /**
  * Implementation of the {@code LoggerContextAdminMBean} interface.
@@ -113,7 +114,7 @@ public class LoggerContextAdmin extends 
         if (getConfigName() != null) {
             return String.valueOf(new File(getConfigName()).toURI());
         }
-        return "";
+        return Strings.EMPTY;
     }
 
     @Override

Modified: logging/log4j/log4j2/branches/experimental/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/RingBufferAdmin.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/branches/experimental/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/RingBufferAdmin.java?rev=1595653&r1=1595652&r2=1595653&view=diff
==============================================================================
--- logging/log4j/log4j2/branches/experimental/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/RingBufferAdmin.java (original)
+++ logging/log4j/log4j2/branches/experimental/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/RingBufferAdmin.java Sun May 18 18:40:48 2014
@@ -18,7 +18,7 @@ package org.apache.logging.log4j.core.jm
 
 import javax.management.ObjectName;
 
-import org.apache.logging.log4j.core.helpers.Assert;
+import org.apache.logging.log4j.core.util.Assert;
 
 import com.lmax.disruptor.RingBuffer;
 

Modified: logging/log4j/log4j2/branches/experimental/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/StatusLoggerAdmin.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/branches/experimental/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/StatusLoggerAdmin.java?rev=1595653&r1=1595652&r2=1595653&view=diff
==============================================================================
--- logging/log4j/log4j2/branches/experimental/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/StatusLoggerAdmin.java (original)
+++ logging/log4j/log4j2/branches/experimental/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/StatusLoggerAdmin.java Sun May 18 18:40:48 2014
@@ -16,6 +16,7 @@
  */
 package org.apache.logging.log4j.core.jmx;
 
+import java.io.IOException;
 import java.util.List;
 import java.util.concurrent.Executor;
 import java.util.concurrent.atomic.AtomicLong;
@@ -129,7 +130,7 @@ public class StatusLoggerAdmin extends N
      * Returns the {@code ObjectName} of this mbean.
      * 
      * @return the {@code ObjectName}
-     * @see StatusLoggerAdminMBean#NAME
+     * @see StatusLoggerAdminMBean#PATTERN
      */
     @Override
     public ObjectName getObjectName() {
@@ -143,4 +144,9 @@ public class StatusLoggerAdmin extends N
     private long now() {
         return System.currentTimeMillis();
     }
+
+    @Override
+    public void close() throws IOException {
+        // nothing to close here
+    }
 }

Modified: logging/log4j/log4j2/branches/experimental/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/AbstractStringLayout.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/branches/experimental/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/AbstractStringLayout.java?rev=1595653&r1=1595652&r2=1595653&view=diff
==============================================================================
--- logging/log4j/log4j2/branches/experimental/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/AbstractStringLayout.java (original)
+++ logging/log4j/log4j2/branches/experimental/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/AbstractStringLayout.java Sun May 18 18:40:48 2014
@@ -26,7 +26,7 @@ import org.apache.logging.log4j.core.Log
 public abstract class AbstractStringLayout extends AbstractLayout<String> {
 
     /**
-     * The charset of the formatted message.
+     * The charset for the formatted message.
      */
     private final Charset charset;
 

Modified: logging/log4j/log4j2/branches/experimental/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/HTMLLayout.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/branches/experimental/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/HTMLLayout.java?rev=1595653&r1=1595652&r2=1595653&view=diff
==============================================================================
--- logging/log4j/log4j2/branches/experimental/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/HTMLLayout.java (original)
+++ logging/log4j/log4j2/branches/experimental/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/HTMLLayout.java Sun May 18 18:40:48 2014
@@ -33,9 +33,9 @@ import org.apache.logging.log4j.core.Log
 import org.apache.logging.log4j.core.config.plugins.Plugin;
 import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
 import org.apache.logging.log4j.core.config.plugins.PluginFactory;
-import org.apache.logging.log4j.core.helpers.Charsets;
-import org.apache.logging.log4j.core.helpers.Constants;
-import org.apache.logging.log4j.core.helpers.Transform;
+import org.apache.logging.log4j.core.util.Charsets;
+import org.apache.logging.log4j.core.util.Constants;
+import org.apache.logging.log4j.core.util.Transform;
 
 /**
  * Outputs events as rows in an HTML table on an HTML page.
@@ -50,7 +50,7 @@ public final class HTMLLayout extends Ab
 
     private static final String TRACE_PREFIX = "<br />&nbsp;&nbsp;&nbsp;&nbsp;";
 
-    private static final String REGEXP = Constants.LINE_SEP.equals("\n") ? "\n" : Constants.LINE_SEP + "|\n";
+    private static final String REGEXP = Constants.LINE_SEPARATOR.equals("\n") ? "\n" : Constants.LINE_SEPARATOR + "|\n";
 
     private static final String DEFAULT_TITLE = "Log4j Log Messages";
 
@@ -119,16 +119,16 @@ public final class HTMLLayout extends Ab
     public String toSerializable(final LogEvent event) {
         final StringBuilder sbuf = new StringBuilder(BUF_SIZE);
 
-        sbuf.append(Constants.LINE_SEP).append("<tr>").append(Constants.LINE_SEP);
+        sbuf.append(Constants.LINE_SEPARATOR).append("<tr>").append(Constants.LINE_SEPARATOR);
 
         sbuf.append("<td>");
-        sbuf.append(event.getMillis() - jvmStartTime);
-        sbuf.append("</td>").append(Constants.LINE_SEP);
+        sbuf.append(event.getTimeMillis() - jvmStartTime);
+        sbuf.append("</td>").append(Constants.LINE_SEPARATOR);
 
         final String escapedThread = Transform.escapeHtmlTags(event.getThreadName());
         sbuf.append("<td title=\"").append(escapedThread).append(" thread\">");
         sbuf.append(escapedThread);
-        sbuf.append("</td>").append(Constants.LINE_SEP);
+        sbuf.append("</td>").append(Constants.LINE_SEPARATOR);
 
         sbuf.append("<td title=\"Level\">");
         if (event.getLevel().equals(Level.DEBUG)) {
@@ -142,7 +142,7 @@ public final class HTMLLayout extends Ab
         } else {
             sbuf.append(Transform.escapeHtmlTags(String.valueOf(event.getLevel())));
         }
-        sbuf.append("</td>").append(Constants.LINE_SEP);
+        sbuf.append("</td>").append(Constants.LINE_SEPARATOR);
 
         String escapedLogger = Transform.escapeHtmlTags(event.getLoggerName());
         if (escapedLogger.isEmpty()) {
@@ -150,7 +150,7 @@ public final class HTMLLayout extends Ab
         }
         sbuf.append("<td title=\"").append(escapedLogger).append(" logger\">");
         sbuf.append(escapedLogger);
-        sbuf.append("</td>").append(Constants.LINE_SEP);
+        sbuf.append("</td>").append(Constants.LINE_SEPARATOR);
 
         if (locationInfo) {
             final StackTraceElement element = event.getSource();
@@ -158,28 +158,28 @@ public final class HTMLLayout extends Ab
             sbuf.append(Transform.escapeHtmlTags(element.getFileName()));
             sbuf.append(':');
             sbuf.append(element.getLineNumber());
-            sbuf.append("</td>").append(Constants.LINE_SEP);
+            sbuf.append("</td>").append(Constants.LINE_SEPARATOR);
         }
 
         sbuf.append("<td title=\"Message\">");
         sbuf.append(Transform.escapeHtmlTags(event.getMessage().getFormattedMessage()).replaceAll(REGEXP, "<br />"));
-        sbuf.append("</td>").append(Constants.LINE_SEP);
-        sbuf.append("</tr>").append(Constants.LINE_SEP);
+        sbuf.append("</td>").append(Constants.LINE_SEPARATOR);
+        sbuf.append("</tr>").append(Constants.LINE_SEPARATOR);
 
-        if (event.getContextStack().getDepth() > 0) {
+        if (event.getContextStack() != null && !event.getContextStack().isEmpty()) {
             sbuf.append("<tr><td bgcolor=\"#EEEEEE\" style=\"font-size : ").append(fontSize);
             sbuf.append(";\" colspan=\"6\" ");
             sbuf.append("title=\"Nested Diagnostic Context\">");
             sbuf.append("NDC: ").append(Transform.escapeHtmlTags(event.getContextStack().toString()));
-            sbuf.append("</td></tr>").append(Constants.LINE_SEP);
+            sbuf.append("</td></tr>").append(Constants.LINE_SEPARATOR);
         }
 
-        if (event.getContextMap().size() > 0) {
+        if (event.getContextMap() != null && !event.getContextMap().isEmpty()) {
             sbuf.append("<tr><td bgcolor=\"#EEEEEE\" style=\"font-size : ").append(fontSize);
             sbuf.append(";\" colspan=\"6\" ");
             sbuf.append("title=\"Mapped Diagnostic Context\">");
             sbuf.append("MDC: ").append(Transform.escapeHtmlTags(event.getContextMap().toString()));
-            sbuf.append("</td></tr>").append(Constants.LINE_SEP);
+            sbuf.append("</td></tr>").append(Constants.LINE_SEPARATOR);
         }
 
         final Throwable throwable = event.getThrown();
@@ -187,7 +187,7 @@ public final class HTMLLayout extends Ab
             sbuf.append("<tr><td bgcolor=\"#993300\" style=\"color:White; font-size : ").append(fontSize);
             sbuf.append(";\" colspan=\"6\">");
             appendThrowableAsHTML(throwable, sbuf);
-            sbuf.append("</td></tr>").append(Constants.LINE_SEP);
+            sbuf.append("</td></tr>").append(Constants.LINE_SEPARATOR);
         }
 
         return sbuf.toString();
@@ -242,7 +242,7 @@ public final class HTMLLayout extends Ab
                 first = false;
             }
             sbuf.append(Transform.escapeHtmlTags(line));
-            sbuf.append(Constants.LINE_SEP);
+            sbuf.append(Constants.LINE_SEPARATOR);
         }
     }
 
@@ -255,36 +255,36 @@ public final class HTMLLayout extends Ab
         final StringBuilder sbuf = new StringBuilder();
         sbuf.append("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" ");
         sbuf.append("\"http://www.w3.org/TR/html4/loose.dtd\">");
-        sbuf.append(Constants.LINE_SEP);
-        sbuf.append("<html>").append(Constants.LINE_SEP);
-        sbuf.append("<head>").append(Constants.LINE_SEP);
-        sbuf.append("<meta charset=\"").append(getCharset()).append("\"/>").append(Constants.LINE_SEP);
-        sbuf.append("<title>").append(title).append("</title>").append(Constants.LINE_SEP);
-        sbuf.append("<style type=\"text/css\">").append(Constants.LINE_SEP);
-        sbuf.append("<!--").append(Constants.LINE_SEP);
+        sbuf.append(Constants.LINE_SEPARATOR);
+        sbuf.append("<html>").append(Constants.LINE_SEPARATOR);
+        sbuf.append("<head>").append(Constants.LINE_SEPARATOR);
+        sbuf.append("<meta charset=\"").append(getCharset()).append("\"/>").append(Constants.LINE_SEPARATOR);
+        sbuf.append("<title>").append(title).append("</title>").append(Constants.LINE_SEPARATOR);
+        sbuf.append("<style type=\"text/css\">").append(Constants.LINE_SEPARATOR);
+        sbuf.append("<!--").append(Constants.LINE_SEPARATOR);
         sbuf.append("body, table {font-family:").append(font).append("; font-size: ");
-        sbuf.append(headerSize).append(";}").append(Constants.LINE_SEP);
-        sbuf.append("th {background: #336699; color: #FFFFFF; text-align: left;}").append(Constants.LINE_SEP);
-        sbuf.append("-->").append(Constants.LINE_SEP);
-        sbuf.append("</style>").append(Constants.LINE_SEP);
-        sbuf.append("</head>").append(Constants.LINE_SEP);
-        sbuf.append("<body bgcolor=\"#FFFFFF\" topmargin=\"6\" leftmargin=\"6\">").append(Constants.LINE_SEP);
-        sbuf.append("<hr size=\"1\" noshade>").append(Constants.LINE_SEP);
-        sbuf.append("Log session start time " + new java.util.Date() + "<br>").append(Constants.LINE_SEP);
-        sbuf.append("<br>").append(Constants.LINE_SEP);
+        sbuf.append(headerSize).append(";}").append(Constants.LINE_SEPARATOR);
+        sbuf.append("th {background: #336699; color: #FFFFFF; text-align: left;}").append(Constants.LINE_SEPARATOR);
+        sbuf.append("-->").append(Constants.LINE_SEPARATOR);
+        sbuf.append("</style>").append(Constants.LINE_SEPARATOR);
+        sbuf.append("</head>").append(Constants.LINE_SEPARATOR);
+        sbuf.append("<body bgcolor=\"#FFFFFF\" topmargin=\"6\" leftmargin=\"6\">").append(Constants.LINE_SEPARATOR);
+        sbuf.append("<hr size=\"1\" noshade>").append(Constants.LINE_SEPARATOR);
+        sbuf.append("Log session start time " + new java.util.Date() + "<br>").append(Constants.LINE_SEPARATOR);
+        sbuf.append("<br>").append(Constants.LINE_SEPARATOR);
         sbuf.append(
             "<table cellspacing=\"0\" cellpadding=\"4\" border=\"1\" bordercolor=\"#224466\" width=\"100%\">");
-        sbuf.append(Constants.LINE_SEP);
-        sbuf.append("<tr>").append(Constants.LINE_SEP);
-        sbuf.append("<th>Time</th>").append(Constants.LINE_SEP);
-        sbuf.append("<th>Thread</th>").append(Constants.LINE_SEP);
-        sbuf.append("<th>Level</th>").append(Constants.LINE_SEP);
-        sbuf.append("<th>Logger</th>").append(Constants.LINE_SEP);
+        sbuf.append(Constants.LINE_SEPARATOR);
+        sbuf.append("<tr>").append(Constants.LINE_SEPARATOR);
+        sbuf.append("<th>Time</th>").append(Constants.LINE_SEPARATOR);
+        sbuf.append("<th>Thread</th>").append(Constants.LINE_SEPARATOR);
+        sbuf.append("<th>Level</th>").append(Constants.LINE_SEPARATOR);
+        sbuf.append("<th>Logger</th>").append(Constants.LINE_SEPARATOR);
         if (locationInfo) {
-            sbuf.append("<th>File:Line</th>").append(Constants.LINE_SEP);
+            sbuf.append("<th>File:Line</th>").append(Constants.LINE_SEPARATOR);
         }
-        sbuf.append("<th>Message</th>").append(Constants.LINE_SEP);
-        sbuf.append("</tr>").append(Constants.LINE_SEP);
+        sbuf.append("<th>Message</th>").append(Constants.LINE_SEPARATOR);
+        sbuf.append("</tr>").append(Constants.LINE_SEPARATOR);
         return sbuf.toString().getBytes(getCharset());
     }
 
@@ -295,8 +295,8 @@ public final class HTMLLayout extends Ab
     @Override
     public byte[] getFooter() {
         final StringBuilder sbuf = new StringBuilder();
-        sbuf.append("</table>").append(Constants.LINE_SEP);
-        sbuf.append("<br>").append(Constants.LINE_SEP);
+        sbuf.append("</table>").append(Constants.LINE_SEPARATOR);
+        sbuf.append("<br>").append(Constants.LINE_SEPARATOR);
         sbuf.append("</body></html>");
         return sbuf.toString().getBytes(getCharset());
     }