View Javadoc
1   /*
2    * #%L
3    * wcm.io
4    * %%
5    * Copyright (C) 2014 wcm.io
6    * %%
7    * Licensed under the Apache License, Version 2.0 (the "License");
8    * you may not use this file except in compliance with the License.
9    * You may obtain a copy of the License at
10   *
11   *      http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
18   * #L%
19   */
20  package io.wcm.caravan.io.http.impl;
21  
22  import java.util.Map;
23  
24  import org.apache.commons.configuration.Configuration;
25  import org.apache.commons.lang3.StringUtils;
26  import org.apache.felix.scr.annotations.Activate;
27  import org.apache.felix.scr.annotations.Component;
28  import org.apache.felix.scr.annotations.ConfigurationPolicy;
29  import org.apache.felix.scr.annotations.Deactivate;
30  import org.apache.felix.scr.annotations.Property;
31  import org.apache.sling.commons.osgi.PropertiesUtil;
32  import org.slf4j.Logger;
33  import org.slf4j.LoggerFactory;
34  
35  /**
36   * Configures thread pool options for the transport layer.
37   * The configuration is mapped to archaius configuration internally.
38   */
39  @Component(immediate = true, metatype = true,
40  label = "wcm.io Caravan Resilient Http Thread Pool Configuration",
41  description = " Configures thread pool options for the transport layer.",
42  configurationFactory = true, policy = ConfigurationPolicy.REQUIRE)
43  @Property(name = "webconsole.configurationFactory.nameHint", value = "{threadPoolName}: {hystrixThreadpoolCoresize}")
44  public class CaravanHttpThreadPoolConfig {
45  
46    private static final Logger log = LoggerFactory.getLogger(CaravanHttpThreadPoolConfig.class);
47  
48    /**
49     * Thread Pool Name
50     */
51    @Property(label = "Thread Pool Name", description = "Internal thread pool name.")
52    public static final String THREAD_POOL_NAME_PROPERTY = "threadPoolName";
53  
54    /**
55     * Threadpool size
56     */
57    @Property(label = "Threadpool size",
58        description = "Hystrix: Maximum number of HystrixCommands that can execute concurrently.")
59    public static final String HYSTRIX_THREADPOOL_CORESIZE_PROPERTY = "hystrixThreadpoolCoresize";
60    static final int HYSTRIX_THREADPOOL_CORESIZE_DEFAULT = 10;
61  
62    /**
63     * Max. Threadpool Queue Size
64     */
65    @Property(label = "Max. Threadpool Queue Size",
66        description = "Hystrix: Maximum queue size at which rejections will occur. Note: This property only applies at initialization time.")
67    public static final String HYSTRIX_THREADPOOL_MAXQUEUESIZE_PROPERTY = "hystrixThreadpoolMaxqueuesize";
68    static final int HYSTRIX_THREADPOOL_MAXQUEUESIZE_DEFAULT = 4096;
69  
70    /**
71     * Dynamic Threadpool Queue Size
72     */
73    @Property(label = "Dynamic Threadpool Queue Size",
74        description = "Hystrix: Artificial maximum queue size at which rejections will occur even if hystrixThreadpoolDefaultMaxqueuesize has not been reached.")
75    public static final String HYSTRIX_THREADPOOL_QUEUESIZEREJECTIONTHRESHOLD_PROPERTY = "hystrixThreadpoolQueuesizerejectionthreshold";
76    static final int HYSTRIX_THREADPOOL_QUEUESIZEREJECTIONTHRESHOLD_DEFAULT = 4096;
77  
78    private static final String HYSTRIX_THREADPOOL_PREFIX = "hystrix.threadpool.";
79    private static final String HYSTRIX_PARAM_THREADPOOL_CORESIZE = ".coreSize";
80    private static final String HYSTRIX_PARAM_THREADPOOL_MAXQUEUESIZE = ".maxQueueSize";
81    private static final String HYSTRIX_PARAM_THREADPOOL_QUEUESIZEREJECTIONTHRESHOLD = ".queueSizeRejectionThreshold";
82  
83    @Activate
84    protected void activate(Map<String, Object> config) {
85      String threadPoolName = getThreadPoolName(config);
86      if (validateConfig(threadPoolName, config)) {
87        setArchiausProperties(threadPoolName, config);
88      }
89    }
90  
91    @Deactivate
92    protected void deactivate(Map<String, Object> config) {
93      // clear configuration by writing empty properties
94      String threadPoolName = getThreadPoolName(config);
95      clearArchiausProperties(threadPoolName);
96    }
97  
98    private String getThreadPoolName(Map<String, Object> config) {
99      return PropertiesUtil.toString(config.get(THREAD_POOL_NAME_PROPERTY), null);
100   }
101 
102   /**
103    * Validates configuration
104    * @param threadPoolName Thread pool name
105    * @param config OSGi config
106    */
107   private boolean validateConfig(String threadPoolName, Map<String, Object> config) {
108     if (StringUtils.isBlank(threadPoolName)) {
109       log.warn("Invalid http thread pool configuration without thread pool name, ignoring.", threadPoolName);
110       return false;
111     }
112     return true;
113   }
114 
115   /**
116    * Writes OSGi configuration to archaius configuration.
117    * @param threadPoolName Thread pool name
118    * @param config OSGi config
119    */
120   private void setArchiausProperties(String threadPoolName, Map<String, Object> config) {
121     Configuration archaiusConfig = ArchaiusConfig.getConfiguration();
122     // thread pool size
123     archaiusConfig.setProperty(HYSTRIX_THREADPOOL_PREFIX + threadPoolName + HYSTRIX_PARAM_THREADPOOL_CORESIZE,
124         PropertiesUtil.toInteger(config.get(HYSTRIX_THREADPOOL_CORESIZE_PROPERTY), HYSTRIX_THREADPOOL_CORESIZE_DEFAULT));
125     // maximum thread queue size
126     archaiusConfig.setProperty(HYSTRIX_THREADPOOL_PREFIX + threadPoolName + HYSTRIX_PARAM_THREADPOOL_MAXQUEUESIZE,
127         PropertiesUtil.toInteger(config.get(HYSTRIX_THREADPOOL_MAXQUEUESIZE_PROPERTY), HYSTRIX_THREADPOOL_MAXQUEUESIZE_DEFAULT));
128     // dynamic thread queue size
129     archaiusConfig.setProperty(HYSTRIX_THREADPOOL_PREFIX + threadPoolName + HYSTRIX_PARAM_THREADPOOL_QUEUESIZEREJECTIONTHRESHOLD,
130         PropertiesUtil.toInteger(config.get(HYSTRIX_THREADPOOL_QUEUESIZEREJECTIONTHRESHOLD_PROPERTY), HYSTRIX_THREADPOOL_QUEUESIZEREJECTIONTHRESHOLD_DEFAULT));
131   }
132 
133   /**
134    * Removes OSGi configuration from archaius configuration.
135    * @param threadPoolName Thread pool name
136    */
137   private void clearArchiausProperties(String threadPoolName) {
138     Configuration archaiusConfig = ArchaiusConfig.getConfiguration();
139     archaiusConfig.clearProperty(HYSTRIX_THREADPOOL_PREFIX + threadPoolName + HYSTRIX_PARAM_THREADPOOL_CORESIZE);
140     archaiusConfig.clearProperty(HYSTRIX_THREADPOOL_PREFIX + threadPoolName + HYSTRIX_PARAM_THREADPOOL_MAXQUEUESIZE);
141     archaiusConfig.clearProperty(HYSTRIX_THREADPOOL_PREFIX + threadPoolName + HYSTRIX_PARAM_THREADPOOL_QUEUESIZEREJECTIONTHRESHOLD);
142   }
143 
144 }