Mina log filter and reference count filter

MINA TCP simple communication example: http://donald-draper.iteye.com/blog/2375297
Mina filter chain default builder: http://donald-draper.iteye.com/blog/2375985
Mina filter definition: http: //donald-draper.iteye.com/blog/2376161Introduction
:
We took a look at the filter definition in the previous article, let's review it first:
     When IoFilter is added to the filter chain, it is generally wrapped in ReferenceCountingIoFilter and added to the filter chain. When the init method is added to the filter chain, it is called by ReferenceCountingIoFilter, so some shared resources can be initialized in the init method. If the filter is not wrapped as ReferenceCountingIoFilter, the init method will not be called. Then call onPreAdd to notify that the filter will be added to the filter chain. When the filter is added to the filter chain, all IoHandler events and IO requests will be intercepted by the filter. When the filter is added to the filter chain, it will be called onPostAdd, if there is an exception in the method, the filter is at the end of the filter chain, ReferenceCountingIoFilter will call the #destroy method to release the shared resources. The filter IoFilter mainly monitors IoSession related events (create, open, idle, exception, close, receive data, send data) and the Write and close events of IoSession; is to forward related events. WriteRequest is the wrapper of the session IoSession write operation write. There is a message object inside to store the write content, a socket address, which is the destination socket address of the session write request, and a write request result return value WriteFuture, which is used to obtain the session write message. Operation result. When a filter is removed from the filter chain, #onPreRemove is called to notify that the filter will be removed from the filter chain; if the filter is removed from the filter chain, all IoHandler events and IO requests, the filter does not Intercept again; #onPostRemove is called to notify that the filter has been removed from the filter chain; after removal, if the filter is at the end of the filter chain, ReferenceCountingIoFilter will call the #destroy method to release the shared resource.
        The IoFilter life cycle is as follows:
inti->onPreAdd->onPostAdd->(Intercept IoHandler related events: sessionCreated, Opened, Idle,
exceptionCaught, Closed, messageSent, messageReceived; Session related events: filterWrite, filterClose)->onPreRemove-
>onPostRemove->destroy.
Mina's log filter LoggingFilter used in this article on the TCP simple communication example is as follows:
//Configure the filter
DefaultIoFilterChainBuilder defaultIoFilterChainBuilder = acceptor.getFilterChain();
LoggingFilter loggingFilter = new LoggingFilter();
defaultIoFilterChainBuilder.addLast("loggingFilter", loggingFilter);

Today we take a look at LoggingFilter.
package org.apache.mina.filter;

import org.apache.mina.common.IdleStatus;
import org.apache.mina.common.IoFilterAdapter;
import org.apache.mina.common.IoSession;
import org.apache.mina.util.SessionLog;
import org.slf4j.Logger;

/**
 * Logs all MINA protocol events to {@link Logger}.
 *
 * @author The Apache Directory Project ([email protected])
 * @version $Rev$, $Date$
 *
 * @see SessionLog
 */
public class LoggingFilter extends IoFilterAdapter {
    /**
     * Session attribute key: prefix string
     */
    public static final String PREFIX = SessionLog.PREFIX;

    /**
     * Session attribute key: {@link Logger}
     */
    public static final String LOGGER = SessionLog.LOGGER;

    /**
     * Creates a new instance.
     */
    public LoggingFilter() {
    }
    //Intercept the sessionCreated event of IoHandler and delegate the log output to SessionLog,
    //Then pass related events to the filter successor, intercept sessionOpened, sessionClosed ideas are basically the same
    public void sessionCreated(NextFilter nextFilter, IoSession session) {
        SessionLog.info(session, "CREATED");
        nextFilter.sessionCreated(session);
    }
    public void sessionOpened(NextFilter nextFilter, IoSession session) {
        SessionLog.info(session, "OPENED");
        nextFilter.sessionOpened(session);
    }
    public void sessionClosed(NextFilter nextFilter, IoSession session) {
        SessionLog.info(session, "CLOSED");
        nextFilter.sessionClosed(session);
    }

