001/**
002 * Copyright 2005-2015 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.rice.krad.devtools.util;
017
018import java.lang.reflect.Method;
019
020import org.aopalliance.intercept.MethodInterceptor;
021import org.aopalliance.intercept.MethodInvocation;
022import org.apache.commons.lang.StringUtils;
023import org.apache.logging.log4j.Logger;
024import org.apache.logging.log4j.LogManager;
025
026/**
027 * This interceptor generates log message before entering and after leaving the method being intercepted.
028 * 
029 * 
030 */
031public class MethodLoggingInterceptor implements MethodInterceptor {
032    private static final Logger LOG = LogManager.getLogger(MethodLoggingInterceptor.class);
033
034
035    /**
036     * Surrounds the method invocation with FATAL-level log messages. Using FATAL because I want to make sure that the log messages
037     * will always show up, since the correct way to deactivate method-level logging is to remove (or comment) the bean name from
038     * the KualiTestSpringLogging.xml file.
039     * 
040     * @see org.aopalliance.intercept.MethodInterceptor#invoke(org.aopalliance.intercept.MethodInvocation)
041     */
042    public Object invoke(MethodInvocation invocation) throws Throwable {
043        long startTime = System.currentTimeMillis();
044        Object methodResult = null;
045        String invocationLabel = buildInvocationLabel(invocation);
046        try {
047            LOG.fatal("entering " + invocationLabel);
048
049            methodResult = invocation.proceed();
050        }
051        catch (Exception invocationException) {
052            String exceptionLabel = buildExceptionLabel(invocationException);
053            LOG.fatal("aborting " + invocationLabel + ": throwing " + exceptionLabel);
054
055            throw invocationException;
056        }
057        LOG.fatal(new StringBuffer("leaving  ").append(invocationLabel).append(" / took ").append(System.currentTimeMillis() - startTime).append(" ms"));
058
059        return methodResult;
060    }
061
062    /**
063     * @param invocation MethodInvocation being labeled
064     * @return String used to identify this MethodInvocation
065     */
066    private String buildInvocationLabel(MethodInvocation invocation) {
067        StringBuffer invocationLabel = new StringBuffer();
068
069        Method method = invocation.getMethod();
070        Class targetClass = invocation.getThis().getClass();
071        Class declaringClass = method.getDeclaringClass();
072
073        // {targetClass} declaringClass.method
074        if (targetClass != declaringClass) {
075            invocationLabel.append("{");
076            invocationLabel.append(declaringClass.getName());
077            invocationLabel.append("} ");
078        }
079        invocationLabel.append(targetClass.getName() + "." + method.getName());
080
081
082        // (paramClass=argValue[,paramClass=argValue...])
083        Class[] paramTypes = method.getParameterTypes();
084        Object[] argValues = invocation.getArguments();
085
086        invocationLabel.append("(");
087        if (paramTypes != null) {
088            for (int i = 0; i < paramTypes.length; i++) {
089                if (i > 0) {
090                    invocationLabel.append(",");
091                }
092
093                invocationLabel.append(paramTypes[i].getName());
094                invocationLabel.append("=");
095
096                // differentiate between literal null and object whose toString returns null
097                if (argValues[i] == null) {
098                    invocationLabel.append("<literal null>");
099                }
100                else {
101                    invocationLabel.append(argValues[i]);
102                }
103            }
104        }
105        invocationLabel.append(")");
106
107        return invocationLabel.toString();
108    }
109
110
111    /**
112     * @param e Exception being labeled
113     * @return String used to identify this Exception
114     */
115    private String buildExceptionLabel(Exception e) {
116        String className = e.getClass().getName();
117
118        String exceptionLabel = StringUtils.substringAfterLast(className, ".");
119        if (StringUtils.isBlank(exceptionLabel)) {
120            exceptionLabel = className;
121        }
122
123        return exceptionLabel;
124    }
125}