All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.firefly.server.http2.servlet.AsyncContextImpl Maven / Gradle / Ivy

There is a newer version: 4.0.3.2
Show newest version
package com.firefly.server.http2.servlet;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedTransferQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TransferQueue;

import javax.servlet.AsyncContext;
import javax.servlet.AsyncListener;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

import com.firefly.codec.http2.stream.HTTP2Configuration;
import com.firefly.utils.log.Log;
import com.firefly.utils.log.LogFactory;
import com.firefly.utils.time.HashTimeWheel;

public class AsyncContextImpl implements AsyncContext {

	private static Log log = LogFactory.getInstance().getLog("firefly-system");
	private static final HashTimeWheel TIME_WHEEL = new HashTimeWheel();

	private static ExecutorService executor;

	public static class AsyncContextTreadFactory implements ThreadFactory {

		@Override
		public Thread newThread(Runnable r) {
			return new Thread(r, "firefly asynchronous context thread");
		}

	}

	public static void init(HTTP2Configuration config) {
		executor = new ThreadPoolExecutor(config.getAsynchronousContextCorePoolSize(),
				config.getAsynchronousContextMaximumPoolSize(), config.getAsynchronousContextCorePoolKeepAliveTime(),
				TimeUnit.MILLISECONDS, new LinkedTransferQueue(), new AsyncContextTreadFactory());
	}

	public static void shutdown() {
		executor.shutdown();
		TIME_WHEEL.stop();
	}

	private long timeout = -1;
	private boolean originalRequestAndResponse = true;
	private volatile boolean startAsync = false;
	private volatile boolean complete = false;
	private ServletRequest request;
	private ServletResponse response;
	private final List listeners = new ArrayList();
	private final TransferQueue> threadFutureList = new LinkedTransferQueue>();
	private volatile HashTimeWheel.Future timeoutFuture;

	static {
		TIME_WHEEL.start();
	}

	public boolean isStartAsync() {
		return startAsync;
	}

	public void startAsync(ServletRequest request, ServletResponse response, boolean originalRequestAndResponse,
			long t) {
		this.request = request;
		this.response = response;
		this.originalRequestAndResponse = originalRequestAndResponse;
		setTimeout(t);

		fireOnStartAsync();
		startAsync = true;
		complete = false;
	}

	@Override
	public void complete() {
		if (complete)
			return;

		timeoutFuture.cancel();
		fireOnComplete();
		startAsync = false;
		complete = true;
	}

	@Override
	public ServletRequest getRequest() {
		return request;
	}

	@Override
	public ServletResponse getResponse() {
		return response;
	}

	@Override
	public boolean hasOriginalRequestAndResponse() {
		return originalRequestAndResponse;
	}

	@Override
	public void dispatch() {
		HttpServletRequest sr = (HttpServletRequest) getRequest();
		String path = sr.getRequestURI();
		dispatch(path);
	}

	@Override
	public void dispatch(String path) {
		dispatch(null, path);
	}

	@Override
	public void dispatch(ServletContext context, String path) {
		complete();
		try {
			request.getRequestDispatcher(path).forward(request, response);
		} catch (Throwable e) {
			log.error("async dispatch exception", e);
			fireOnError();
		}
	}

	@Override
	public void start(final Runnable runnable) {
		Future future = executor.submit(runnable);
		threadFutureList.offer(future);
	}

	@Override
	public void addListener(AsyncListener listener) {
		addListener(listener, request, response);
	}

	@Override
	public void addListener(AsyncListener listener, ServletRequest servletRequest, ServletResponse servletResponse) {
		AsyncListenerWrapper wrapper = new AsyncListenerWrapper(this, listener, servletRequest, servletResponse);
		listeners.add(wrapper);
	}

	private void fireOnStartAsync() {
		List listenersCopy = getListenersCopy();
		for (AsyncListenerWrapper listener : listenersCopy) {
			try {
				listener.fireOnStartAsync();
			} catch (IOException e) {
				log.error("async start event error", e);
				fireOnError();
			}
		}
	}

	private void fireOnComplete() {
		List listenersCopy = getListenersCopy();
		for (AsyncListenerWrapper listener : listenersCopy) {
			try {
				listener.fireOnComplete();
			} catch (IOException e) {
				log.error("async complete event error", e);
				fireOnError();
			}
		}
	}

	private void fireOnTimeout() {
		List listenersCopy = getListenersCopy();
		for (AsyncListenerWrapper listener : listenersCopy) {
			try {
				listener.fireOnTimeout();
			} catch (IOException e) {
				log.error("async timeout event error", e);
				fireOnError();
			}
		}
	}

	private void fireOnError() {
		List listenersCopy = getListenersCopy();
		for (AsyncListenerWrapper listener : listenersCopy) {
			try {
				listener.fireOnError();
			} catch (IOException e) {
				log.error("async error event exception", e);
			}
		}
	}

	private List getListenersCopy() {
		List listenersCopy = new ArrayList(listeners);
		return listenersCopy;
	}

	@Override
	public  T createListener(Class clazz) throws ServletException {
		T listener = null;
		try {
			listener = clazz.newInstance();
		} catch (Throwable e) {
			log.error("create async listener error", e);
		}
		return listener;
	}

	@Override
	public void setTimeout(long timeout) {
		this.timeout = timeout;

		if (timeout <= 0)
			return;

		if (timeoutFuture != null) {
			timeoutFuture.cancel();
		}

		timeoutFuture = TIME_WHEEL.add(timeout, new Runnable() {

			@Override
			public void run() {
				if (complete)
					return;

				Future f = null;
				while ((f = threadFutureList.poll()) != null) {
					if (!f.isDone() && !f.isCancelled()) {
						f.cancel(true);
					}
				}
				fireOnTimeout();
				startAsync = false;
				complete = false;
			}
		});
	}

	@Override
	public long getTimeout() {
		return timeout;
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy