001/**
002 * Copyright 2010-2013 The Kuali Foundation
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.kuali.common.util.log;
017
018import java.util.ArrayList;
019import java.util.List;
020import java.util.Properties;
021
022import org.apache.commons.lang3.StringUtils;
023import org.kuali.common.util.Assert;
024import org.kuali.common.util.CollectionUtils;
025import org.kuali.common.util.KeyValue;
026import org.kuali.common.util.nullify.NullUtils;
027import org.kuali.common.util.obscure.DefaultObscurer;
028import org.kuali.common.util.obscure.Obscurer;
029import org.kuali.common.util.property.Constants;
030import org.slf4j.Logger;
031import org.slf4j.LoggerFactory;
032import org.springframework.util.PropertyPlaceholderHelper;
033
034public class LoggerUtils {
035
036        public static final Logger LOGGER_UTILS_LOGGER = LoggerFactory.getLogger(LoggerUtils.class);
037        private static final Obscurer DEFAULT_OBSCURER = new DefaultObscurer();
038        private static final PropertyPlaceholderHelper HELPER = Constants.DEFAULT_PROPERTY_PLACEHOLDER_HELPER;
039
040        /**
041         * <p>
042         * Convenience method for obtaining a logger (borrowed from the JBoss crew)
043         * </p>
044         * 
045         * <pre>
046         * private static final Logger logger = LoggerUtils.make();
047         * </pre>
048         */
049        public static Logger make() {
050                Throwable throwable = new Throwable();
051                StackTraceElement[] elements = throwable.getStackTrace();
052                StackTraceElement directCaller = elements[1];
053                return LoggerFactory.getLogger(directCaller.getClassName());
054        }
055
056        public static String getLogMsg(List<String> includes, List<String> excludes) {
057                if (CollectionUtils.isEmpty(includes) && CollectionUtils.isEmpty(excludes)) {
058                        return "";
059                }
060                String includesCSV = StringUtils.trimToNull(CollectionUtils.getSpaceSeparatedCSV(includes));
061                String excludesCSV = StringUtils.trimToNull(CollectionUtils.getSpaceSeparatedCSV(excludes));
062                List<KeyValue> msgs = new ArrayList<KeyValue>();
063                if (!StringUtils.isBlank(includesCSV)) {
064                        msgs.add(new KeyValue("includes", includesCSV));
065                }
066                if (!StringUtils.isBlank(excludesCSV)) {
067                        msgs.add(new KeyValue("excludes", excludesCSV));
068                }
069                StringBuilder sb = new StringBuilder();
070                sb.append("[");
071                for (int i = 0; i < msgs.size(); i++) {
072                        if (i != 0) {
073                                sb.append("  ");
074                        }
075                        KeyValue msg = msgs.get(i);
076                        sb.append(msg.getKey());
077                        sb.append(": ");
078                        sb.append(msg.getValue());
079                }
080                sb.append("]");
081                return sb.toString();
082        }
083
084        @Deprecated
085        public static String getLogMsg(org.kuali.common.util.StringFilter filter) {
086                Assert.notNull(filter, "filter is null");
087                return getLogMsg(filter.getIncludes(), filter.getExcludes());
088        }
089
090        @Deprecated
091        public static Object[] getLogMsgArgs(org.kuali.common.util.StringFilter filter) {
092                Assert.notNull(filter, "filter is null");
093                String includes = CollectionUtils.getSpaceSeparatedCSV(filter.getIncludes());
094                String excludes = CollectionUtils.getSpaceSeparatedCSV(filter.getExcludes());
095                return new Object[] { includes, excludes };
096        }
097
098        public static void log(LogMsg msg, Logger logger) {
099                Assert.notNull(logger, "logger is null");
100                logMsg(msg.getMessage(), msg.getArgs(), logger, msg.getLevel());
101        }
102
103        public static int[] getPadding(List<String> columns, List<Object[]> argsList) {
104                int[] padding = new int[columns.size()];
105                for (int i = 0; i < padding.length; i++) {
106                        padding[i] = Math.max(padding[i], columns.get(i).length());
107                }
108                for (Object[] args : argsList) {
109                        Assert.isTrue(columns.size() == args.length, "Column count must equals args.length");
110                        for (int i = 0; i < args.length; i++) {
111                                padding[i] = Math.max(padding[i], args[i].toString().length());
112                        }
113                }
114                return padding;
115        }
116
117        public static String getHeader(List<String> columns, int[] padding, boolean leftAlign) {
118                StringBuilder sb = new StringBuilder();
119                for (int i = 0; i < columns.size(); i++) {
120                        if (i == 0) {
121                                sb.append("||  ");
122                        } else {
123                                sb.append("|  ");
124                        }
125                        if (leftAlign) {
126                                sb.append(StringUtils.rightPad(columns.get(i), padding[i]));
127                        } else {
128                                sb.append(StringUtils.leftPad(columns.get(i), padding[i]));
129                        }
130                        if (i == columns.size() - 1) {
131                                sb.append("  ||");
132                        } else {
133                                sb.append("  |");
134                        }
135                }
136                return sb.toString();
137        }
138
139        public static void updateArgsList(List<Object[]> argsList, int[] padding, boolean leftAlign) {
140                for (Object[] args : argsList) {
141                        for (int i = 0; i < args.length; i++) {
142                                if (leftAlign) {
143                                        args[i] = StringUtils.rightPad(args[i].toString(), padding[i]);
144                                } else {
145                                        args[i] = StringUtils.leftPad(args[i].toString(), padding[i]);
146                                }
147                        }
148                }
149        }
150
151        public static void logTable(List<String> columns, List<Object[]> rows, Logger logger) {
152                logTable(columns, rows, LogTableContext.DEFAULT_LOGGER_LEVEL, logger, false);
153        }
154
155        public static void logTable(List<String> columns, List<Object[]> rows, LoggerLevel level, Logger logger) {
156                logTable(columns, rows, level, logger, false);
157        }
158
159        public static void logTable(List<String> columns, List<Object[]> rows, LoggerLevel level, Logger logger, boolean leftAlign) {
160                LogTableContext context = new LogTableContext(columns, rows, level, logger, leftAlign);
161                logTable(context);
162        }
163
164        public static void logTable(String title, List<String> columns, List<Object[]> rows) {
165                LogTableContext context = new LogTableContext(title, columns, rows);
166                logTable(context);
167        }
168
169        public static void logTable(List<String> columns, List<Object[]> rows) {
170                LogTableContext context = new LogTableContext(columns, rows);
171                logTable(context);
172        }
173
174        public static String getTable(LogTableContext context) {
175                Assert.notNull(context, "context is null");
176                int[] padding = getPadding(context.getColumns(), context.getRows());
177                int cols = context.getColumns().size();
178                int rows = context.getRows().size();
179
180                String header = getHeader(context.getColumns(), padding, context.isLeftAlign());
181                updateArgsList(context.getRows(), padding, context.isLeftAlign());
182                Properties properties = getProperties(context.getRows());
183                String tableString = getTableString(rows, cols);
184
185                String resolved = HELPER.replacePlaceholders(tableString, properties);
186
187                return header + "\n" + resolved;
188        }
189
190        public static void logTable(LogTableContext context) {
191                String table = getTable(context);
192                int cols = context.getColumns().size();
193                int rows = context.getRows().size();
194                String defaultTitle = "Displaying a table with " + cols + " columns and " + rows + " rows\n\n";
195                String title = StringUtils.equals(LogTableContext.NO_TITLE, context.getTitle()) ? defaultTitle : context.getTitle() + "\n\n";
196                String msg = title + table;
197                logMsg(msg, context.getLogger(), context.getLevel());
198
199        }
200
201        protected static String getTableString(int rows, int cols) {
202                StringBuilder sb = new StringBuilder();
203                for (int row = 0; row < rows; row++) {
204                        for (int col = 0; col < cols; col++) {
205                                sb.append("${" + getPropertyKey(row, col) + "}");
206                        }
207                        sb.append("\n");
208                }
209                return sb.toString();
210        }
211
212        protected static Properties getProperties(List<Object[]> rows) {
213                Properties properties = new Properties();
214                for (int row = 0; row < rows.size(); row++) {
215                        Object[] rowData = rows.get(row);
216                        for (int col = 0; col < rowData.length; col++) {
217                                String key = getPropertyKey(row, col);
218                                StringBuilder sb = new StringBuilder();
219                                if (col == 0) {
220                                        sb.append("||  ");
221                                } else {
222                                        sb.append("|  ");
223                                }
224                                sb.append(rowData[col] + "");
225                                if (col == rowData.length - 1) {
226                                        sb.append("  ||");
227                                } else {
228                                        sb.append("  |");
229                                }
230                                properties.setProperty(key, sb.toString());
231                        }
232                }
233                return properties;
234        }
235
236        protected static String getPropertyKey(int row, int col) {
237                return "log.table.row." + row + ".col." + col;
238        }
239
240        public static void logLines(String s, Logger logger, LoggerLevel level) {
241                if (s == null) {
242                        return;
243                }
244                String[] lines = StringUtils.split(s, "\n");
245                for (String line : lines) {
246                        LoggerUtils.logMsg(line, logger, level);
247                }
248        }
249
250        public static final void logMsg(String msg, Object[] args, Logger logger, LoggerLevel level) {
251                if (StringUtils.equals(LogMsg.NO_MSG, msg)) {
252                        return;
253                }
254                switch (level) {
255                case DEBUG:
256                        logger.debug(msg, args);
257                        return;
258                case TRACE:
259                        logger.trace(msg, args);
260                        return;
261                case INFO:
262                        logger.info(msg, args);
263                        return;
264                case WARN:
265                        logger.warn(msg, args);
266                        return;
267                case ERROR:
268                        logger.error(msg, args);
269                        return;
270                default:
271                        throw new IllegalArgumentException("Logger level " + level + " is unknown");
272                }
273        }
274
275        public static final void logMsg(String msg, Logger logger, LoggerLevel level) {
276                logMsg(msg, null, logger, level);
277        }
278
279        public static final String getUsername(String username) {
280                return getNullAsNone(username);
281        }
282
283        public static final String getNullAsNone(String string) {
284                if (string == null) {
285                        return NullUtils.NONE;
286                } else {
287                        return string;
288                }
289        }
290
291        public static final String getPassword(String username, String password) {
292                return getPassword(username, password, DEFAULT_OBSCURER);
293        }
294
295        public static boolean isNullOrNone(String s) {
296                return NullUtils.isNullOrNone(s);
297        }
298
299        public static final String getPassword(String username, String password, Obscurer obscurer) {
300                if (isNullOrNone(password)) {
301                        // There is no password, return NONE
302                        return NullUtils.NONE;
303                } else if (StringUtils.equals(username, password)) {
304                        // Not exactly high security, display the clear text value
305                        return password;
306                } else {
307                        // Otherwise obscure it
308                        return obscurer.obscure(password);
309                }
310        }
311
312}