1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 *
19 */
20 package org.apache.mina.common;
21
22 import java.util.HashMap;
23 import java.util.Map;
24 import java.util.concurrent.Executor;
25 import java.util.concurrent.ThreadFactory;
26 import java.util.concurrent.ThreadPoolExecutor;
27 import java.util.concurrent.atomic.AtomicInteger;
28
29 import org.apache.mina.filter.executor.ExecutorFilter;
30 import org.apache.mina.util.NamePreservingRunnable;
31
32 /**
33 * A {@link ThreadModel} which represents a thread model with an {@link Executor}
34 * per service. The default underlying {@link Executor} is {@link ThreadPoolExecutor},
35 * so you can safely downcast the returned {@link Executor} of {@link #getExecutor()} to
36 * {@link ThreadPoolExecutor} by default.
37 *
38 * @author The Apache Directory Project (mina-dev@directory.apache.org)
39 * @version $Rev: 588150 $, $Date: 2007-10-25 15:20:04 +0900 (Thu, 25 Oct 2007) $
40 */
41 public class ExecutorThreadModel implements ThreadModel {
42 /**
43 * Maps a service name to a PooledThreadModel instance.
44 * Without this map, we might create extremely many thread pools that leads the system to
45 * coma. */
46 private static final Map<String, ExecutorThreadModel> service2model = new HashMap<String, ExecutorThreadModel>();
47
48 /**
49 * Returns a {@link ExecutorThreadModel} instance for the specified <tt>serviceName</tt>.
50 * Please note that all returned instances will be managed globally; the same instance
51 * will be returned if you specified the same service name. Please try to specify
52 * different names for different services.
53 *
54 * @param serviceName the name of the service that needs thread pooling
55 */
56 public static ExecutorThreadModel getInstance(String serviceName) {
57 if (serviceName == null) {
58 throw new NullPointerException("serviceName");
59 }
60
61 ExecutorThreadModel model;
62 synchronized (service2model) {
63 model = service2model.get(serviceName);
64 if (model == null) {
65 model = new ExecutorThreadModel(serviceName);
66 service2model.put(serviceName, model);
67 }
68 }
69
70 return model;
71 }
72
73 private final String threadNamePrefix;
74
75 private final ExecutorFilter defaultFilter;
76
77 private ExecutorFilter filter = new ExecutorFilter();
78
79 private ExecutorThreadModel(String threadNamePrefix) {
80 this.threadNamePrefix = threadNamePrefix;
81
82 // Create the default filter
83 defaultFilter = new ExecutorFilter();
84 ThreadPoolExecutor tpe = (ThreadPoolExecutor) defaultFilter
85 .getExecutor();
86 final ThreadFactory originalThreadFactory = tpe.getThreadFactory();
87 ThreadFactory newThreadFactory = new ThreadFactory() {
88 private final AtomicInteger threadId = new AtomicInteger(0);
89
90 public Thread newThread(Runnable runnable) {
91 Thread t = originalThreadFactory.newThread(
92 new NamePreservingRunnable(
93 runnable,
94 ExecutorThreadModel.this.threadNamePrefix + '-' +
95 threadId.incrementAndGet()));
96 t.setDaemon(true);
97 return t;
98 }
99 };
100 tpe.setThreadFactory(newThreadFactory);
101
102 // Set to default.
103 setExecutor(null);
104 }
105
106 /**
107 * Returns the underlying {@link Executor} of this model.
108 * You can change various properties such as the number of threads
109 * by calling methods of the {@link Executor} implementation.
110 */
111 public Executor getExecutor() {
112 return filter.getExecutor();
113 }
114
115 /**
116 * Changes the underlying {@link Executor} of this model.
117 * Previous settings such as the number of threads should be configured again.
118 * Only newly created {@link IoSession}s will be affected.
119 *
120 * @param executor <tt>null</tt> to revert to the default setting
121 */
122 public void setExecutor(Executor executor) {
123 if (executor == null) {
124 filter = defaultFilter;
125 } else {
126 filter = new ExecutorFilter(executor);
127 }
128 }
129
130 public void buildFilterChain(IoFilterChain chain) throws Exception {
131 chain.addFirst(ExecutorThreadModel.class.getName(), filter);
132 }
133 }