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