View Javadoc

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 }