    001    /*****************************************************************************
    002     * Copyright (C) PicoContainer Organization. All rights reserved.            *
    003     * ------------------------------------------------------------------------- *
    004     * The software in this package is published under the terms of the BSD      *
    005     * style license a copy of which has been included with this distribution in *
    006     * the LICENSE.txt file.                                                     *
    007     *                                                                           *
    008     * Original code by Paul Hammaant                                            *
    009     *****************************************************************************/
    010    package org.picocontainer.gems.monitors;
    011
    012    import static org.picocontainer.monitors.ComponentMonitorHelper.ctorToString;
    013    import static org.picocontainer.monitors.ComponentMonitorHelper.format;
    014    import static org.picocontainer.monitors.ComponentMonitorHelper.memberToString;
    015    import static org.picocontainer.monitors.ComponentMonitorHelper.methodToString;
    016    import static org.picocontainer.monitors.ComponentMonitorHelper.parmsToString;
    017
    018    import java.io.IOException;
    019    import java.io.ObjectInputStream;
    020    import java.io.ObjectOutputStream;
    021    import java.io.Serializable;
    022    import java.lang.reflect.Constructor;
    023    import java.lang.reflect.Member;
    024    import java.lang.reflect.Method;
    025
    026    import org.picocontainer.ComponentAdapter;
    027    import org.picocontainer.ComponentMonitor;
    028    import org.picocontainer.MutablePicoContainer;
    029    import org.picocontainer.PicoContainer;
    030    import org.picocontainer.Injector;
    031    import org.picocontainer.Behavior;
    032    import org.picocontainer.monitors.ComponentMonitorHelper;
    033    import org.picocontainer.monitors.NullComponentMonitor;
    034    import org.slf4j.Logger;
    035    import org.slf4j.LoggerFactory;
    036
    037    /**
    038     * A {@link org.picocontainer.ComponentMonitor} which writes to a Slf4j
    039     * {@link org.slf4j.Logger} instance. The Logger instance can either be injected
    040     * or, if not set, the {@link org.slf4j.LoggerFactory} will be used to retrieve
    041     * it at every invocation of the monitor.
    042     *
    043     * @author Paul Hammant
    044     * @author Mauro Talevi
    045     * @author Michael Rimov
    046     */
    047    @SuppressWarnings("serial")
    048    public class Slf4jComponentMonitor implements ComponentMonitor, Serializable {
    049
    050
    051            /**
    052             * Slf4j Logger.
    053             */
    054            private transient Logger logger;
    055
    056            /**
    057             * Delegate Monitor.
    058             */
    059            private final ComponentMonitor delegate;
    060
    061            /**
    062             * Creates a Slf4jComponentMonitor with no Logger instance set. The
    063             * {@link org.slf4j.LoggerFactory} will be used to retrieve the Logger
    064             * instance at every invocation of the monitor.
    065             */
    066            public Slf4jComponentMonitor() {
    067                    delegate = new NullComponentMonitor();
    068
    069            }
    070
    071            /**
    072             * Creates a Slf4jComponentMonitor with a given Logger instance class. The
    073             * class name is used to retrieve the Logger instance.
    074             *
    075             * @param loggerClass
    076             *            the class of the Logger
    077             */
    078            public Slf4jComponentMonitor(final Class<?> loggerClass) {
    079                    this(loggerClass.getName());
    080            }
    081
    082            /**
    083             * Creates a Slf4jComponentMonitor with a given Logger instance name. It
    084             * uses the {@link org.slf4j.LoggerFactory} to create the Logger instance.
    085             *
    086             * @param loggerName
    087             *            the name of the Log
    088             */
    089            public Slf4jComponentMonitor(final String loggerName) {
    090                    this(LoggerFactory.getLogger(loggerName));
    091            }
    092
    093            /**
    094             * Creates a Slf4jComponentMonitor with a given Logger instance
    095             *
    096             * @param logger
    097             *            the Logger to write to
    098             */
    099            public Slf4jComponentMonitor(final Logger logger) {
    100                    this();
    101                    this.logger = logger;
    102            }
    103
    104            /**
    105             * Creates a Slf4jComponentMonitor with a given Logger instance class. The
    106             * class name is used to retrieve the Logger instance.
    107             *
    108             * @param loggerClass
    109             *            the class of the Logger
    110             * @param delegate
    111             *            the delegate
    112             */
    113            public Slf4jComponentMonitor(final Class<?> loggerClass,
    114                            final ComponentMonitor delegate) {
    115                    this(loggerClass.getName(), delegate);
    116            }
    117
    118            /**
    119             * Creates a Slf4jComponentMonitor with a given Logger instance name. It
    120             * uses the {@link org.slf4j.LoggerFactory} to create the Logger instance.
    121             *
    122             * @param loggerName
    123             *            the name of the Log
    124             * @param delegate
    125             *            the delegate
    126             */
    127            public Slf4jComponentMonitor(final String loggerName,
    128                            final ComponentMonitor delegate) {
    129                    this(LoggerFactory.getLogger(loggerName), delegate);
    130            }
    131
    132            /**
    133             * Creates a Slf4jComponentMonitor with a given Slf4j Logger instance
    134             *
    135             * @param logger
    136             *            the Logger to write to
    137             * @param delegate
    138             *            the delegate
    139             */
    140            public Slf4jComponentMonitor(final Logger logger,
    141                            final ComponentMonitor delegate) {
    142                    this(delegate);
    143                    this.logger = logger;
    144            }
    145
    146            /**
    147             * Similar to default constructor behavior, but this version wraps a
    148             * delegate ComponentMonitor.
    149             *
    150             * @param delegate
    151             *            The next component monitor in the chain.
    152             */
    153            public Slf4jComponentMonitor(final ComponentMonitor delegate) {
    154                    this.delegate = delegate;
    155            }
    156
    157            /** {@inheritDoc} * */
    158            public <T> Constructor<T> instantiating(final PicoContainer container,
    159                            final ComponentAdapter<T> componentAdapter,
    160                            final Constructor<T> constructor) {
    161                    Logger logger = getLogger(constructor);
    162                    if (logger.isDebugEnabled()) {
    163                            logger.debug(format(ComponentMonitorHelper.INSTANTIATING,
    164                                            ctorToString(constructor)));
    165                    }
    166                    return delegate.instantiating(container, componentAdapter, constructor);
    167            }
    168
    169            /** {@inheritDoc} * */
    170            public <T> void instantiated(final PicoContainer container,
    171                            final ComponentAdapter<T> componentAdapter,
    172                            final Constructor<T> constructor, final Object instantiated,
    173                            final Object[] parameters, final long duration) {
    174                    Logger logger = getLogger(constructor);
    175                    if (logger.isDebugEnabled()) {
    176                            logger.debug(format(ComponentMonitorHelper.INSTANTIATED,
    177                                            ctorToString(constructor), duration, instantiated
    178                                                            .getClass().getName(), parmsToString(parameters)));
    179                    }
    180                    delegate.instantiated(container, componentAdapter, constructor,
    181                                    instantiated, parameters, duration);
    182            }
    183
    184            /** {@inheritDoc} * */
    185            public <T> void instantiationFailed(final PicoContainer container,
    186                            final ComponentAdapter<T> componentAdapter,
    187                            final Constructor<T> constructor, final Exception cause) {
    188                    Logger logger = getLogger(constructor);
    189                    if (logger.isWarnEnabled()) {
    190                            logger.warn(format(ComponentMonitorHelper.INSTANTIATION_FAILED,
    191                                            ctorToString(constructor), cause.getMessage()), cause);
    192                    }
    193                    delegate.instantiationFailed(container, componentAdapter, constructor,
    194                                    cause);
    195            }
    196
    197            /** {@inheritDoc} * */
    198            public void invoking(final PicoContainer container,
    199                            final ComponentAdapter<?> componentAdapter, final Member member,
    200                            final Object instance) {
    201                    Logger logger = getLogger(member);
    202                    if (logger.isDebugEnabled()) {
    203                            logger.debug(format(ComponentMonitorHelper.INVOKING,
    204                                            memberToString(member), instance));
    205                    }
    206                    delegate.invoking(container, componentAdapter, member, instance);
    207            }
    208
    209            /** {@inheritDoc} * */
    210            public void invoked(final PicoContainer container,
    211                            final ComponentAdapter<?> componentAdapter, final Method method,
    212                            final Object instance, final long duration) {
    213                    Logger logger = getLogger(method);
    214                    if (logger.isDebugEnabled()) {
    215                            logger.debug(format(ComponentMonitorHelper.INVOKED,
    216                                            methodToString(method), instance, duration));
    217                    }
    218                    delegate.invoked(container, componentAdapter, method, instance,
    219                                    duration);
    220            }
    221
    222            /** {@inheritDoc} * */
    223            public void invocationFailed(final Member member, final Object instance,
    224                            final Exception cause) {
    225                    Logger logger = getLogger(member);
    226                    if (logger.isWarnEnabled()) {
    227                            logger.warn(format(ComponentMonitorHelper.INVOCATION_FAILED,
    228                                            memberToString(member), instance, cause.getMessage()),
    229                                            cause);
    230                    }
    231                    delegate.invocationFailed(member, instance, cause);
    232            }
    233
    234            /** {@inheritDoc} * */
    235            public void lifecycleInvocationFailed(final MutablePicoContainer container,
    236                            final ComponentAdapter<?> componentAdapter, final Method method,
    237                            final Object instance, final RuntimeException cause) {
    238                    Logger logger = getLogger(method);
    239                    if (logger.isWarnEnabled()) {
    240                            logger.warn(format(
    241                                            ComponentMonitorHelper.LIFECYCLE_INVOCATION_FAILED,
    242                                            methodToString(method), instance, cause.getMessage()),
    243                                            cause);
    244                    }
    245                    delegate.lifecycleInvocationFailed(container, componentAdapter, method,
    246                                    instance, cause);
    247            }
    248
    249            /** {@inheritDoc} * */
    250            public Object noComponentFound(final MutablePicoContainer container,
    251                            final Object componentKey) {
    252                    Logger logger = this.logger != null ? this.logger : LoggerFactory
    253                                    .getLogger(ComponentMonitor.class);
    254                    if (logger.isWarnEnabled()) {
    255                            logger.warn(format(ComponentMonitorHelper.NO_COMPONENT,
    256                                            componentKey));
    257                    }
    258                    return delegate.noComponentFound(container, componentKey);
    259
    260            }
    261
    262            /** {@inheritDoc} */
    263            public Injector newInjector(
    264                            final Injector injector) {
    265                    return delegate.newInjector(injector);
    266            }
    267
    268        /** {@inheritDoc} **/
    269        public Behavior newBehavior(Behavior behavior) {
    270            return delegate.newBehavior(behavior);
    271        }
    272
    273
    274        /**
    275             * Retrieves the logger factory based class being instantiated.
    276             *
    277             * @param member
    278             *            Source method/constructor, etc being instantiated.
    279             * @return an appropriate logger instance for this callback.
    280             */
    281            protected Logger getLogger(final Member member) {
    282                    if (logger != null) {
    283                            return logger;
    284                    }
    285                    return LoggerFactory.getLogger(member.getDeclaringClass());
    286            }
    287
    288            /**
    289             * Serializes the monitor.
    290             *
    291             * @param oos
    292             *            object output stream.
    293             * @throws IOException
    294             */
    295            private void writeObject(final ObjectOutputStream oos) throws IOException {
    296                    oos.defaultWriteObject();
    297                    if (logger != null) {
    298                            oos.writeBoolean(true);
    299                            oos.writeUTF(logger.getName());
    300                    } else {
    301                            oos.writeBoolean(false);
    302                    }
    303            }
    304
    305            /**
    306             * Manually creates a new logger instance if it was defined earlier.
    307             *
    308             * @param ois
    309             * @throws IOException
    310             * @throws ClassNotFoundException
    311             */
    312            private void readObject(final ObjectInputStream ois) throws IOException,
    313                            ClassNotFoundException {
    314                    ois.defaultReadObject();
    315                    boolean hasDefaultLogger = ois.readBoolean();
    316                    if (hasDefaultLogger) {
    317                            String defaultLoggerCategory = ois.readUTF();
    318                            assert defaultLoggerCategory != null : "Serialization indicated default logger, "
    319                                            + "but no logger category found in input stream.";
    320                            logger = LoggerFactory.getLogger(defaultLoggerCategory);
    321                    }
    322            }
    323    }