001/*
002 * Copyright 2002-2012 the original author or authors.
003 *
004 * Licensed under the Apache 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 *      https://www.apache.org/licenses/LICENSE-2.0
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 */
016
017package org.springframework.remoting.support;
018
019import java.lang.reflect.Method;
020
021import org.aopalliance.intercept.MethodInterceptor;
022import org.aopalliance.intercept.MethodInvocation;
023import org.apache.commons.logging.Log;
024import org.apache.commons.logging.LogFactory;
025
026import org.springframework.util.ClassUtils;
027
028/**
029 * AOP Alliance MethodInterceptor for tracing remote invocations.
030 * Automatically applied by RemoteExporter and its subclasses.
031 *
032 * <p>Logs an incoming remote call as well as the finished processing of a remote call
033 * at DEBUG level. If the processing of a remote call results in a checked exception,
034 * the exception will get logged at INFO level; if it results in an unchecked
035 * exception (or error), the exception will get logged at WARN level.
036 *
037 * <p>The logging of exceptions is particularly useful to save the stacktrace
038 * information on the server-side rather than just propagating the exception
039 * to the client (who might or might not log it properly).
040 *
041 * @author Juergen Hoeller
042 * @since 1.2
043 * @see RemoteExporter#setRegisterTraceInterceptor
044 * @see RemoteExporter#getProxyForService
045 */
046public class RemoteInvocationTraceInterceptor implements MethodInterceptor {
047
048        protected static final Log logger = LogFactory.getLog(RemoteInvocationTraceInterceptor.class);
049
050        private final String exporterNameClause;
051
052
053        /**
054         * Create a new RemoteInvocationTraceInterceptor.
055         */
056        public RemoteInvocationTraceInterceptor() {
057                this.exporterNameClause = "";
058        }
059
060        /**
061         * Create a new RemoteInvocationTraceInterceptor.
062         * @param exporterName the name of the remote exporter
063         * (to be used as context information in log messages)
064         */
065        public RemoteInvocationTraceInterceptor(String exporterName) {
066                this.exporterNameClause = exporterName + " ";
067        }
068
069
070        @Override
071        public Object invoke(MethodInvocation invocation) throws Throwable {
072                Method method = invocation.getMethod();
073                if (logger.isDebugEnabled()) {
074                        logger.debug("Incoming " + this.exporterNameClause + "remote call: " +
075                                        ClassUtils.getQualifiedMethodName(method));
076                }
077                try {
078                        Object retVal = invocation.proceed();
079                        if (logger.isDebugEnabled()) {
080                                logger.debug("Finished processing of " + this.exporterNameClause + "remote call: " +
081                                                ClassUtils.getQualifiedMethodName(method));
082                        }
083                        return retVal;
084                }
085                catch (Throwable ex) {
086                        if (ex instanceof RuntimeException || ex instanceof Error) {
087                                if (logger.isWarnEnabled()) {
088                                        logger.warn("Processing of " + this.exporterNameClause + "remote call resulted in fatal exception: " +
089                                                        ClassUtils.getQualifiedMethodName(method), ex);
090                                }
091                        }
092                        else {
093                                if (logger.isInfoEnabled()) {
094                                        logger.info("Processing of " + this.exporterNameClause + "remote call resulted in exception: " +
095                                                        ClassUtils.getQualifiedMethodName(method), ex);
096                                }
097                        }
098                        throw ex;
099                }
100        }
101
102}