1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.mina.transport.vmpipe.support;
21
22 import java.util.Queue;
23 import java.util.concurrent.ConcurrentLinkedQueue;
24
25 import org.apache.mina.common.ByteBuffer;
26 import org.apache.mina.common.IdleStatus;
27 import org.apache.mina.common.IoSession;
28 import org.apache.mina.common.IoFilter.WriteRequest;
29 import org.apache.mina.common.support.AbstractIoFilterChain;
30
31
32
33
34
35 public class VmPipeFilterChain extends AbstractIoFilterChain {
36
37 private final Queue<Event> eventQueue = new ConcurrentLinkedQueue<Event>();
38
39 private volatile boolean flushEnabled;
40 private volatile boolean sessionOpened;
41
42 public VmPipeFilterChain(IoSession session) {
43 super(session);
44 }
45
46 public void start() {
47 flushEnabled = true;
48 flushEvents();
49 flushPendingDataQueues( (VmPipeSessionImpl) getSession() );
50 }
51
52 private void pushEvent(Event e) {
53 eventQueue.offer(e);
54 if ( flushEnabled ) {
55 flushEvents();
56 }
57 }
58
59 private void flushEvents() {
60 Event e;
61 while ((e = eventQueue.poll()) != null) {
62 fireEvent(e);
63 }
64 }
65
66 private void fireEvent(Event e) {
67 IoSession session = getSession();
68 EventType type = e.getType();
69 Object data = e.getData();
70
71 if (type == EventType.RECEIVED) {
72 VmPipeSessionImpl s = (VmPipeSessionImpl) session;
73
74 if( sessionOpened && s.getTrafficMask().isReadable() && s.getLock().tryLock()) {
75 try {
76 int byteCount = 1;
77 if (data instanceof ByteBuffer) {
78 byteCount = ((ByteBuffer) data).remaining();
79 }
80
81 s.increaseReadBytes(byteCount);
82
83 super.fireMessageReceived(s, data);
84 } finally {
85 s.getLock().unlock();
86 }
87
88 flushPendingDataQueues( s );
89 } else {
90 s.pendingDataQueue.add(data);
91 }
92 } else if (type == EventType.WRITE) {
93 super.fireFilterWrite(session, (WriteRequest) data);
94 } else if (type == EventType.SENT) {
95 super.fireMessageSent(session, (WriteRequest) data);
96 } else if (type == EventType.EXCEPTION) {
97 super.fireExceptionCaught(session, (Throwable) data);
98 } else if (type == EventType.IDLE) {
99 super.fireSessionIdle(session, (IdleStatus) data);
100 } else if (type == EventType.OPENED) {
101 super.fireSessionOpened(session);
102 sessionOpened = true;
103 } else if (type == EventType.CREATED) {
104 super.fireSessionCreated(session);
105 } else if (type == EventType.CLOSED) {
106 super.fireSessionClosed(session);
107 } else if (type == EventType.CLOSE) {
108 super.fireFilterClose(session);
109 }
110 }
111
112 private static void flushPendingDataQueues( VmPipeSessionImpl s ) {
113 s.updateTrafficMask();
114 s.getRemoteSession().updateTrafficMask();
115 }
116
117 @Override
118 public void fireFilterClose(IoSession session) {
119 pushEvent(new Event(EventType.CLOSE, null));
120 }
121
122 @Override
123 public void fireFilterWrite(IoSession session, WriteRequest writeRequest) {
124 pushEvent(new Event(EventType.WRITE, writeRequest));
125 }
126
127 @Override
128 public void fireExceptionCaught(IoSession session, Throwable cause) {
129 pushEvent(new Event(EventType.EXCEPTION, cause));
130 }
131
132 @Override
133 public void fireMessageSent(IoSession session, WriteRequest request) {
134 pushEvent(new Event(EventType.SENT, request));
135 }
136
137 @Override
138 public void fireSessionClosed(IoSession session) {
139 pushEvent(new Event(EventType.CLOSED, null));
140 }
141
142 @Override
143 public void fireSessionCreated(IoSession session) {
144 pushEvent(new Event(EventType.CREATED, null));
145 }
146
147 @Override
148 public void fireSessionIdle(IoSession session, IdleStatus status) {
149 pushEvent(new Event(EventType.IDLE, status));
150 }
151
152 @Override
153 public void fireSessionOpened(IoSession session) {
154 pushEvent(new Event(EventType.OPENED, null));
155 }
156
157 @Override
158 public void fireMessageReceived(IoSession session, Object message) {
159 pushEvent(new Event(EventType.RECEIVED, message));
160 }
161
162 @Override
163 protected void doWrite(IoSession session, WriteRequest writeRequest) {
164 VmPipeSessionImpl s = (VmPipeSessionImpl) session;
165 if (s.isConnected()) {
166 if ( s.getTrafficMask().isWritable() && s.getLock().tryLock()) {
167 try {
168 Object message = writeRequest.getMessage();
169
170 int byteCount = 1;
171 Object messageCopy = message;
172 if (message instanceof ByteBuffer) {
173 ByteBuffer rb = (ByteBuffer) message;
174 rb.mark();
175 byteCount = rb.remaining();
176 ByteBuffer wb = ByteBuffer.allocate(rb.remaining());
177 wb.put(rb);
178 wb.flip();
179 rb.reset();
180 messageCopy = wb;
181 }
182
183
184
185 s.increaseScheduledWriteBytes(byteCount);
186 s.increaseScheduledWriteRequests();
187
188 s.increaseWrittenBytes(byteCount);
189 s.increaseWrittenMessages();
190
191 s.getRemoteSession().getFilterChain().fireMessageReceived(
192 s.getRemoteSession(), messageCopy);
193 s.getFilterChain().fireMessageSent(s, writeRequest);
194 } finally {
195 s.getLock().unlock();
196 }
197
198 flushPendingDataQueues( s );
199 } else {
200 s.pendingDataQueue.add(writeRequest);
201 }
202 } else {
203 writeRequest.getFuture().setWritten(false);
204 }
205 }
206
207 @Override
208 protected void doClose(IoSession session) {
209 VmPipeSessionImpl s = (VmPipeSessionImpl) session;
210
211 try {
212 s.getLock().lock();
213
214 if (!session.getCloseFuture().isClosed()) {
215 s.getServiceListeners().fireSessionDestroyed(s);
216 s.getRemoteSession().close();
217 }
218 } finally {
219 s.getLock().unlock();
220 }
221 }
222
223
224 private static class EventType {
225 public static final EventType CREATED = new EventType("CREATED");
226
227 public static final EventType OPENED = new EventType("OPENED");
228
229 public static final EventType CLOSED = new EventType("CLOSED");
230
231 public static final EventType RECEIVED = new EventType("RECEIVED");
232
233 public static final EventType SENT = new EventType("SENT");
234
235 public static final EventType IDLE = new EventType("IDLE");
236
237 public static final EventType EXCEPTION = new EventType("EXCEPTION");
238
239 public static final EventType WRITE = new EventType("WRITE");
240
241 public static final EventType CLOSE = new EventType("CLOSE");
242
243 private final String value;
244
245 private EventType(String value) {
246 this.value = value;
247 }
248
249 @Override
250 public String toString() {
251 return value;
252 }
253 }
254
255 private static class Event {
256 private final EventType type;
257
258 private final Object data;
259
260 private Event(EventType type, Object data) {
261 this.type = type;
262 this.data = data;
263 }
264
265 public Object getData() {
266 return data;
267 }
268
269 public EventType getType() {
270 return type;
271 }
272 }
273 }