    001    // Copyright 2006, 2007, 2008, 2011 The Apache Software Foundation
    002    //
    003    // Licensed under the Apache License, Version 2.0 (the "License");
    004    // you may not use this file except in compliance with the License.
    005    // You may obtain a copy of the License at
    006    //
    007    //     http://www.apache.org/licenses/LICENSE-2.0
    008    //
    009    // Unless required by applicable law or agreed to in writing, software
    010    // distributed under the License is distributed on an "AS IS" BASIS,
    011    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    012    // See the License for the specific language governing permissions and
    013    // limitations under the License.
    014
    015    package org.apache.tapestry5.ioc.internal.services;
    016
    017    import org.apache.tapestry5.ioc.services.ExceptionTracker;
    018    import org.apache.tapestry5.plastic.MethodInvocation;
    019    import org.slf4j.Logger;
    020
    021    import java.util.Iterator;
    022
    023    import static java.lang.String.format;
    024
    025    /**
    026     * Used by {@link org.apache.tapestry5.ioc.internal.services.LoggingDecoratorImpl} to delegate out logging behavior to a
    027     * separate object.
    028     */
    029    public final class MethodLogger
    030    {
    031        private static final int BUFFER_SIZE = 200;
    032
    033        private static final String ENTER = "ENTER";
    034
    035        private static final String EXIT = " EXIT";
    036
    037        private static final String FAIL = " FAIL";
    038
    039        private final Logger logger;
    040
    041        private final ExceptionTracker exceptionTracker;
    042
    043        public MethodLogger(Logger logger, ExceptionTracker exceptionTracker)
    044        {
    045            this.logger = logger;
    046            this.exceptionTracker = exceptionTracker;
    047        }
    048
    049        public boolean isDebugEnabled()
    050        {
    051            return logger.isDebugEnabled();
    052        }
    053
    054        /**
    055         * Invoked when a method is first entered
    056         *
    057         * @param invocation identifies method invoked as well as parameters passed to method
    058         */
    059        public void entry(MethodInvocation invocation)
    060        {
    061            StringBuilder buffer = new StringBuilder(BUFFER_SIZE);
    062
    063            buffer.append(format("[%s] %s(", ENTER, invocation.getMethod().getName()));
    064
    065            for (int i = 0; i < invocation.getMethod().getParameterTypes().length; i++)
    066            {
    067                if (i > 0) buffer.append(", ");
    068
    069                convert(buffer, invocation.getParameter(i));
    070            }
    071
    072            buffer.append(")");
    073
    074            logger.debug(buffer.toString());
    075        }
    076
    077        private void convert(StringBuilder buffer, Object object)
    078        {
    079            if (object == null)
    080            {
    081                buffer.append("null");
    082                return;
    083            }
    084
    085            // Minimal, alas: Doesn't handle embedded quotes and other
    086            // characters. Really want to convert the string back to what it
    087            // would look like as source code.
    088
    089            if (object instanceof String)
    090            {
    091                buffer.append("\"");
    092                buffer.append(object.toString());
    093                buffer.append("\"");
    094                return;
    095            }
    096
    097            if (object instanceof Object[])
    098            {
    099                Object[] values = (Object[]) object;
    100                buffer.append('{');
    101
    102                for (int i = 0; i < values.length; i++)
    103                {
    104                    if (i > 0) buffer.append(", ");
    105
    106                    convert(buffer, values[i]);
    107                }
    108
    109                buffer.append('}');
    110                return;
    111            }
    112
    113            if (object instanceof Iterable)
    114            {
    115                Iterable itr = (Iterable) object;
    116                boolean first = true;
    117
    118                buffer.append('[');
    119                Iterator i = itr.iterator();
    120                while (i.hasNext())
    121                {
    122                    if (!first) buffer.append(", ");
    123
    124                    convert(buffer, i.next());
    125                    first = false;
    126                }
    127                buffer.append(']');
    128                return;
    129            }
    130
    131            // Might need to add a few more, for things like character values ...
    132
    133            buffer.append(object.toString());
    134        }
    135
    136        /**
    137         * Invoked when a method exits (possibly returning a value).
    138         *
    139         * @param invocation identifies method invocation and  result value
    140         */
    141        public void exit(MethodInvocation invocation)
    142        {
    143            StringBuilder buffer = new StringBuilder(BUFFER_SIZE);
    144
    145            buffer.append(format("[%s] %s", EXIT, invocation.getMethod().getName()));
    146
    147            if (invocation.getMethod().getReturnType() != void.class)
    148            {
    149                buffer.append(" [");
    150                convert(buffer, invocation.getReturnValue());
    151                buffer.append(']');
    152            }
    153
    154            logger.debug(buffer.toString());
    155        }
    156
    157        /**
    158         * Invoked when method invocation instead throws an exception.
    159         *
    160         * @param invocation identifies method invocation which failed
    161         * @param t          exception throws by method invocation
    162         */
    163        public void fail(MethodInvocation invocation, Throwable t)
    164        {
    165            logger.debug(
    166                    format("[%s] %s -- %s", FAIL,
    167                            invocation.getMethod().getName(),
    168                            t.getClass().getName()),
    169                    exceptionTracker.exceptionLogged(t) ? null : t);
    170        }
    171    }