    public void sessionIdle(NextFilter nextFilter, IoSession session,
            IdleStatus status) {
	//First determine whether the session log Info level is enabled
        if (SessionLog.isInfoEnabled(session)) {
            SessionLog.info(session, "IDLE: " + status);
        }
        nextFilter.sessionIdle(session, status);
    }

    public void exceptionCaught(NextFilter nextFilter, IoSession session,
            Throwable cause) {
        if (SessionLog.isWarnEnabled(session)) {
            SessionLog.warn(session, "EXCEPTION:", cause);
        }
        nextFilter.exceptionCaught(session, cause);
    }

    public void messageReceived(NextFilter nextFilter, IoSession session,
            Object message) {
        if (SessionLog.isInfoEnabled(session)) {
            SessionLog.info(session, "RECEIVED: " + message);
        }
        nextFilter.messageReceived(session, message);
    }

    public void messageSent(NextFilter nextFilter, IoSession session,
            Object message) {
        if (SessionLog.isInfoEnabled(session)) {
            SessionLog.info(session, "SENT: " + message);
        }
        nextFilter.messageSent(session, message);
    }

    public void filterWrite(NextFilter nextFilter, IoSession session,
            WriteRequest writeRequest) {
        if (SessionLog.isInfoEnabled(session)) {
            SessionLog.info(session, "WRITE: " + writeRequest);
        }
        nextFilter.filterWrite(session, writeRequest);
    }

    public void filterClose(NextFilter nextFilter, IoSession session)
            throws Exception {
        SessionLog.info(session, "CLOSE");
        nextFilter.filterClose(session);
    }
}

LoggingFilter intercepts the sessionCreated event of IoHandler, delegates log output to SessionLog,
and then passes related events to the filter successor, and intercepts sessionOpened, sessionClosed, and filterClose events. The idea is basically the same. For sessionIdle, messageSent, messageReceived, and filterWrite, first determine whether the info level of the session log is enabled, and output the corresponding event log if it is enabled. The log levels of the above events are all Info; exceptionCaught first determines whether the warn level of the session log is enabled, and outputs the corresponding event log if it is enabled.

Let's look at SessionLog again:
package org.apache.mina.util;

import org.apache.mina.common.IoSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
//From the package introduction, MINA uses the slf4j log component by default
/**
 * Provides utility methods to log protocol-specific messages.
 * <p>
 * Set {@link #PREFIX} and {@link #LOGGER} session attributes
 * to override prefix string and logger.
 *
 * @author The Apache Directory Project ([email protected])
 * @version $Rev$, $Date$
 *
 */
public class SessionLog {
    /**
     * Session attribute key: prefix string
     */
    public static final String PREFIX = SessionLog.class.getName() + ".prefix";

