package org.server.log.appender;

import java.util.Iterator;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

import org.server.log.appender.disruptor.LogDisruptorEventHandle;
import org.server.log.appender.disruptor.LogValueEvent;

import ch.qos.logback.core.Appender;
import ch.qos.logback.core.UnsynchronizedAppenderBase;
import ch.qos.logback.core.spi.AppenderAttachable;
import ch.qos.logback.core.spi.AppenderAttachableImpl;

import com.lmax.disruptor.RingBuffer;
import com.lmax.disruptor.SleepingWaitStrategy;
import com.lmax.disruptor.dsl.Disruptor;
import com.lmax.disruptor.dsl.ProducerType;

/**
 * 
 * 自定义异步记录日志Appender.
 * 替换掉以前的BlockingQueue队列,改用Disruptor无锁内存队列.
 * @author 刘源
 */
public class DisruptorLogAppenderBase<E> extends UnsynchronizedAppenderBase<E>
		implements AppenderAttachable<E> {

	AppenderAttachableImpl<E> aai = new AppenderAttachableImpl<E>();
	RingBuffer<LogValueEvent> ringBuffer;
	/**
	 * The default buffer size.
	 */
	public static final int DEFAULT_QUEUE_SIZE = 1024;
	int queueSize = DEFAULT_QUEUE_SIZE;

	int appenderCount = 0;

	static final int UNDEFINED = -1;
	int discardingThreshold = UNDEFINED;

	/**
	 * Is the eventObject passed as parameter discardable? The base class's
	 * implementation of this method always returns 'false' but sub-classes may
	 * (and do) override this method.
	 * <p/>
	 * <p>
	 * Note that only if the buffer is nearly full are events discarded.
	 * Otherwise, when the buffer is "not full" all events are logged.
	 * 
	 * @param eventObject
	 * @return - true if the event can be discarded, false otherwise
	 */
	protected boolean isDiscardable(E eventObject) {
		return false;
	}

	/**
	 * Pre-process the event prior to queueing. The base class does no
	 * pre-processing but sub-classes can override this behavior.
	 * 
	 * @param eventObject
	 */
	protected void preprocess(E eventObject) {
	}

	@SuppressWarnings("unchecked")
	@Override
	public void start() {
		if (appenderCount == 0) {
			addError("No attached appenders found.");
			return;
		}
		if (queueSize < 1) {
			addError("Invalid queue size [" + queueSize + "]");
			return;
		}
		addInfo("环形缓冲区的大小: " + queueSize);
		Executor executor = Executors.newCachedThreadPool();
		Disruptor<LogValueEvent> disruptor = new Disruptor<LogValueEvent>(
				LogValueEvent.EVENT_FACTORY, queueSize, executor,
				ProducerType.MULTI, new SleepingWaitStrategy());
		disruptor.handleEventsWith(new LogDisruptorEventHandle());
		disruptor.start();
		ringBuffer = disruptor.getRingBuffer();
		super.start();
	}

	@Override
	public void stop() {
		if (!isStarted())
			return;
		// mark this appender as stopped so that Worker can also
		// processPriorToRemoval if it is invoking aii.appendLoopOnAppenders
		// and sub-appenders consume the interruption
		super.stop();
	}

	@Override
	protected void append(E eventObject) {
		preprocess(eventObject);
		put(eventObject);
	}
	
	protected void put(E eventObject) {
	}
	public int getQueueSize() {
		return queueSize;
	}

	public void setQueueSize(int queueSize) {
		this.queueSize = queueSize;
	}

	public int getDiscardingThreshold() {
		return discardingThreshold;
	}

	public void setDiscardingThreshold(int discardingThreshold) {
		this.discardingThreshold = discardingThreshold;
	}

	public void addAppender(Appender<E> newAppender) {
			appenderCount++;
			addInfo("Attaching appender named [" + newAppender.getName()
					+ "] to DisruptorLogAppender.");
			aai.addAppender(newAppender);
	}

	public Iterator<Appender<E>> iteratorForAppenders() {
		return aai.iteratorForAppenders();
	}

	public Appender<E> getAppender(String name) {
		return aai.getAppender(name);
	}

	public boolean isAttached(Appender<E> eAppender) {
		return aai.isAttached(eAppender);
	}

	public void detachAndStopAllAppenders() {
		aai.detachAndStopAllAppenders();
	}

	public boolean detachAppender(Appender<E> eAppender) {
		return aai.detachAppender(eAppender);
	}

	public boolean detachAppender(String name) {
		return aai.detachAppender(name);
	}
}