1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.mina.core.service;
21
22 import java.util.AbstractSet;
23 import java.util.Iterator;
24 import java.util.List;
25 import java.util.Map;
26 import java.util.Set;
27 import java.util.concurrent.Executor;
28 import java.util.concurrent.ExecutorService;
29 import java.util.concurrent.Executors;
30 import java.util.concurrent.TimeUnit;
31 import java.util.concurrent.atomic.AtomicInteger;
32
33 import org.apache.mina.core.IoUtil;
34 import org.apache.mina.core.filterchain.DefaultIoFilterChain;
35 import org.apache.mina.core.filterchain.DefaultIoFilterChainBuilder;
36 import org.apache.mina.core.filterchain.IoFilterChainBuilder;
37 import org.apache.mina.core.future.ConnectFuture;
38 import org.apache.mina.core.future.DefaultIoFuture;
39 import org.apache.mina.core.future.IoFuture;
40 import org.apache.mina.core.future.WriteFuture;
41 import org.apache.mina.core.session.AbstractIoSession;
42 import org.apache.mina.core.session.DefaultIoSessionDataStructureFactory;
43 import org.apache.mina.core.session.IdleStatus;
44 import org.apache.mina.core.session.IoSession;
45 import org.apache.mina.core.session.IoSessionConfig;
46 import org.apache.mina.core.session.IoSessionDataStructureFactory;
47 import org.apache.mina.core.session.IoSessionInitializationException;
48 import org.apache.mina.core.session.IoSessionInitializer;
49 import org.apache.mina.util.ExceptionMonitor;
50 import org.apache.mina.util.NamePreservingRunnable;
51 import org.slf4j.Logger;
52 import org.slf4j.LoggerFactory;
53
54
55
56
57
58
59
60
61
62 public abstract class AbstractIoService implements IoService {
63
64 private static final Logger LOGGER = LoggerFactory.getLogger(AbstractIoService.class);
65
66
67
68
69
70 private static final AtomicInteger id = new AtomicInteger();
71
72
73
74
75
76 private final String threadName;
77
78
79
80
81 private final Executor executor;
82
83
84
85
86
87
88
89
90 private final boolean createdExecutor;
91
92
93
94
95 private IoHandler handler;
96
97
98
99
100 private final IoSessionConfig sessionConfig;
101
102 private final IoServiceListener serviceActivationListener = new IoServiceListener() {
103 public void serviceActivated(IoService service) {
104
105 AbstractIoService s = (AbstractIoService) service;
106 IoServiceStatistics _stats = s.getStatistics();
107 _stats.setLastReadTime(s.getActivationTime());
108 _stats.setLastWriteTime(s.getActivationTime());
109 _stats.setLastThroughputCalculationTime(s.getActivationTime());
110
111 }
112
113 public void serviceDeactivated(IoService service) {
114
115 }
116
117 public void serviceIdle(IoService service, IdleStatus idleStatus) {
118
119 }
120
121 public void sessionCreated(IoSession session) {
122
123 }
124
125 public void sessionDestroyed(IoSession session) {
126
127 }
128 };
129
130
131
132
133 private IoFilterChainBuilder filterChainBuilder = new DefaultIoFilterChainBuilder();
134
135 private IoSessionDataStructureFactory sessionDataStructureFactory = new DefaultIoSessionDataStructureFactory();
136
137
138
139
140 private final IoServiceListenerSupport listeners;
141
142
143
144
145
146 protected final Object disposalLock = new Object();
147
148 private volatile boolean disposing;
149
150 private volatile boolean disposed;
151
152
153
154
155 private IoServiceStatistics stats = new IoServiceStatistics(this);
156
157
158
159
160
161
162
163
164
165
166
167
168
169 protected AbstractIoService(IoSessionConfig sessionConfig, Executor executor) {
170 if (sessionConfig == null) {
171 throw new IllegalArgumentException("sessionConfig");
172 }
173
174 if (getTransportMetadata() == null) {
175 throw new IllegalArgumentException("TransportMetadata");
176 }
177
178 if (!getTransportMetadata().getSessionConfigType().isAssignableFrom(sessionConfig.getClass())) {
179 throw new IllegalArgumentException("sessionConfig type: " + sessionConfig.getClass() + " (expected: "
180 + getTransportMetadata().getSessionConfigType() + ")");
181 }
182
183
184
185 listeners = new IoServiceListenerSupport(this);
186 listeners.add(serviceActivationListener);
187
188
189 this.sessionConfig = sessionConfig;
190
191
192
193 ExceptionMonitor.getInstance();
194
195 if (executor == null) {
196 this.executor = Executors.newCachedThreadPool();
197 createdExecutor = true;
198 } else {
199 this.executor = executor;
200 createdExecutor = false;
201 }
202
203 threadName = getClass().getSimpleName() + '-' + id.incrementAndGet();
204 }
205
206
207
208
209 public final IoFilterChainBuilder getFilterChainBuilder() {
210 return filterChainBuilder;
211 }
212
213
214
215
216 public final void setFilterChainBuilder(IoFilterChainBuilder builder) {
217 if (builder == null) {
218 builder = new DefaultIoFilterChainBuilder();
219 }
220 filterChainBuilder = builder;
221 }
222
223
224
225
226 public final DefaultIoFilterChainBuilder getFilterChain() {
227 if (filterChainBuilder instanceof DefaultIoFilterChainBuilder) {
228 return (DefaultIoFilterChainBuilder) filterChainBuilder;
229 }
230
231 throw new IllegalStateException("Current filter chain builder is not a DefaultIoFilterChainBuilder.");
232 }
233
234
235
236
237 public final void addListener(IoServiceListener listener) {
238 listeners.add(listener);
239 }
240
241
242
243
244 public final void removeListener(IoServiceListener listener) {
245 listeners.remove(listener);
246 }
247
248
249
250
251 public final boolean isActive() {
252 return listeners.isActive();
253 }
254
255
256
257
258 public final boolean isDisposing() {
259 return disposing;
260 }
261
262
263
264
265 public final boolean isDisposed() {
266 return disposed;
267 }
268
269
270
271
272 public final void dispose() {
273 dispose(false);
274 }
275
276
277
278
279 public final void dispose(boolean awaitTermination) {
280 if (disposed) {
281 return;
282 }
283
284 synchronized (disposalLock) {
285 if (!disposing) {
286 disposing = true;
287
288 try {
289 dispose0();
290 } catch (Exception e) {
291 ExceptionMonitor.getInstance().exceptionCaught(e);
292 }
293 }
294 }
295
296 if (createdExecutor) {
297 ExecutorService e = (ExecutorService) executor;
298 e.shutdownNow();
299 if (awaitTermination) {
300
301
302
303 try {
304 LOGGER.debug("awaitTermination on {} called by thread=[{}]", this, Thread.currentThread().getName());
305 e.awaitTermination(Integer.MAX_VALUE, TimeUnit.SECONDS);
306 LOGGER.debug("awaitTermination on {} finished", this);
307 } catch (InterruptedException e1) {
308 LOGGER.warn("awaitTermination on [{}] was interrupted", this);
309
310 Thread.currentThread().interrupt();
311 }
312 }
313 }
314 disposed = true;
315 }
316
317
318
319
320
321 protected abstract void dispose0() throws Exception;
322
323
324
325
326 public final Map<Long, IoSession> getManagedSessions() {
327 return listeners.getManagedSessions();
328 }
329
330
331
332
333 public final int getManagedSessionCount() {
334 return listeners.getManagedSessionCount();
335 }
336
337
338
339
340 public final IoHandler getHandler() {
341 return handler;
342 }
343
344
345
346
347 public final void setHandler(IoHandler handler) {
348 if (handler == null) {
349 throw new IllegalArgumentException("handler cannot be null");
350 }
351
352 if (isActive()) {
353 throw new IllegalStateException("handler cannot be set while the service is active.");
354 }
355
356 this.handler = handler;
357 }
358
359
360
361
362 public IoSessionConfig getSessionConfig() {
363 return sessionConfig;
364 }
365
366
367
368
369 public final IoSessionDataStructureFactory getSessionDataStructureFactory() {
370 return sessionDataStructureFactory;
371 }
372
373
374
375
376 public final void setSessionDataStructureFactory(IoSessionDataStructureFactory sessionDataStructureFactory) {
377 if (sessionDataStructureFactory == null) {
378 throw new IllegalArgumentException("sessionDataStructureFactory");
379 }
380
381 if (isActive()) {
382 throw new IllegalStateException("sessionDataStructureFactory cannot be set while the service is active.");
383 }
384
385 this.sessionDataStructureFactory = sessionDataStructureFactory;
386 }
387
388
389
390
391 public IoServiceStatistics getStatistics() {
392 return stats;
393 }
394
395
396
397
398 public final long getActivationTime() {
399 return listeners.getActivationTime();
400 }
401
402
403
404
405 public final Set<WriteFuture> broadcast(Object message) {
406
407
408
409 final List<WriteFuture> futures = IoUtil.broadcast(message, getManagedSessions().values());
410 return new AbstractSet<WriteFuture>() {
411 @Override
412 public Iterator<WriteFuture> iterator() {
413 return futures.iterator();
414 }
415
416 @Override
417 public int size() {
418 return futures.size();
419 }
420 };
421 }
422
423 public final IoServiceListenerSupport getListeners() {
424 return listeners;
425 }
426
427 protected final void executeWorker(Runnable worker) {
428 executeWorker(worker, null);
429 }
430
431 protected final void executeWorker(Runnable worker, String suffix) {
432 String actualThreadName = threadName;
433 if (suffix != null) {
434 actualThreadName = actualThreadName + '-' + suffix;
435 }
436 executor.execute(new NamePreservingRunnable(worker, actualThreadName));
437 }
438
439
440 @SuppressWarnings("unchecked")
441 protected final void initSession(IoSession session, IoFuture future, IoSessionInitializer sessionInitializer) {
442
443 if (stats.getLastReadTime() == 0) {
444 stats.setLastReadTime(getActivationTime());
445 }
446
447 if (stats.getLastWriteTime() == 0) {
448 stats.setLastWriteTime(getActivationTime());
449 }
450
451
452
453
454
455 try {
456 ((AbstractIoSession) session).setAttributeMap(session.getService().getSessionDataStructureFactory()
457 .getAttributeMap(session));
458 } catch (IoSessionInitializationException e) {
459 throw e;
460 } catch (Exception e) {
461 throw new IoSessionInitializationException("Failed to initialize an attributeMap.", e);
462 }
463
464 try {
465 ((AbstractIoSession) session).setWriteRequestQueue(session.getService().getSessionDataStructureFactory()
466 .getWriteRequestQueue(session));
467 } catch (IoSessionInitializationException e) {
468 throw e;
469 } catch (Exception e) {
470 throw new IoSessionInitializationException("Failed to initialize a writeRequestQueue.", e);
471 }
472
473 if ((future != null) && (future instanceof ConnectFuture)) {
474
475 session.setAttribute(DefaultIoFilterChain.SESSION_CREATED_FUTURE, future);
476 }
477
478 if (sessionInitializer != null) {
479 sessionInitializer.initializeSession(session, future);
480 }
481
482 finishSessionInitialization0(session, future);
483 }
484
485
486
487
488
489
490
491 protected void finishSessionInitialization0(IoSession session, IoFuture future) {
492
493 }
494
495 protected static class ServiceOperationFuture extends DefaultIoFuture {
496 public ServiceOperationFuture() {
497 super(null);
498 }
499
500 public final boolean isDone() {
501 return getValue() == Boolean.TRUE;
502 }
503
504 public final void setDone() {
505 setValue(Boolean.TRUE);
506 }
507
508 public final Exception getException() {
509 if (getValue() instanceof Exception) {
510 return (Exception) getValue();
511 }
512
513 return null;
514 }
515
516 public final void setException(Exception exception) {
517 if (exception == null) {
518 throw new IllegalArgumentException("exception");
519 }
520 setValue(exception);
521 }
522 }
523
524
525
526
527 public int getScheduledWriteBytes() {
528 return stats.getScheduledWriteBytes();
529 }
530
531
532
533
534 public int getScheduledWriteMessages() {
535 return stats.getScheduledWriteMessages();
536 }
537
538 }