package com.chamago.bison.logger.helper; import java.io.PrintStream; import java.util.HashMap; import java.util.Map; public final class MessageFormatter { static final char DELIM_START = '{'; static final char DELIM_STOP = '}'; static final String DELIM_STR = "{}"; private static final char ESCAPE_CHAR = '\\'; public static final FormattingTuple format(String messagePattern, Object arg) { return arrayFormat(messagePattern, new Object[] { arg }); } public static final FormattingTuple format(String messagePattern, Object arg1, Object arg2) { return arrayFormat(messagePattern, new Object[] { arg1, arg2 }); } static final Throwable getThrowableCandidate(Object[] argArray) { if ((argArray == null) || (argArray.length == 0)) { return null; } Object lastEntry = argArray[(argArray.length - 1)]; if ((lastEntry instanceof Throwable)) { return (Throwable)lastEntry; } return null; } public static final FormattingTuple arrayFormat(String messagePattern, 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; StringBuffer sbuf = new StringBuffer(messagePattern.length() + 50); for (int L = 0; L < argArray.length; L++) { int j = messagePattern.indexOf("{}", i); if (j == -1) { if (i == 0) { return new FormattingTuple(messagePattern, argArray, throwableCandidate); } sbuf.append(messagePattern.substring(i, messagePattern.length())); return new FormattingTuple(sbuf.toString(), argArray, throwableCandidate); } if (isEscapedDelimeter(messagePattern, j)) { if (!isDoubleEscaped(messagePattern, j)) { L--; sbuf.append(messagePattern.substring(i, j - 1)); sbuf.append('{'); i = j + 1; } else { sbuf.append(messagePattern.substring(i, j - 1)); deeplyAppendParameter(sbuf, argArray[L], new HashMap()); i = j + 2; } } else { sbuf.append(messagePattern.substring(i, j)); deeplyAppendParameter(sbuf, argArray[L], new HashMap()); i = j + 2; } } sbuf.append(messagePattern.substring(i, messagePattern.length())); if (i < argArray.length - 1) { return new FormattingTuple(sbuf.toString(), argArray, throwableCandidate); } return new FormattingTuple(sbuf.toString(), argArray, null); } static final boolean isEscapedDelimeter(String messagePattern, int delimeterStartIndex) { if (delimeterStartIndex == 0) { return false; } char potentialEscape = messagePattern.charAt(delimeterStartIndex - 1); return potentialEscape == '\\'; } static final boolean isDoubleEscaped(String messagePattern, int delimeterStartIndex) { return (delimeterStartIndex >= 2) && (messagePattern.charAt(delimeterStartIndex - 2) == '\\'); } private static void deeplyAppendParameter(StringBuffer sbuf, Object o, Map<Object[], Object> seenMap) { if (o == null) { sbuf.append("null"); return; } if (!o.getClass().isArray()) { safeObjectAppend(sbuf, o); } else if ((o instanceof boolean[])) booleanArrayAppend(sbuf, (boolean[])o); else if ((o instanceof byte[])) byteArrayAppend(sbuf, (byte[])o); else if ((o instanceof char[])) charArrayAppend(sbuf, (char[])o); else if ((o instanceof short[])) shortArrayAppend(sbuf, (short[])o); else if ((o instanceof int[])) intArrayAppend(sbuf, (int[])o); else if ((o instanceof long[])) longArrayAppend(sbuf, (long[])o); else if ((o instanceof float[])) floatArrayAppend(sbuf, (float[])o); else if ((o instanceof double[])) doubleArrayAppend(sbuf, (double[])o); else objectArrayAppend(sbuf, (Object[])o, seenMap); } private static void safeObjectAppend(StringBuffer sbuf, Object o) { try { String oAsString = o.toString(); sbuf.append(oAsString); } catch (Throwable t) { System.err.println("SLF4J: Failed toString() invocation on an object of type [" + o.getClass().getName() + "]"); t.printStackTrace(); sbuf.append("[FAILED toString()]"); } } private static void objectArrayAppend(StringBuffer sbuf, Object[] a, Map<Object[], Object> seenMap) { sbuf.append('['); if (!seenMap.containsKey(a)) { seenMap.put(a, null); int len = a.length; for (int i = 0; i < len; i++) { deeplyAppendParameter(sbuf, a[i], seenMap); if (i != len - 1) { sbuf.append(", "); } } seenMap.remove(a); } else { sbuf.append("..."); } sbuf.append(']'); } private static void booleanArrayAppend(StringBuffer sbuf, boolean[] a) { sbuf.append('['); int len = a.length; for (int i = 0; i < len; i++) { sbuf.append(a[i]); if (i != len - 1) sbuf.append(", "); } sbuf.append(']'); } private static void byteArrayAppend(StringBuffer sbuf, byte[] a) { sbuf.append('['); int len = a.length; for (int i = 0; i < len; i++) { sbuf.append(a[i]); if (i != len - 1) sbuf.append(", "); } sbuf.append(']'); } private static void charArrayAppend(StringBuffer sbuf, char[] a) { sbuf.append('['); int len = a.length; for (int i = 0; i < len; i++) { sbuf.append(a[i]); if (i != len - 1) sbuf.append(", "); } sbuf.append(']'); } private static void shortArrayAppend(StringBuffer sbuf, short[] a) { sbuf.append('['); int len = a.length; for (int i = 0; i < len; i++) { sbuf.append(a[i]); if (i != len - 1) sbuf.append(", "); } sbuf.append(']'); } private static void intArrayAppend(StringBuffer sbuf, int[] a) { sbuf.append('['); int len = a.length; for (int i = 0; i < len; i++) { sbuf.append(a[i]); if (i != len - 1) sbuf.append(", "); } sbuf.append(']'); } private static void longArrayAppend(StringBuffer sbuf, long[] a) { sbuf.append('['); int len = a.length; for (int i = 0; i < len; i++) { sbuf.append(a[i]); if (i != len - 1) sbuf.append(", "); } sbuf.append(']'); } private static void floatArrayAppend(StringBuffer sbuf, float[] a) { sbuf.append('['); int len = a.length; for (int i = 0; i < len; i++) { sbuf.append(a[i]); if (i != len - 1) sbuf.append(", "); } sbuf.append(']'); } private static void doubleArrayAppend(StringBuffer sbuf, double[] a) { sbuf.append('['); int len = a.length; for (int i = 0; i < len; i++) { sbuf.append(a[i]); if (i != len - 1) sbuf.append(", "); } sbuf.append(']'); } public static void main(String[] args) { FormattingTuple ft = format("Hello World {}", "chenzhurong"); System.out.println(ft.getMessage()); System.out.println(ft.getThrowable()); } }