PageRenderTime 43ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/bootstrap/src/main/java/io/airlift/bootstrap/Bootstrap.java

https://gitlab.com/CORP-RESELLER/airlift
Java | 343 lines | 259 code | 44 blank | 40 comment | 30 complexity | b1ab38472e9e65ab7ea34a75988319c6 MD5 | raw file
  1. /*
  2. * Copyright 2010 Proofpoint, Inc.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package io.airlift.bootstrap;
  17. import com.google.common.annotations.Beta;
  18. import com.google.common.base.Preconditions;
  19. import com.google.common.collect.ImmutableList;
  20. import com.google.common.collect.ImmutableList.Builder;
  21. import com.google.common.collect.ImmutableSortedMap;
  22. import com.google.common.collect.Maps;
  23. import com.google.inject.Binder;
  24. import com.google.inject.Guice;
  25. import com.google.inject.Injector;
  26. import com.google.inject.Module;
  27. import com.google.inject.Stage;
  28. import com.google.inject.spi.Message;
  29. import io.airlift.bootstrap.LoggingWriter.Type;
  30. import io.airlift.configuration.ConfigurationAwareModule;
  31. import io.airlift.configuration.ConfigurationFactory;
  32. import io.airlift.configuration.ConfigurationInspector;
  33. import io.airlift.configuration.ConfigurationInspector.ConfigAttribute;
  34. import io.airlift.configuration.ConfigurationInspector.ConfigRecord;
  35. import io.airlift.configuration.ConfigurationLoader;
  36. import io.airlift.configuration.ConfigurationModule;
  37. import io.airlift.configuration.ConfigurationValidator;
  38. import io.airlift.configuration.ValidationErrorModule;
  39. import io.airlift.configuration.WarningsMonitor;
  40. import io.airlift.log.Logger;
  41. import io.airlift.log.Logging;
  42. import io.airlift.log.LoggingConfiguration;
  43. import java.io.PrintWriter;
  44. import java.util.Collections;
  45. import java.util.List;
  46. import java.util.Map;
  47. import java.util.Map.Entry;
  48. import java.util.SortedMap;
  49. import java.util.TreeMap;
  50. import static com.google.common.collect.Maps.fromProperties;
  51. /**
  52. * Entry point for an application built using the platform codebase.
  53. * <p>
  54. * This class will:
  55. * <ul>
  56. * <li>load, validate and bind configurations</li>
  57. * <li>initialize logging</li>
  58. * <li>set up bootstrap management</li>
  59. * <li>create an Guice injector</li>
  60. * </ul>
  61. */
  62. public class Bootstrap
  63. {
  64. private final Logger log = Logger.get("Bootstrap");
  65. private final List<Module> modules;
  66. private Map<String, String> requiredConfigurationProperties;
  67. private Map<String, String> optionalConfigurationProperties;
  68. private boolean initializeLogging = true;
  69. private boolean quiet;
  70. private boolean strictConfig;
  71. private boolean requireExplicitBindings = true;
  72. private boolean initialized;
  73. public Bootstrap(Module... modules)
  74. {
  75. this(ImmutableList.copyOf(modules));
  76. }
  77. public Bootstrap(Iterable<? extends Module> modules)
  78. {
  79. this.modules = ImmutableList.copyOf(modules);
  80. }
  81. @Beta
  82. public Bootstrap setRequiredConfigurationProperty(String key, String value)
  83. {
  84. if (this.requiredConfigurationProperties == null) {
  85. this.requiredConfigurationProperties = new TreeMap<>();
  86. }
  87. this.requiredConfigurationProperties.put(key, value);
  88. return this;
  89. }
  90. @Beta
  91. public Bootstrap setRequiredConfigurationProperties(Map<String, String> requiredConfigurationProperties)
  92. {
  93. if (this.requiredConfigurationProperties == null) {
  94. this.requiredConfigurationProperties = new TreeMap<>();
  95. }
  96. this.requiredConfigurationProperties.putAll(requiredConfigurationProperties);
  97. return this;
  98. }
  99. @Beta
  100. public Bootstrap setOptionalConfigurationProperty(String key, String value)
  101. {
  102. if (this.optionalConfigurationProperties == null) {
  103. this.optionalConfigurationProperties = new TreeMap<>();
  104. }
  105. this.optionalConfigurationProperties.put(key, value);
  106. return this;
  107. }
  108. @Beta
  109. public Bootstrap setOptionalConfigurationProperties(Map<String, String> optionalConfigurationProperties)
  110. {
  111. if (this.optionalConfigurationProperties == null) {
  112. this.optionalConfigurationProperties = new TreeMap<>();
  113. }
  114. this.optionalConfigurationProperties.putAll(optionalConfigurationProperties);
  115. return this;
  116. }
  117. @Beta
  118. public Bootstrap doNotInitializeLogging()
  119. {
  120. this.initializeLogging = false;
  121. return this;
  122. }
  123. public Bootstrap quiet()
  124. {
  125. this.quiet = true;
  126. return this;
  127. }
  128. public Bootstrap strictConfig()
  129. {
  130. this.strictConfig = true;
  131. return this;
  132. }
  133. public Bootstrap requireExplicitBindings(boolean requireExplicitBindings)
  134. {
  135. this.requireExplicitBindings = requireExplicitBindings;
  136. return this;
  137. }
  138. public Injector initialize()
  139. throws Exception
  140. {
  141. Preconditions.checkState(!initialized, "Already initialized");
  142. initialized = true;
  143. Logging logging = null;
  144. if (initializeLogging) {
  145. logging = Logging.initialize();
  146. }
  147. Thread.currentThread().setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler()
  148. {
  149. @Override
  150. public void uncaughtException(Thread t, Throwable e)
  151. {
  152. log.error(e, "Uncaught exception in thread %s", t.getName());
  153. }
  154. });
  155. Map<String, String> requiredProperties;
  156. ConfigurationFactory configurationFactory;
  157. if (requiredConfigurationProperties == null) {
  158. // initialize configuration
  159. log.info("Loading configuration");
  160. ConfigurationLoader loader = new ConfigurationLoader();
  161. requiredProperties = Collections.emptyMap();
  162. String configFile = System.getProperty("config");
  163. if (configFile != null) {
  164. requiredProperties = loader.loadPropertiesFrom(configFile);
  165. }
  166. }
  167. else {
  168. requiredProperties = requiredConfigurationProperties;
  169. }
  170. SortedMap<String, String> properties = Maps.newTreeMap();
  171. if (optionalConfigurationProperties != null) {
  172. properties.putAll(optionalConfigurationProperties);
  173. }
  174. properties.putAll(requiredProperties);
  175. properties.putAll(fromProperties(System.getProperties()));
  176. properties = ImmutableSortedMap.copyOf(properties);
  177. configurationFactory = new ConfigurationFactory(properties);
  178. if (logging != null) {
  179. // initialize logging
  180. log.info("Initializing logging");
  181. LoggingConfiguration configuration = configurationFactory.build(LoggingConfiguration.class);
  182. logging.configure(configuration);
  183. }
  184. // create warning logger now that we have logging initialized
  185. final WarningsMonitor warningsMonitor = new WarningsMonitor()
  186. {
  187. @Override
  188. public void onWarning(String message)
  189. {
  190. log.warn(message);
  191. }
  192. };
  193. // initialize configuration factory
  194. for (Module module : modules) {
  195. if (module instanceof ConfigurationAwareModule) {
  196. ConfigurationAwareModule configurationAwareModule = (ConfigurationAwareModule) module;
  197. configurationAwareModule.setConfigurationFactory(configurationFactory);
  198. }
  199. }
  200. // Validate configuration
  201. ConfigurationValidator configurationValidator = new ConfigurationValidator(configurationFactory, warningsMonitor);
  202. List<Message> messages = configurationValidator.validate(modules);
  203. // at this point all config file properties should be used
  204. // so we can calculate the unused properties
  205. final TreeMap<String, String> unusedProperties = Maps.newTreeMap();
  206. unusedProperties.putAll(requiredProperties);
  207. unusedProperties.keySet().removeAll(configurationFactory.getUsedProperties());
  208. // Log effective configuration
  209. if (!quiet) {
  210. logConfiguration(configurationFactory, unusedProperties);
  211. }
  212. // system modules
  213. Builder<Module> moduleList = ImmutableList.builder();
  214. moduleList.add(new LifeCycleModule());
  215. moduleList.add(new ConfigurationModule(configurationFactory));
  216. if (!messages.isEmpty()) {
  217. moduleList.add(new ValidationErrorModule(messages));
  218. }
  219. moduleList.add(new Module()
  220. {
  221. @Override
  222. public void configure(Binder binder)
  223. {
  224. binder.bind(WarningsMonitor.class).toInstance(warningsMonitor);
  225. }
  226. });
  227. moduleList.add(new Module()
  228. {
  229. @Override
  230. public void configure(Binder binder)
  231. {
  232. binder.disableCircularProxies();
  233. if(requireExplicitBindings) {
  234. binder.requireExplicitBindings();
  235. }
  236. }
  237. });
  238. // todo this should be part of the ValidationErrorModule
  239. if (strictConfig) {
  240. moduleList.add(new Module()
  241. {
  242. @Override
  243. public void configure(Binder binder)
  244. {
  245. for (Entry<String, String> unusedProperty : unusedProperties.entrySet()) {
  246. binder.addError("Configuration property '%s=%s' was not used", unusedProperty.getKey(), unusedProperty.getValue());
  247. }
  248. }
  249. });
  250. }
  251. moduleList.addAll(modules);
  252. // create the injector
  253. Injector injector = Guice.createInjector(Stage.PRODUCTION, moduleList.build());
  254. // Create the life-cycle manager
  255. LifeCycleManager lifeCycleManager = injector.getInstance(LifeCycleManager.class);
  256. // Start services
  257. if (lifeCycleManager.size() > 0) {
  258. lifeCycleManager.start();
  259. }
  260. return injector;
  261. }
  262. private static final String PROPERTY_NAME_COLUMN = "PROPERTY";
  263. private static final String DEFAULT_VALUE_COLUMN = "DEFAULT";
  264. private static final String CURRENT_VALUE_COLUMN = "RUNTIME";
  265. private static final String DESCRIPTION_COLUMN = "DESCRIPTION";
  266. private void logConfiguration(ConfigurationFactory configurationFactory, Map<String, String> unusedProperties)
  267. {
  268. ColumnPrinter columnPrinter = makePrinterForConfiguration(configurationFactory);
  269. try (PrintWriter out = new PrintWriter(new LoggingWriter(log, Type.INFO))) {
  270. columnPrinter.print(out);
  271. }
  272. // Warn about unused properties
  273. if (!unusedProperties.isEmpty()) {
  274. log.warn("UNUSED PROPERTIES");
  275. for (Entry<String, String> unusedProperty : unusedProperties.entrySet()) {
  276. log.warn("%s=%s", unusedProperty.getKey(), unusedProperty.getValue());
  277. }
  278. log.warn("");
  279. }
  280. }
  281. private ColumnPrinter makePrinterForConfiguration(ConfigurationFactory configurationFactory)
  282. {
  283. ConfigurationInspector configurationInspector = new ConfigurationInspector();
  284. ColumnPrinter columnPrinter = new ColumnPrinter();
  285. columnPrinter.addColumn(PROPERTY_NAME_COLUMN);
  286. columnPrinter.addColumn(DEFAULT_VALUE_COLUMN);
  287. columnPrinter.addColumn(CURRENT_VALUE_COLUMN);
  288. columnPrinter.addColumn(DESCRIPTION_COLUMN);
  289. for (ConfigRecord<?> record : configurationInspector.inspect(configurationFactory)) {
  290. for (ConfigAttribute attribute : record.getAttributes()) {
  291. columnPrinter.addValue(PROPERTY_NAME_COLUMN, attribute.getPropertyName());
  292. columnPrinter.addValue(DEFAULT_VALUE_COLUMN, attribute.getDefaultValue());
  293. columnPrinter.addValue(CURRENT_VALUE_COLUMN, attribute.getCurrentValue());
  294. columnPrinter.addValue(DESCRIPTION_COLUMN, attribute.getDescription());
  295. }
  296. }
  297. return columnPrinter;
  298. }
  299. }