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
25 import org.apache.mina.filter.executor.ExecutorFilter;
26 import org.apache.mina.util.NamePreservingRunnable;
27
28 import edu.emory.mathcs.backport.java.util.concurrent.Executor;
29 import edu.emory.mathcs.backport.java.util.concurrent.ThreadFactory;
30 import edu.emory.mathcs.backport.java.util.concurrent.ThreadPoolExecutor;
31 import edu.emory.mathcs.backport.java.util.concurrent.atomic.AtomicInteger;
32
33 /**
34 * A {@link ThreadModel} which represents a thread model with an {@link Executor}
35 * (from <a href="http://dcl.mathcs.emory.edu/util/backport-util-concurrent/">backport-util-concurrent</a>)
36 * per service. The default underlying {@link Executor} is {@link ThreadPoolExecutor},
37 * so you can safely downcast the returned {@link Executor} of {@link #getExecutor()} to
38 * {@link ThreadPoolExecutor} by default.
39 *
40 * @author The Apache Directory Project (mina-dev@directory.apache.org)
41 * @version $Rev: 588150 $, $Date: 2007-10-25 08:20:04 +0200 (Thu, 25 Oct 2007) $
42 */
43 public class ExecutorThreadModel implements ThreadModel {
44 /**
45 * Maps a service name to a PooledThreadModel instance.
46 * Without this map, we might create extremely many thread pools that leads the system to
47 * coma. */
48 private static final Map service2model = new HashMap();
49
50 /**
51 * Returns a {@link ExecutorThreadModel} instance for the specified <tt>serviceName</tt>.
52 * Please note that all returned instances will be managed globally; the same instance
53 * will be returned if you specified the same service name. Please try to specify
54 * different names for different services.
55 *
56 * @param serviceName the name of the service that needs thread pooling
57 */
58 public static ExecutorThreadModel getInstance(String serviceName) {
59 if (serviceName == null) {
60 throw new NullPointerException("serviceName");
61 }
62
63 ExecutorThreadModel model;
64 synchronized (service2model) {
65 model = (ExecutorThreadModel) service2model.get(serviceName);
66 if (model == null) {
67 model = new ExecutorThreadModel(serviceName);
68 service2model.put(serviceName, model);
69 }
70 }
71
72 return model;
73 }
74
75 private final String threadNamePrefix;
76
77 private final ExecutorFilter defaultFilter;
78
79 private ExecutorFilter filter = new ExecutorFilter();
80
81 private ExecutorThreadModel(String threadNamePrefix) {
82 this.threadNamePrefix = threadNamePrefix;
83
84 // Create the default filter
85 defaultFilter = new ExecutorFilter();
86 ThreadPoolExecutor tpe = (ThreadPoolExecutor) defaultFilter
87 .getExecutor();
88 final ThreadFactory originalThreadFactory = tpe.getThreadFactory();
89 ThreadFactory newThreadFactory = new ThreadFactory() {
90 private final AtomicInteger threadId = new AtomicInteger(0);
91
92 public Thread newThread(Runnable runnable) {
93 Thread t = originalThreadFactory.newThread(
94 new NamePreservingRunnable(
95 runnable,
96 ExecutorThreadModel.this.threadNamePrefix + '-' +
97 threadId.incrementAndGet()));
98 t.setDaemon(true);
99 return t;
100 }
101 };
102 tpe.setThreadFactory(newThreadFactory);
103
104 // Set to default.
105 setExecutor(null);
106 }
107
108 /**
109 * Returns the underlying {@link Executor} of this model.
110 * You can change various properties such as the number of threads
111 * by calling methods of the {@link Executor} implementation.
112 */
113 public Executor getExecutor() {
114 return filter.getExecutor();
115 }
116
117 /**
118 * Changes the underlying {@link Executor} of this model.
119 * Previous settings such as the number of threads should be configured again.
120 * Only newly created {@link IoSession}s will be affected.
121 *
122 * @param executor <tt>null</tt> to revert to the default setting
123 */
124 public void setExecutor(Executor executor) {
125 if (executor == null) {
126 filter = defaultFilter;
127 } else {
128 filter = new ExecutorFilter(executor);
129 }
130 }
131
132 public void buildFilterChain(IoFilterChain chain) throws Exception {
133 chain.addFirst(ExecutorThreadModel.class.getName(), filter);
134 }
135 }