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

gu.sql2java.ListenerContainer Maven / Gradle / Ivy

There is a newer version: 5.3.3
Show newest version
package gu.sql2java;

import java.util.LinkedHashSet;
import java.util.LinkedList;

import com.google.common.collect.ImmutableList;

import gu.sql2java.exception.RuntimeDaoException;

import static com.google.common.base.Preconditions.*;
import static gu.sql2java.SimpleLog.*;

/** 
 * container for multiple listener management
 * @author guyadong 
 */
class ListenerContainer  implements TableListener {
	private final LinkedHashSet> listeners = new LinkedHashSet>(16);

	static final TransactionListenerImpl TRANSACTION_LISTENER = new TransactionListenerImpl();
	public ListenerContainer() {
	}

	@Override
	public void beforeInsert(B bean)throws RuntimeDaoException{
		synchronized (listeners) {
			for(TableListener listener:listeners){
				try{
					listener.beforeInsert(bean);
				}catch(Exception e){
					log("beforeInsert listener %s error:%s",listener.getClass().getName(),e.getMessage());
					if(BaseTableManager.isDebug()){
						log(e);
					}
				}
			}
		}
	}

	@Override
	public void afterInsert(final B bean)throws RuntimeDaoException{
		synchronized (listeners) {
			for(final TableListener listener:listeners){
				TRANSACTION_LISTENER.runCommitTask(new Runnable() {

					@Override
					public void run() {
						try{
							listener.afterInsert(bean);
						}catch(Exception e){
							log("afterInsert listener %s error:%s",listener.getClass().getName(),e.getMessage());
							if(BaseTableManager.isDebug()){
								log(e);
							}
						}
					}
				});
			}
		}
	}

	@Override
	public void beforeUpdate(B bean)throws RuntimeDaoException{
		synchronized (listeners) {
			for(TableListener listener:listeners){
				try{
					listener.beforeUpdate(bean);
				}catch(Exception e){
					log("beforeUpdate listener %s error:%s",listener.getClass().getName(),e.getMessage());
					if(BaseTableManager.isDebug()){
						log(e);
					}
				}
			}
		}
	}

	@Override
	public void afterUpdate(final B bean)throws RuntimeDaoException{
		synchronized (listeners) {
			for(final TableListener listener:listeners){
				TRANSACTION_LISTENER.runCommitTask(new Runnable() {

					@Override
					public void run() {
						try{
							listener.afterUpdate(bean);
						}catch(Exception e){
							log("afterUpdate listener %s error:%s",listener.getClass().getName(),e.getMessage());
							if(BaseTableManager.isDebug()){
								log(e);
							}
						}
					}
				});
			}
		}
	}

	@Override
	public void beforeDelete(B bean)throws RuntimeDaoException{
		synchronized (listeners) {
			for(TableListener listener:listeners){
				try{
					listener.beforeDelete(bean);
				}catch(Exception e){
					log("beforeDelete listener %s error:%s",listener.getClass().getName(),e.getMessage());
					if(BaseTableManager.isDebug()){
						log(e);
					}
				}
			}
		}
	}

	@Override
	public void afterDelete(final B bean)throws RuntimeDaoException{
		synchronized (listeners) {
			for(final TableListener listener:listeners){
				TRANSACTION_LISTENER.runCommitTask(new Runnable() {

					@Override
					public void run() {
						try{
							listener.afterDelete(bean);
						}catch(Exception e){
							log("afterDelete listener %s error:%s",listener.getClass().getName(),e.getMessage());
							if(BaseTableManager.isDebug()){
								log(e);
							}
						}
					}
				});

			}
		}
	}

	@Override
	public void done()throws RuntimeDaoException{
		synchronized (listeners) {
			for(final TableListener listener:listeners){
				TRANSACTION_LISTENER.runDoneTask(new Runnable() {

					@Override
					public void run() {
						try{
							listener.done();
						}catch(Exception e){
							log("done listener %s error:%s",listener.getClass().getName(),e.getMessage());
							if(BaseTableManager.isDebug()){
								log(e);
							}
						}
					}
				});

			}
		}
	}
	/**
	 * determine if the container is empty.
	 * @return 
	 */
	public boolean isEmpty() {
		return listeners.isEmpty();
	}
	/**
	 * determine if the {@code listener} be added.
	 * @param listener
	 * @return {@code true} if {@code listener} exists in container
	 */
	public boolean contains(TableListener listener) {
		synchronized (listeners) {
			return listeners.contains(listener);
		}
	}
	/**
	 * add {@code listener} into container
	 * @return {@code true} if add successfully.
	 */
	public boolean add(TableListener listener) {
		synchronized (listeners) {
			return null == listener ? false : listeners.add(listener);
		}
	}
	/**
	 * remove {@code listener} from container
	 * @param listener instance that will be removed.
	 * @return {@code true} if remove successfully.
	 */
	public boolean remove(TableListener listener) {
		synchronized (listeners) {
			return null == listener? false : listeners.remove(listener);
		}
	}
	/** remove all listeners in container */
	public void clear() {
		synchronized (listeners) {
			listeners.clear();
		}
	}
	private static class TransactionListenerImpl implements TransactionListener{
		private static final ThreadLocal> commitTasks = new ThreadLocal<>();
		private static final ThreadLocal> doneTasks = new ThreadLocal<>();
		@Override
		public void onBegin() {
			commitTasks.set(new LinkedList());
			doneTasks.set(new LinkedList());
		}
		
		private static void runEachTask(LinkedList tasks){
			try {
				// task.run()执行时可能会修改 tasks 的内容,如果直接对tasks遍历会导致 ConcurrentModificationException 异常 
				// 所以这里在tasks的复本(copy)上执行遍历
				ImmutableList copy;
				while (! tasks.isEmpty()) {
					copy = ImmutableList.copyOf(tasks);
					for (Runnable task : copy) {
						task.run();
					}
					tasks.removeAll(copy);
				} 
			} catch (Exception e) {
				log("{}:{}",e.getClass().getName(),e.getMessage());
			}
		}
	
		
		@Override
		public void onCommit() {
			// run all commit tasks
			runEachTask(checkNotNull(commitTasks.get(),"'onBegin' must be called firstly"));
		}
		@Override
		public void onEnd() {
			// run all done tasks
			runEachTask(checkNotNull(doneTasks.get(),"'onBegin' must be called firstly"));
			commitTasks.remove();
			doneTasks.remove();
		}
		void runCommitTask(Runnable task){
			LinkedList tasks = commitTasks.get();
			if(tasks != null){
				tasks.add(task);
			}else {
				task.run();
			}
		}
		void runDoneTask(Runnable task){
			LinkedList tasks = doneTasks.get();
			if(tasks != null){
				tasks.add(task);
			}else {
				task.run();
			}
		}
	}
}