    /**
     * Session attribute key: {@link Logger}
     */
    public static final String LOGGER = SessionLog.class.getName() + ".logger";
    //Get the session IoHandler type
    private static Class getClass(IoSession session) {
        return session.getHandler().getClass();
    }
    //Debug output, if the session log is enabled with the debug level, the debug log is output
    public static void debug(IoSession session, String message) {
        Logger log = getLogger(session);
        if (log.isDebugEnabled()) {
            log.debug(String.valueOf(session.getAttribute(PREFIX)) + message);
        }
    }
    public static void debug(IoSession session, String message, Throwable cause) {
        Logger log = getLogger(session);
        if (log.isDebugEnabled()) {
            log.debug(String.valueOf(session.getAttribute(PREFIX)) + message,
                    cause);
        }
    }
    //get session log
      private static Logger getLogger(IoSession session) {
        Logger log = (Logger) session.getAttribute(LOGGER);
        if (log == null) {
	    //If the session log is empty, get the Logger from the LoggerFactory
            log = LoggerFactory.getLogger(getClass(session));
            String prefix = (String) session.getAttribute(PREFIX);
            if (prefix == null) {
                prefix = "[" + session.getRemoteAddress() + "] ";
                session.setAttribute(PREFIX, prefix);
            }
            //Add the log log to the session
            session.setAttribute(LOGGER, log);
        }

        return log;
    }
    / / Determine whether the debug level of the log is enabled
     public static boolean isDebugEnabled(IoSession session) {
        return getLogger(session).isDebugEnabled();
    }
    /* The following info, warn, error and debug ideas are the same
    */
    public static void info(IoSession session, String message) {
        Logger log = getLogger(session);
        if (log.isInfoEnabled()) {
            log.info(String.valueOf(session.getAttribute(PREFIX)) + message);
        }
    }
    public static void info(IoSession session, String message, Throwable cause) {
        Logger log = getLogger(session);
        if (log.isInfoEnabled()) {
            log.info(String.valueOf(session.getAttribute(PREFIX)) + message,
                    cause);
        }
    }
    public static void warn(IoSession session, String message) {
        Logger log = getLogger(session);
        if (log.isWarnEnabled()) {
            log.warn(String.valueOf(session.getAttribute(PREFIX)) + message);
        }
    }
    public static void warn(IoSession session, String message, Throwable cause) {
        Logger log = getLogger(session);
        if (log.isWarnEnabled()) {
            log.warn(String.valueOf(session.getAttribute(PREFIX)) + message,
                    cause);
        }
    }
    public static void error(IoSession session, String message) {
        Logger log = getLogger(session);
        if (log.isErrorEnabled()) {
            log.error(String.valueOf(session.getAttribute(PREFIX)) + message);
        }
    }
    public static void error(IoSession session, String message, Throwable cause) {
        Logger log = getLogger(session);
        if (log.isErrorEnabled()) {
            log.error(String.valueOf(session.getAttribute(PREFIX)) + message,
                    cause);
        }
    }
    public static boolean isInfoEnabled(IoSession session) {
        return getLogger(session).isInfoEnabled();
    }
    public static boolean isWarnEnabled(IoSession session) {
        return getLogger(session).isWarnEnabled();
    }
    public static boolean isErrorEnabled(IoSession session) {
        return getLogger(session).isErrorEnabled();
    }
}

In the article of TCP simple communication example, we have created a test filter TestFilter, which is added to the
filter :
TestFilter testFilter = new TestFilter();
ReferenceCountingFilter referenceCountingFilter = new ReferenceCountingFilter(testFilter);
defaultIoFilterChainBuilder.addLast("testFilter",referenceCountingFilter);

In the previous filter article, we also mentioned ReferenceCountingFilter, let's take a look at ReferenceCountingFilter
package org.apache.mina.filter;

import org.apache.mina.common.IdleStatus;
import org.apache.mina.common.IoFilter;
import org.apache.mina.common.IoFilterChain;
import org.apache.mina.common.IoSession;

/**
 * An {@link IoFilter}s wrapper that keeps track of the number of usages of this filter and will call init/destroy
 * when the filter is not in use.
 *ReferenceCountingIoFilter is used to wrap the filter to record the usage of the filter,
 When a filter is added to the filter chain, the filter's init method is called, and when it is removed from the filter chain, the filter's destroy method is called.
 * @author The Apache Directory Project ([email protected])
 * @version $Rev$, $Date$
 */
public class ReferenceCountingIoFilter implements IoFilter {
    private final IoFilter filter;//Packaged filter

    private int count = 0;//The filter uses the counter

    public ReferenceCountingIoFilter(IoFilter filter) {
        this.filter = filter;
    }
    public void init() throws Exception {
        // no-op, will init on-demand in pre-add if count == 0
    }
    public void destroy() throws Exception {
        //no-op, will destroy on-demand in post-remove if count == 0
    }
    public void onPostAdd(IoFilterChain parent, String name,
            NextFilter nextFilter) throws Exception {
        filter.onPostAdd(parent, name, nextFilter);
    }
    public synchronized void onPreAdd(IoFilterChain parent, String name,
            NextFilter nextFilter) throws Exception {
        if (0 == count) {
	    //When the filter is added to the filter chain for the first time, the init method of the filter is called.
            filter.init();
            ++count;
        }

        filter.onPreAdd(parent, name, nextFilter);
    }
    public void onPreRemove(IoFilterChain parent, String name,
            NextFilter nextFilter) throws Exception {
        filter.onPreRemove(parent, name, nextFilter);
    }
    public synchronized void onPostRemove(IoFilterChain parent, String name,
            NextFilter nextFilter) throws Exception {
        filter.onPostRemove(parent, name, nextFilter);
        --count;
	//When the filter is completely removed from the filter chain, call the filter's destroy method.
        if (0 == count) {
            filter.destroy();
        }
    }
    public void exceptionCaught(NextFilter nextFilter, IoSession session,
            Throwable cause) throws Exception {
        filter.exceptionCaught(nextFilter, session, cause);
    }
    public void filterClose(NextFilter nextFilter, IoSession session)
            throws Exception {
        filter.filterClose(nextFilter, session);
    }

    public void filterWrite(NextFilter nextFilter, IoSession session,
            WriteRequest writeRequest) throws Exception {
        filter.filterWrite(nextFilter, session, writeRequest);
    }

    public void messageReceived(NextFilter nextFilter, IoSession session,
            Object message) throws Exception {
        filter.messageReceived(nextFilter, session, message);
    }

    public void messageSent(NextFilter nextFilter, IoSession session,
            Object message) throws Exception {
        filter.messageSent(nextFilter, session, message);
    }
    public void sessionClosed(NextFilter nextFilter, IoSession session)
            throws Exception {
        filter.sessionClosed(nextFilter, session);
    }
    public void sessionCreated(NextFilter nextFilter, IoSession session)
            throws Exception {
        filter.sessionCreated(nextFilter, session);
    }
    public void sessionIdle(NextFilter nextFilter, IoSession session,
            IdleStatus status) throws Exception {
        filter.sessionIdle(nextFilter, session, status);
    }
    public void sessionOpened(NextFilter nextFilter, IoSession session)
            throws Exception {
        filter.sessionOpened(nextFilter, session);
    }
}

A filter can be added to the filter chain multiple times. How to ensure that when the filter is added to the filter chain for the first time, the filter is initialized, and when it is completely removed from the filter chain, the filter is destroyed and resources are released? This is the role of ReferenceCountingIoFilter. ReferenceCountingIoFilter is also a filter. An internal count is used to record the number of times the filter filter is added to the filter chain, that is, the number of filters in the filter chain. One filter, that is, the filter wrapped by ReferenceCountingIoFilter, The related events of IoHandler and IoSession are triggered, and they are directly handed over to the internal filter of the package for processing.


Summary:
     LoggingFilter intercepts the sessionCreated event of IoHandler, delegates log output to SessionLog, and then passes related events to the filter successor, and intercepts sessionOpened, sessionClosed, and
filterClose events. The idea is basically the same. For sessionIdle, messageSent, messageReceived, and
filterWrite, first determine whether the info level of the session log is enabled, and output the corresponding event log if it is enabled. The log levels of the above events are all Info; exceptionCaught first determines whether the warn level of the session log is enabled, and outputs the corresponding
event log if it is enabled.
     A filter can be added to the filter chain multiple times. ReferenceCountingIoFilter is used to ensure that when the filter is added to the filter chain for the first time, the filter is initialized, and when it is completely removed from the filter chain, the filter is destroyed and resources are released; ReferenceCountingIoFilter internal A count is used to record the number of times the packaging filter filter is added to the filter chain, that is, the number of filters in the filter chain, and a filter is the filter wrapped by ReferenceCountingIoFilter. ReferenceCountingIoFilter triggers IoHandler and IoSession related events, which are directly handed over to the packaging internal filter processing.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326448726&siteId=291194637