001package gu.sql2java; 002 003import java.util.LinkedHashSet; 004import java.util.LinkedList; 005import gu.sql2java.exception.RuntimeDaoException; 006 007import static com.google.common.base.Preconditions.*; 008import static gu.sql2java.SimpleLog.*; 009 010/** 011 * container for multiple listener management 012 * @author guyadong 013 */ 014public class ListenerContainer <B> implements TableListener<B> { 015 private final LinkedHashSet<TableListener<B>> listeners = new LinkedHashSet<TableListener<B>>(16); 016 017 static final TransactionListenerImpl TRANSACTION_LISTENER = new TransactionListenerImpl(); 018 public ListenerContainer() { 019 } 020 021 @Override 022 public void beforeInsert(B bean)throws RuntimeDaoException{ 023 synchronized (listeners) { 024 for(TableListener<B> listener:listeners){ 025 try{ 026 listener.beforeInsert(bean); 027 }catch(Exception e){ 028 log("beforeInsert listener %s error:%s",listener.getClass().getName(),e.getMessage()); 029 } 030 } 031 } 032 } 033 034 @Override 035 public void afterInsert(final B bean)throws RuntimeDaoException{ 036 synchronized (listeners) { 037 for(final TableListener<B> listener:listeners){ 038 TRANSACTION_LISTENER.runCommitTask(new Runnable() { 039 040 @Override 041 public void run() { 042 try{ 043 listener.afterInsert(bean); 044 }catch(Exception e){ 045 log("afterInsert listener %s error:%s",listener.getClass().getName(),e.getMessage()); 046 //log(e); 047 } 048 } 049 }); 050 } 051 } 052 } 053 054 @Override 055 public void beforeUpdate(B bean)throws RuntimeDaoException{ 056 synchronized (listeners) { 057 for(TableListener<B> listener:listeners){ 058 try{ 059 listener.beforeUpdate(bean); 060 }catch(Exception e){ 061 log("beforeUpdate listener %s error:%s",listener.getClass().getName(),e.getMessage()); 062 } 063 } 064 } 065 } 066 067 @Override 068 public void afterUpdate(final B bean)throws RuntimeDaoException{ 069 synchronized (listeners) { 070 for(final TableListener<B> listener:listeners){ 071 TRANSACTION_LISTENER.runCommitTask(new Runnable() { 072 073 @Override 074 public void run() { 075 try{ 076 listener.afterUpdate(bean); 077 }catch(Exception e){ 078 log("afterUpdate listener %s error:%s",listener.getClass().getName(),e.getMessage()); 079 //log(e); 080 } 081 } 082 }); 083 } 084 } 085 } 086 087 @Override 088 public void beforeDelete(B bean)throws RuntimeDaoException{ 089 synchronized (listeners) { 090 for(TableListener<B> listener:listeners){ 091 try{ 092 listener.beforeDelete(bean); 093 }catch(Exception e){ 094 log("beforeDelete listener %s error:%s",listener.getClass().getName(),e.getMessage()); 095 } 096 } 097 } 098 } 099 100 @Override 101 public void afterDelete(final B bean)throws RuntimeDaoException{ 102 synchronized (listeners) { 103 for(final TableListener<B> listener:listeners){ 104 TRANSACTION_LISTENER.runCommitTask(new Runnable() { 105 106 @Override 107 public void run() { 108 try{ 109 listener.afterDelete(bean); 110 }catch(Exception e){ 111 log("afterDelete listener %s error:%s",listener.getClass().getName(),e.getMessage()); 112 } 113 } 114 }); 115 116 } 117 } 118 } 119 120 @Override 121 public void done()throws RuntimeDaoException{ 122 synchronized (listeners) { 123 for(final TableListener<B> listener:listeners){ 124 TRANSACTION_LISTENER.runDoneTask(new Runnable() { 125 126 @Override 127 public void run() { 128 try{ 129 listener.done(); 130 }catch(Exception e){ 131 log("done listener %s error:%s",listener.getClass().getName(),e.getMessage()); 132 } 133 } 134 }); 135 136 } 137 } 138 } 139 /** 140 * determine if the container is empty. 141 * @return 142 */ 143 public boolean isEmpty() { 144 return listeners.isEmpty(); 145 } 146 /** 147 * determine if the {@code listener} be added. 148 * @param listener 149 * @return {@code true} if {@code listener} exists in container 150 */ 151 public boolean contains(TableListener<B> listener) { 152 synchronized (listeners) { 153 return listeners.contains(listener); 154 } 155 } 156 /** 157 * add {@code listener} into container 158 * @return {@code true} if add successfully. 159 */ 160 public boolean add(TableListener<B> listener) { 161 synchronized (listeners) { 162 return null == listener ? false : listeners.add(listener); 163 } 164 } 165 /** 166 * remove {@code listener} from container 167 * @param listener instance that will be removed. 168 * @return {@code true} if remove successfully. 169 */ 170 public boolean remove(TableListener<B> listener) { 171 synchronized (listeners) { 172 return null == listener? false : listeners.remove(listener); 173 } 174 } 175 /** remove all listeners in container */ 176 public void clear() { 177 synchronized (listeners) { 178 listeners.clear(); 179 } 180 } 181 private static class TransactionListenerImpl implements TransactionListener{ 182 private static final InheritableThreadLocal<LinkedList<Runnable>> commitTasks = new InheritableThreadLocal<>(); 183 private static final InheritableThreadLocal<LinkedList<Runnable>> doneTasks = new InheritableThreadLocal<>(); 184 @Override 185 public void onBegin() { 186 commitTasks.set(new LinkedList<Runnable>()); 187 doneTasks.set(new LinkedList<Runnable>()); 188 } 189 @Override 190 public void onCommit() { 191 // run all commit tasks 192 LinkedList<Runnable> tasks = commitTasks.get(); 193 checkState(null != tasks,"'onBegin' must be called firstly"); 194 for (Runnable task : tasks) { 195 task.run(); 196 } 197 } 198 @Override 199 public void onEnd() { 200 // run all done tasks 201 LinkedList<Runnable> tasks = doneTasks.get(); 202 checkState(null != tasks,"'onBegin' must be called firstly"); 203 for (Runnable task : tasks) { 204 task.run(); 205 } 206 commitTasks.remove(); 207 doneTasks.remove(); 208 } 209 void runCommitTask(Runnable task){ 210 LinkedList<Runnable> tasks = commitTasks.get(); 211 if(tasks != null){ 212 tasks.add(task); 213 }else { 214 task.run(); 215 } 216 } 217 void runDoneTask(Runnable task){ 218 LinkedList<Runnable> tasks = doneTasks.get(); 219 if(tasks != null){ 220 tasks.add(task); 221 }else { 222 task.run(); 223 } 224 } 225 } 226}