Author: rgoers
Date: Fri Aug 10 07:02:22 2012
New Revision: 1371582

URL: http://svn.apache.org/viewvc?rev=1371582&view=rev
Log:
Add support for formatting using String.format()

Added:
    
logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/message/StringFormattedMessage.java
      - copied, changed from r1371500, 
logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/message/ParameterizedMessage.java
    
logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/Timer.java
      - copied, changed from r1371500, 
logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/Timer.java
    
logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/message/StringFormattedMessageTest.java
      - copied, changed from r1371500, 
logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/message/ParameterizedMessageTest.java
Modified:
    logging/log4j/log4j2/trunk/src/changes/changes.xml

Copied: 
logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/message/StringFormattedMessage.java
 (from r1371500, 
logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/message/ParameterizedMessage.java)
URL: 
http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/message/StringFormattedMessage.java?p2=logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/message/StringFormattedMessage.java&p1=logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/message/ParameterizedMessage.java&r1=1371500&r2=1371582&rev=1371582&view=diff
==============================================================================
--- 
logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/message/ParameterizedMessage.java
 (original)
+++ 
logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/message/StringFormattedMessage.java
 Fri Aug 10 07:02:22 2012
@@ -16,156 +16,43 @@
  */
 package org.apache.logging.log4j.message;
 
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.status.StatusLogger;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
 import java.io.Serializable;
-import java.text.SimpleDateFormat;
 import java.util.Arrays;
-import java.util.Collection;
-import java.util.Date;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
+import java.util.IllegalFormatException;
 
 /**
- * Handles messages that consist of a format string containing '{}' to 
represent each replaceable token, and
- * the parameters.
- * <p/>
- * This class was originally written for Lillith 
(http://mac.freshmeat.net/projects/lilith-viewer) by
- * Joern Huxhorn where it is licensed under the LGPL. It has been relicensed 
here with his permission
- * providing that this attribution remain.
+ * Handles messages that consist of a format string conforming to 
java.util.Formatter
  */
-public class ParameterizedMessage implements Message, Serializable {
+public class StringFormattedMessage implements Message, Serializable {
 
-    /**
-     * Prefix for recursion.
-     */
-    public static final String RECURSION_PREFIX = "[...";
-    /**
-     * Suffix for recursion.
-     */
-    public static final String RECURSION_SUFFIX = "...]";
-
-    /**
-     * Prefix for errors.
-     */
-    public static final String ERROR_PREFIX = "[!!!";
-    /**
-     * Separator for errors.
-     */
-    public static final String ERROR_SEPARATOR = "=>";
-    /**
-     * Separator for error messages.
-     */
-    public static final String ERROR_MSG_SEPARATOR = ":";
-    /**
-     * Suffix for errors.
-     */
-    public static final String ERROR_SUFFIX = "!!!]";
+    private static final Logger LOGGER = StatusLogger.getLogger();
 
     private static final long serialVersionUID = -665975803997290697L;
 
     private static final int HASHVAL = 31;
 
-    private static final char DELIM_START = '{';
-    private static final char DELIM_STOP = '}';
-    private static final char ESCAPE_CHAR = '\\';
-
     private String messagePattern;
-    private String[] stringArgs;
     private transient Object[] argArray;
+    private String[] stringArgs;
     private transient String formattedMessage;
-    private transient Throwable throwable;
 
     /**
-     * Create the ParameterizedMessage.
+     * Create the StringFormattedMessage.
      */
-    public ParameterizedMessage() {
+    public StringFormattedMessage() {
         this(null, null, null);
     }
 
-    /**
-     * Create the parameterizedMessage.
-     * @param messagePattern The message "format" string. This will be a 
String containing "{}" placeholders
-     * where parameters should be substituted.
-     * @param stringArgs The arguments for substitution.
-     * @param throwable A Throwable.
-     */
-    public ParameterizedMessage(String messagePattern, String[] stringArgs, 
Throwable throwable) {
-        this.messagePattern = messagePattern;
-        this.stringArgs = stringArgs;
-        this.throwable = throwable;
-    }
-
-    public ParameterizedMessage(String messagePattern, Object[] arguments, 
Throwable throwable) {
-        this.messagePattern = messagePattern;
-        this.throwable = throwable;
-        if (arguments != null) {
-            parseArguments(arguments);
-        }
-    }
 
-    /**
-     * <p>This method returns a ParameterizedMessage which contains the 
arguments converted to String
-     * as well as an optional Throwable.</p>
-     * <p/>
-     * <p>If the last argument is a Throwable and is NOT used up by a 
placeholder in the message pattern it is returned
-     * in ParameterizedMessage.getThrowable() and won't be contained in the 
created String[].<br/>
-     * If it is used up ParameterizedMessage.getThrowable() will return null 
even if the last argument was a
-     * Throwable!</p>
-     *
-     * @param messagePattern the message pattern that to be checked for 
placeholders.
-     * @param arguments      the argument array to be converted.
-     */
-    public ParameterizedMessage(String messagePattern, Object[] arguments) {
+    public StringFormattedMessage(String messagePattern, Object... arguments) {
         this.messagePattern = messagePattern;
-        if (arguments == null) {
-            return;
-        }
-        parseArguments(arguments);
-    }
-
-    /**
-     * Constructor with a pattern and a single parameter.
-     * @param messagePattern The message pattern.
-     * @param arg The parameter.
-     */
-    public ParameterizedMessage(String messagePattern, Object arg) {
-        this(messagePattern, new Object[]{arg});
-    }
-
-    /**
-     * Constructor with a pattern and two parameters.
-     * @param messagePattern The message pattern.
-     * @param arg1 The first parameter.
-     * @param arg2 The second parameter.
-     */
-    public ParameterizedMessage(String messagePattern, Object arg1, Object 
arg2) {
-        this(messagePattern, new Object[]{arg1, arg2});
-    }
-
-    private void parseArguments(Object[] arguments) {
-        int argsCount = countArgumentPlaceholders(messagePattern);
-        int resultArgCount = arguments.length;
-        if (argsCount < arguments.length) {
-            if (throwable == null && arguments[arguments.length - 1] 
instanceof Throwable) {
-                throwable = (Throwable) arguments[arguments.length - 1];
-                resultArgCount--;
-            }
-        }
-        argArray = new Object[resultArgCount];
-        for (int i = 0; i < resultArgCount; ++i) {
-            argArray[i] = arguments[i];
-        }
-
-        if (argsCount == 1 && throwable == null && arguments.length > 1) {
-            // special case
-            stringArgs = new String[1];
-            stringArgs[0] = deepToString(arguments);
-        } else {
-            stringArgs = new String[resultArgCount];
-            for (int i = 0; i < stringArgs.length; i++) {
-                stringArgs[i] = deepToString(arguments[i]);
-            }
-        }
+        this.argArray = arguments;
     }
 
     /**
@@ -174,7 +61,7 @@ public class ParameterizedMessage implem
      */
     public String getFormattedMessage() {
         if (formattedMessage == null) {
-            formattedMessage = formatMessage(messagePattern, stringArgs);
+            formattedMessage = formatMessage(messagePattern, argArray);
         }
         return formattedMessage;
     }
@@ -211,43 +98,18 @@ public class ParameterizedMessage implem
      * Sets the parameters for the message.
      * @param parameters The parameters.
      */
-    public void setParameters(String[] parameters) {
-        this.stringArgs = parameters;
-        this.formattedMessage = null;
-    }
-
-    /**
-     * Sets the parameters for the message.
-     * @param parameters The parameters.
-     */
     public void setParameters(Object[] parameters) {
-        parseArguments(parameters);
+        this.argArray = parameters;
         this.formattedMessage = null;
     }
 
-    /**
-     * Set the Throwable for the message.
-     * @param throwable The Throwable.
-     */
-    public void setThrowable(Throwable throwable) {
-        this.throwable = throwable;
-    }
-
-    /**
-     * Returns the Throwable that was given as the last argument, if any.
-     * It will not survive serialization. The Throwable exists as part of the 
message
-     * primarily so that it can be extracted from the end of the list of 
parameters
-     * and then be added to the LogEvent. As such, the Throwable in the event 
should
-     * not be used once the LogEvent has been constructed.
-     *
-     * @return the Throwable, if any.
-     */
-    public Throwable getThrowable() {
-        return throwable;
-    }
-
-    protected String formatMessage(String msgPattern, String[] sArgs) {
-        return format(msgPattern, sArgs);
+    protected String formatMessage(String msgPattern, Object... args) {
+        try {
+            return String.format(msgPattern, args);
+        } catch (IllegalFormatException ife) {
+            LOGGER.error("Unable to format msg: " + msgPattern, ife);
+            return msgPattern;
+        }
     }
 
     public boolean equals(Object o) {
@@ -258,7 +120,7 @@ public class ParameterizedMessage implem
             return false;
         }
 
-        ParameterizedMessage that = (ParameterizedMessage) o;
+        StringFormattedMessage that = (StringFormattedMessage) o;
 
         if (messagePattern != null ? 
!messagePattern.equals(that.messagePattern) : that.messagePattern != null) {
             return false;
@@ -266,7 +128,6 @@ public class ParameterizedMessage implem
         if (!Arrays.equals(stringArgs, that.stringArgs)) {
             return false;
         }
-        //if (throwable != null ? !throwable.equals(that.throwable) : 
that.throwable != null) return false;
 
         return true;
     }
@@ -277,306 +138,34 @@ public class ParameterizedMessage implem
         return result;
     }
 
-    /**
-     * Replace placeholders in the given messagePattern with arguments.
-     *
-     * @param messagePattern the message pattern containing placeholders.
-     * @param arguments      the arguments to be used to replace placeholders.
-     * @return the formatted message.
-     */
-    public static String format(String messagePattern, Object[] arguments) {
-        if (messagePattern == null || arguments == null || arguments.length == 
0) {
-            return messagePattern;
-        }
-
-        StringBuilder result = new StringBuilder();
-        int escapeCounter = 0;
-        int currentArgument = 0;
-        for (int i = 0; i < messagePattern.length(); i++) {
-            char curChar = messagePattern.charAt(i);
-            if (curChar == ESCAPE_CHAR) {
-                escapeCounter++;
-            } else {
-                if (curChar == DELIM_START) {
-                    if (i < messagePattern.length() - 1) {
-                        if (messagePattern.charAt(i + 1) == DELIM_STOP) {
-                            // write escaped escape chars
-                            int escapedEscapes = escapeCounter / 2;
-                            for (int j = 0; j < escapedEscapes; j++) {
-                                result.append(ESCAPE_CHAR);
-                            }
-
-                            if (escapeCounter % 2 == 1) {
-                                // i.e. escaped
-                                // write escaped escape chars
-                                result.append(DELIM_START);
-                                result.append(DELIM_STOP);
-                            } else {
-                                // unescaped
-                                if (currentArgument < arguments.length) {
-                                    result.append(arguments[currentArgument]);
-                                } else {
-                                    
result.append(DELIM_START).append(DELIM_STOP);
-                                }
-                                currentArgument++;
-                            }
-                            i++;
-                            escapeCounter = 0;
-                            continue;
-                        }
-                    }
-                }
-                // any other char beside ESCAPE or DELIM_START/STOP-combo
-                // write unescaped escape chars
-                if (escapeCounter > 0) {
-                    for (int j = 0; j < escapeCounter; j++) {
-                        result.append(ESCAPE_CHAR);
-                    }
-                    escapeCounter = 0;
-                }
-                result.append(curChar);
-            }
-        }
-        return result.toString();
-    }
-
-    /**
-     * Counts the number of unescaped placeholders in the given messagePattern.
-     *
-     * @param messagePattern the message pattern to be analyzed.
-     * @return the number of unescaped placeholders.
-     */
-    public static int countArgumentPlaceholders(String messagePattern) {
-        if (messagePattern == null) {
-            return 0;
-        }
-
-        int delim = messagePattern.indexOf(DELIM_START);
-
-        if (delim == -1) {
-            // special case, no placeholders at all.
-            return 0;
-        }
-        int result = 0;
-        boolean isEscaped = false;
-        for (int i = 0; i < messagePattern.length(); i++) {
-            char curChar = messagePattern.charAt(i);
-            if (curChar == ESCAPE_CHAR) {
-                isEscaped = !isEscaped;
-            } else if (curChar == DELIM_START) {
-                if (!isEscaped) {
-                    if (i < messagePattern.length() - 1) {
-                        if (messagePattern.charAt(i + 1) == DELIM_STOP) {
-                            result++;
-                            i++;
-                        }
-                    }
-                }
-                isEscaped = false;
-            } else {
-                isEscaped = false;
-            }
-        }
-        return result;
-    }
 
-    /**
-     * This method performs a deep toString of the given Object.
-     * Primitive arrays are converted using their respective Arrays.toString 
methods while
-     * special handling is implemented for "container types", i.e. Object[], 
Map and Collection because those could
-     * contain themselves.
-     * <p/>
-     * It should be noted that neither AbstractMap.toString() nor 
AbstractCollection.toString() implement such a
-     * behavior. They only check if the container is directly contained in 
itself, but not if a contained container
-     * contains the original one. Because of that, Arrays.toString(Object[]) 
isn't safe either.
-     * Confusing? Just read the last paragraph again and check the respective 
toString() implementation.
-     * <p/>
-     * This means, in effect, that logging would produce a usable output even 
if an ordinary System.out.println(o)
-     * would produce a relatively hard-to-debug StackOverflowError.
-     * @param o The object.
-     * @return The String representation.
-     */
-    public static String deepToString(Object o) {
-        if (o == null) {
-            return null;
-        }
-        if (o instanceof String) {
-            return (String) o;
-        }
-        StringBuilder str = new StringBuilder();
-        Set<String> dejaVu = new HashSet<String>(); // that's actually a neat 
name ;)
-        recursiveDeepToString(o, str, dejaVu);
-        return str.toString();
+    public String toString() {
+        return "StringFormatMessage[messagePattern=" + messagePattern + ", 
args=" +
+            Arrays.toString(argArray) +  "]";
     }
 
-    /**
-     * This method performs a deep toString of the given Object.
-     * Primitive arrays are converted using their respective Arrays.toString 
methods while
-     * special handling is implemented for "container types", i.e. Object[], 
Map and Collection because those could
-     * contain themselves.
-     * <p/>
-     * dejaVu is used in case of those container types to prevent an endless 
recursion.
-     * <p/>
-     * It should be noted that neither AbstractMap.toString() nor 
AbstractCollection.toString() implement such a
-     * behavior.
-     * They only check if the container is directly contained in itself, but 
not if a contained container contains the
-     * original one. Because of that, Arrays.toString(Object[]) isn't safe 
either.
-     * Confusing? Just read the last paragraph again and check the respective 
toString() implementation.
-     * <p/>
-     * This means, in effect, that logging would produce a usable output even 
if an ordinary System.out.println(o)
-     * would produce a relatively hard-to-debug StackOverflowError.
-     *
-     * @param o      the Object to convert into a String
-     * @param str    the StringBuilder that o will be appended to
-     * @param dejaVu a list of container identities that were already used.
-     */
-    private static void recursiveDeepToString(Object o, StringBuilder str, 
Set<String> dejaVu) {
-        if (o == null) {
-            str.append("null");
-            return;
-        }
-        if (o instanceof String) {
-            str.append(o);
-            return;
-        }
-
-        Class oClass = o.getClass();
-        if (oClass.isArray()) {
-            if (oClass == byte[].class) {
-                str.append(Arrays.toString((byte[]) o));
-            } else if (oClass == short[].class) {
-                str.append(Arrays.toString((short[]) o));
-            } else if (oClass == int[].class) {
-                str.append(Arrays.toString((int[]) o));
-            } else if (oClass == long[].class) {
-                str.append(Arrays.toString((long[]) o));
-            } else if (oClass == float[].class) {
-                str.append(Arrays.toString((float[]) o));
-            } else if (oClass == double[].class) {
-                str.append(Arrays.toString((double[]) o));
-            } else if (oClass == boolean[].class) {
-                str.append(Arrays.toString((boolean[]) o));
-            } else if (oClass == char[].class) {
-                str.append(Arrays.toString((char[]) o));
-            } else {
-                // special handling of container Object[]
-                String id = identityToString(o);
-                if (dejaVu.contains(id)) {
-                    
str.append(RECURSION_PREFIX).append(id).append(RECURSION_SUFFIX);
-                } else {
-                    dejaVu.add(id);
-                    Object[] oArray = (Object[]) o;
-                    str.append("[");
-                    boolean first = true;
-                    for (Object current : oArray) {
-                        if (first) {
-                            first = false;
-                        } else {
-                            str.append(", ");
-                        }
-                        recursiveDeepToString(current, str, new 
HashSet<String>(dejaVu));
-                    }
-                    str.append("]");
-                }
-                //str.append(Arrays.deepToString((Object[]) o));
-            }
-        } else if (o instanceof Map) {
-            // special handling of container Map
-            String id = identityToString(o);
-            if (dejaVu.contains(id)) {
-                
str.append(RECURSION_PREFIX).append(id).append(RECURSION_SUFFIX);
-            } else {
-                dejaVu.add(id);
-                Map oMap = (Map) o;
-                str.append("{");
-                boolean isFirst = true;
-                for (Object o1 : oMap.entrySet()) {
-                    Map.Entry current = (Map.Entry) o1;
-                    if (isFirst) {
-                        isFirst = false;
-                    } else {
-                        str.append(", ");
-                    }
-                    Object key = current.getKey();
-                    Object value = current.getValue();
-                    recursiveDeepToString(key, str, new 
HashSet<String>(dejaVu));
-                    str.append("=");
-                    recursiveDeepToString(value, str, new 
HashSet<String>(dejaVu));
-                }
-                str.append("}");
-            }
-        } else if (o instanceof Collection) {
-            // special handling of container Collection
-            String id = identityToString(o);
-            if (dejaVu.contains(id)) {
-                
str.append(RECURSION_PREFIX).append(id).append(RECURSION_SUFFIX);
-            } else {
-                dejaVu.add(id);
-                Collection oCol = (Collection) o;
-                str.append("[");
-                boolean isFirst = true;
-                for (Object anOCol : oCol) {
-                    if (isFirst) {
-                        isFirst = false;
-                    } else {
-                        str.append(", ");
-                    }
-                    recursiveDeepToString(anOCol, str, new 
HashSet<String>(dejaVu));
-                }
-                str.append("]");
-            }
-        } else if (o instanceof Date) {
-            Date date = (Date) o;
-            SimpleDateFormat format = new 
SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
-            // I'll leave it like this for the moment... this could probably 
be optimized using ThreadLocal...
-            str.append(format.format(date));
-        } else {
-            // it's just some other Object, we can only use toString().
-            try {
-                str.append(o.toString());
-            } catch (Throwable t) {
-                str.append(ERROR_PREFIX);
-                str.append(identityToString(o));
-                str.append(ERROR_SEPARATOR);
-                String msg = t.getMessage();
-                String className = t.getClass().getName();
-                str.append(className);
-                if (!className.equals(msg)) {
-                    str.append(ERROR_MSG_SEPARATOR);
-                    str.append(msg);
-                }
-                str.append(ERROR_SUFFIX);
-            }
+    private void writeObject(ObjectOutputStream out) throws IOException {
+        out.defaultWriteObject();
+        getFormattedMessage();
+        out.writeUTF(formattedMessage);
+        out.writeUTF(messagePattern);
+        out.writeInt(argArray.length);
+        stringArgs = new String[argArray.length];
+        int i = 0;
+        for (Object obj: argArray) {
+            stringArgs[i] = obj.toString();
+            ++i;
         }
     }
 
-    /**
-     * This method returns the same as if Object.toString() would not have been
-     * overridden in obj.
-     * <p/>
-     * Note that this isn't 100% secure as collisions can always happen with 
hash codes.
-     * <p/>
-     * Copied from Object.hashCode():
-     * As much as is reasonably practical, the hashCode method defined by
-     * class <tt>Object</tt> does return distinct integers for distinct
-     * objects. (This is typically implemented by converting the internal
-     * address of the object into an integer, but this implementation
-     * technique is not required by the
-     * Java<font size="-2"><sup>TM</sup></font>
-     * programming language.)
-     *
-     * @param obj the Object that is to be converted into an identity string.
-     * @return the identity string as also defined in Object.toString()
-     */
-    public static String identityToString(Object obj) {
-        if (obj == null) {
-            return null;
+    private void readObject(ObjectInputStream in) throws IOException, 
ClassNotFoundException {
+        in.defaultReadObject();
+        formattedMessage = in.readUTF();
+        messagePattern = in.readUTF();
+        int length = in.readInt();
+        stringArgs = new String[length];
+        for (int i=0; i < length; ++i) {
+            stringArgs[i] = in.readUTF();
         }
-        return obj.getClass().getName() + "@" + 
Integer.toHexString(System.identityHashCode(obj));
-    }
-
-    public String toString() {
-        return "ParameterizedMessage[messagePattern=" + messagePattern + ", 
stringArgs=" +
-            Arrays.toString(stringArgs) + ", throwable=" + throwable + "]";
     }
 }

Copied: 
logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/Timer.java
 (from r1371500, 
logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/Timer.java)
URL: 
http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/Timer.java?p2=logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/Timer.java&p1=logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/Timer.java&r1=1371500&r2=1371582&rev=1371582&view=diff
==============================================================================
--- 
logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/Timer.java
 (original)
+++ 
logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/Timer.java
 Fri Aug 10 07:02:22 2012
@@ -14,7 +14,7 @@
  * See the license for the specific language governing permissions and
  * limitations under the license.
  */
-package org.apache.logging.log4j.core;
+package org.apache.logging.log4j;
 
 import java.io.Serializable;
 import java.text.DecimalFormat;

Copied: 
logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/message/StringFormattedMessageTest.java
 (from r1371500, 
logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/message/ParameterizedMessageTest.java)
URL: 
http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/message/StringFormattedMessageTest.java?p2=logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/message/StringFormattedMessageTest.java&p1=logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/message/ParameterizedMessageTest.java&r1=1371500&r2=1371582&rev=1371582&view=diff
==============================================================================
--- 
logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/message/ParameterizedMessageTest.java
 (original)
+++ 
logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/message/StringFormattedMessageTest.java
 Fri Aug 10 07:02:22 2012
@@ -16,27 +16,82 @@
  */
 package org.apache.logging.log4j.message;
 
+import org.apache.logging.log4j.Timer;
+import org.junit.AfterClass;
 import org.junit.Test;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
 
 /**
  *
  */
-public class ParameterizedMessageTest {
+public class StringFormattedMessageTest {
+
+    private static final int LOOP_CNT = 500;
+    String[] array = new String[LOOP_CNT];
+    private static long stringTime = 0;
+    private static long paramTime = 0;
+
+    @AfterClass
+    public static void after() {
+        if (stringTime > paramTime) {
+            System.out.println(String.format("Parameterized is %1$.2f times 
faster than StringFormat.",
+                ((float) stringTime / paramTime)));
+        } else if (stringTime > paramTime) {
+            System.out.println(String.format("Parameterized is %1$.2f times 
slower than StringFormat.",
+                ((float) paramTime / stringTime)));
+        } else {
+            System.out.println("The speed of Parameterized and StringFormat 
are the same");
+        }
+    }
 
     @Test
     public void testNoArgs() {
-        String testMsg = "Test message {}";
-        ParameterizedMessage msg = new ParameterizedMessage(testMsg, null);
+        String testMsg = "Test message %1s";
+        StringFormattedMessage msg = new StringFormattedMessage(testMsg, null);
         String result = msg.getFormattedMessage();
-        assertEquals(testMsg, result);
+        String expected = "Test message null";
+        assertEquals(expected, result);
         Object[] array = null;
-        msg = new ParameterizedMessage(testMsg, array, null);
+        msg = new StringFormattedMessage(testMsg, array, null);
         result = msg.getFormattedMessage();
-        assertEquals(testMsg, result);
+        assertEquals(expected, result);
+    }
+
+    @Test
+    public void testOneArg() {
+        String testMsg = "Test message %1s";
+        StringFormattedMessage msg = new StringFormattedMessage(testMsg, 
"Apache");
+        String result = msg.getFormattedMessage();
+        String expected = "Test message Apache";
+        assertEquals(expected, result);
+    }
+
+    @Test
+    public void testStringPerf() {
+        String testMsg = "Test message %1s %2s";
+        Timer timer = new Timer("StringFormat", LOOP_CNT);
+        timer.start();
+        for (int i = 0; i < LOOP_CNT; ++i) {
+            StringFormattedMessage msg = new StringFormattedMessage(testMsg, 
"Apache", "Log4j");
+            array[i] = msg.getFormattedMessage();
+        }
+        timer.stop();
+        stringTime = timer.getElapsedNanoTime();
+        System.out.println(timer.toString());
+    }
+
+    @Test
+    public void testParameterizedPerf() {
+        String testMsg = "Test message {} {}";
+        Timer timer = new Timer("Parameterized", LOOP_CNT);
+        timer.start();
+        for (int i = 0; i < LOOP_CNT; ++i) {
+            ParameterizedMessage msg = new ParameterizedMessage(testMsg, 
"Apache", "Log4j");
+            array[i] = msg.getFormattedMessage();
+        }
+        timer.stop();
+        paramTime = timer.getElapsedNanoTime();
+        System.out.println(timer.toString());
     }
 }

Modified: logging/log4j/log4j2/trunk/src/changes/changes.xml
URL: 
http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/src/changes/changes.xml?rev=1371582&r1=1371581&r2=1371582&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/src/changes/changes.xml (original)
+++ logging/log4j/log4j2/trunk/src/changes/changes.xml Fri Aug 10 07:02:22 2012
@@ -23,6 +23,9 @@
 
   <body>
     <release version="2.0-alpha2" date="TBD" description="Bug fixes and minor 
enhancements">
+      <action dev="rgoers" type="add">
+        Add support for formatting using String.format().
+      </action>
       <action issue="LOG4J2-67" dev="rgoers" type="add">
         Allow components besides core to create a PluginMap for faster plugin 
loading and not
         having to specify the plugin package in the configuration.


Reply via email to