1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.mina.filter.executor;
21
22 import java.util.ArrayList;
23 import java.util.List;
24
25 import org.apache.mina.common.IdleStatus;
26 import org.apache.mina.common.IoFilterAdapter;
27 import org.apache.mina.common.IoFilterChain;
28 import org.apache.mina.common.IoSession;
29 import org.apache.mina.common.ThreadModel;
30 import org.apache.mina.util.ByteBufferUtil;
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
33
34 import edu.emory.mathcs.backport.java.util.concurrent.Executor;
35 import edu.emory.mathcs.backport.java.util.concurrent.LinkedBlockingQueue;
36 import edu.emory.mathcs.backport.java.util.concurrent.ThreadPoolExecutor;
37 import edu.emory.mathcs.backport.java.util.concurrent.TimeUnit;
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52 public class ExecutorFilter extends IoFilterAdapter {
53 private final Logger logger = LoggerFactory.getLogger(getClass());
54
55 private final Executor executor;
56
57
58
59
60
61 public ExecutorFilter() {
62 this(new ThreadPoolExecutor(16, 16, 60, TimeUnit.SECONDS,
63 new LinkedBlockingQueue()));
64 }
65
66
67
68
69 public ExecutorFilter(Executor executor) {
70 if (executor == null) {
71 throw new NullPointerException("executor");
72 }
73
74 this.executor = executor;
75 }
76
77
78
79
80 public Executor getExecutor() {
81 return executor;
82 }
83
84 private void fireEvent(NextFilter nextFilter, IoSession session,
85 EventType type, Object data) {
86 Event event = new Event(type, nextFilter, data);
87 SessionBuffer buf = SessionBuffer.getSessionBuffer(session);
88
89 synchronized (buf.eventQueue) {
90 buf.eventQueue.add(event);
91 if (buf.processingCompleted) {
92 buf.processingCompleted = false;
93 if (logger.isDebugEnabled()) {
94 logger.debug("Launching thread for "
95 + session.getRemoteAddress());
96 }
97
98 executor.execute(new ProcessEventsRunnable(buf));
99 }
100 }
101 }
102
103 private static class SessionBuffer {
104 private static final String KEY = SessionBuffer.class.getName()
105 + ".KEY";
106
107 private static SessionBuffer getSessionBuffer(IoSession session) {
108 synchronized (session) {
109 SessionBuffer buf = (SessionBuffer) session.getAttribute(KEY);
110 if (buf == null) {
111 buf = new SessionBuffer(session);
112 session.setAttribute(KEY, buf);
113 }
114 return buf;
115 }
116 }
117
118 private final IoSession session;
119
120 private final List eventQueue = new ArrayList();
121
122 private boolean processingCompleted = true;
123
124 private SessionBuffer(IoSession session) {
125 this.session = session;
126 }
127 }
128
129 protected static class EventType {
130 public static final EventType OPENED = new EventType("OPENED");
131
132 public static final EventType CLOSED = new EventType("CLOSED");
133
134 public static final EventType READ = new EventType("READ");
135
136 public static final EventType WRITTEN = new EventType("WRITTEN");
137
138 public static final EventType RECEIVED = new EventType("RECEIVED");
139
140 public static final EventType SENT = new EventType("SENT");
141
142 public static final EventType IDLE = new EventType("IDLE");
143
144 public static final EventType EXCEPTION = new EventType("EXCEPTION");
145
146 private final String value;
147
148 private EventType(String value) {
149 this.value = value;
150 }
151
152 public String toString() {
153 return value;
154 }
155 }
156
157 protected static class Event {
158 private final EventType type;
159
160 private final NextFilter nextFilter;
161
162 private final Object data;
163
164 Event(EventType type, NextFilter nextFilter, Object data) {
165 this.type = type;
166 this.nextFilter = nextFilter;
167 this.data = data;
168 }
169
170 public Object getData() {
171 return data;
172 }
173
174 public NextFilter getNextFilter() {
175 return nextFilter;
176 }
177
178 public EventType getType() {
179 return type;
180 }
181 }
182
183 public void sessionCreated(NextFilter nextFilter, IoSession session) {
184 nextFilter.sessionCreated(session);
185 }
186
187 public void sessionOpened(NextFilter nextFilter, IoSession session) {
188 fireEvent(nextFilter, session, EventType.OPENED, null);
189 }
190
191 public void sessionClosed(NextFilter nextFilter, IoSession session) {
192 fireEvent(nextFilter, session, EventType.CLOSED, null);
193 }
194
195 public void sessionIdle(NextFilter nextFilter, IoSession session,
196 IdleStatus status) {
197 fireEvent(nextFilter, session, EventType.IDLE, status);
198 }
199
200 public void exceptionCaught(NextFilter nextFilter, IoSession session,
201 Throwable cause) {
202 fireEvent(nextFilter, session, EventType.EXCEPTION, cause);
203 }
204
205 public void messageReceived(NextFilter nextFilter, IoSession session,
206 Object message) {
207 ByteBufferUtil.acquireIfPossible(message);
208 fireEvent(nextFilter, session, EventType.RECEIVED, message);
209 }
210
211 public void messageSent(NextFilter nextFilter, IoSession session,
212 Object message) {
213 ByteBufferUtil.acquireIfPossible(message);
214 fireEvent(nextFilter, session, EventType.SENT, message);
215 }
216
217 protected void processEvent(NextFilter nextFilter, IoSession session,
218 EventType type, Object data) {
219 if (type == EventType.RECEIVED) {
220 nextFilter.messageReceived(session, data);
221 ByteBufferUtil.releaseIfPossible(data);
222 } else if (type == EventType.SENT) {
223 nextFilter.messageSent(session, data);
224 ByteBufferUtil.releaseIfPossible(data);
225 } else if (type == EventType.EXCEPTION) {
226 nextFilter.exceptionCaught(session, (Throwable) data);
227 } else if (type == EventType.IDLE) {
228 nextFilter.sessionIdle(session, (IdleStatus) data);
229 } else if (type == EventType.OPENED) {
230 nextFilter.sessionOpened(session);
231 } else if (type == EventType.CLOSED) {
232 nextFilter.sessionClosed(session);
233 }
234 }
235
236 public void filterWrite(NextFilter nextFilter, IoSession session,
237 WriteRequest writeRequest) {
238 nextFilter.filterWrite(session, writeRequest);
239 }
240
241 public void filterClose(NextFilter nextFilter, IoSession session)
242 throws Exception {
243 nextFilter.filterClose(session);
244 }
245
246 private class ProcessEventsRunnable implements Runnable {
247 private final SessionBuffer buffer;
248
249 ProcessEventsRunnable(SessionBuffer buffer) {
250 this.buffer = buffer;
251 }
252
253 public void run() {
254 while (true) {
255 Event event;
256
257 synchronized (buffer.eventQueue) {
258 if (buffer.eventQueue.isEmpty()) {
259 buffer.processingCompleted = true;
260 break;
261 }
262
263 event = (Event) buffer.eventQueue.remove(0);
264 }
265
266 processEvent(event.getNextFilter(), buffer.session, event
267 .getType(), event.getData());
268 }
269
270 if (logger.isDebugEnabled()) {
271 logger.debug("Exiting since queue is empty for "
272 + buffer.session.getRemoteAddress());
273 }
274 }
275 }
276 }