001package org.slf4j.helpers;
002
003import org.slf4j.event.LoggingEvent;
004
005/**
006 * Holds normalized calling call parameters.
007 * 
008 * Includes utility methods such as {@link #normalize(String, Object[], Throwable)} to help the normalization of parameters.
009 * 
010 * @author ceki
011 * @since 2.0
012 */
013public class NormalizedParameters {
014
015    final String message;
016    final Object[] arguments;
017    final Throwable throwable;
018
019    public NormalizedParameters(String message, Object[] arguments, Throwable throwable) {
020        this.message = message;
021        this.arguments = arguments;
022        this.throwable = throwable;
023    }
024
025    public NormalizedParameters(String message, Object[] arguments) {
026        this(message, arguments, null);
027    }
028
029    public String getMessage() {
030        return message;
031    }
032
033    public Object[] getArguments() {
034        return arguments;
035    }
036
037    public Throwable getThrowable() {
038        return throwable;
039    }
040
041    /**
042     * Helper method to determine if an {@link Object} array contains a
043     * {@link Throwable} as last element
044     *
045     * @param argArray The arguments off which we want to know if it contains a
046     *                 {@link Throwable} as last element
047     * @return if the last {@link Object} in argArray is a {@link Throwable} this
048     *         method will return it, otherwise it returns null
049     */
050    public static Throwable getThrowableCandidate(final Object[] argArray) {
051        if (argArray == null || argArray.length == 0) {
052            return null;
053        }
054
055        final Object lastEntry = argArray[argArray.length - 1];
056        if (lastEntry instanceof Throwable) {
057            return (Throwable) lastEntry;
058        }
059
060        return null;
061    }
062
063    /**
064     * Helper method to get all but the last element of an array
065     *
066     * @param argArray The arguments from which we want to remove the last element
067     *
068     * @return a copy of the array without the last element
069     */
070    public static Object[] trimmedCopy(final Object[] argArray) {
071        if (argArray == null || argArray.length == 0) {
072            throw new IllegalStateException("non-sensical empty or null argument array");
073        }
074
075        final int trimmedLen = argArray.length - 1;
076
077        Object[] trimmed = new Object[trimmedLen];
078
079        if (trimmedLen > 0) {
080            System.arraycopy(argArray, 0, trimmed, 0, trimmedLen);
081        }
082
083        return trimmed;
084    }
085
086    /**
087     * This method serves to normalize logging call invocation parameters.
088     * 
089     * More specifically, if a throwable argument is not supplied directly, it
090     * attempts to extract it from the argument array.
091     */
092    public static NormalizedParameters normalize(String msg, Object[] arguments, Throwable t) {
093
094        if (t != null) {
095            return new NormalizedParameters(msg, arguments, t);
096        }
097
098        if (arguments == null || arguments.length == 0) {
099            return new NormalizedParameters(msg, arguments, t);
100        }
101
102        Throwable throwableCandidate = NormalizedParameters.getThrowableCandidate(arguments);
103        if (throwableCandidate != null) {
104            Object[] trimmedArguments = MessageFormatter.trimmedCopy(arguments);
105            return new NormalizedParameters(msg, trimmedArguments, throwableCandidate);
106        } else {
107            return new NormalizedParameters(msg, arguments);
108        }
109
110    }
111
112    public static NormalizedParameters normalize(LoggingEvent event) {
113        return normalize(event.getMessage(), event.getArgumentArray(), event.getThrowable());
114    }
115
116}