All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.airlift.bootstrap.Bootstrap Maven / Gradle / Ivy

There is a newer version: 297
Show newest version
/*
 * Copyright 2010 Proofpoint, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package io.airlift.bootstrap;

import com.google.common.annotations.Beta;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableList.Builder;
import com.google.common.collect.ImmutableSortedMap;
import com.google.common.collect.Maps;
import com.google.inject.Binder;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Module;
import com.google.inject.Stage;
import com.google.inject.spi.Message;
import io.airlift.bootstrap.LoggingWriter.Type;
import io.airlift.configuration.ConfigurationFactory;
import io.airlift.configuration.ConfigurationInspector;
import io.airlift.configuration.ConfigurationInspector.ConfigAttribute;
import io.airlift.configuration.ConfigurationInspector.ConfigRecord;
import io.airlift.configuration.ConfigurationLoader;
import io.airlift.configuration.ConfigurationModule;
import io.airlift.configuration.ValidationErrorModule;
import io.airlift.configuration.WarningsMonitor;
import io.airlift.log.Logger;
import io.airlift.log.Logging;
import io.airlift.log.LoggingConfiguration;

import java.io.PrintWriter;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.SortedMap;
import java.util.TreeMap;

import static com.google.common.collect.Maps.fromProperties;
import static io.airlift.configuration.Configuration.processConfiguration;

/**
 * Entry point for an application built using the platform codebase.
 * 

* This class will: *

    *
  • load, validate and bind configurations
  • *
  • initialize logging
  • *
  • set up bootstrap management
  • *
  • create an Guice injector
  • *
*/ public class Bootstrap { private final Logger log = Logger.get("Bootstrap"); private final List modules; private Map requiredConfigurationProperties; private Map optionalConfigurationProperties; private boolean initializeLogging = true; private boolean quiet; private boolean strictConfig; private boolean requireExplicitBindings = true; private boolean initialized; public Bootstrap(Module... modules) { this(ImmutableList.copyOf(modules)); } public Bootstrap(Iterable modules) { this.modules = ImmutableList.copyOf(modules); } @Beta public Bootstrap setRequiredConfigurationProperty(String key, String value) { if (this.requiredConfigurationProperties == null) { this.requiredConfigurationProperties = new TreeMap<>(); } this.requiredConfigurationProperties.put(key, value); return this; } @Beta public Bootstrap setRequiredConfigurationProperties(Map requiredConfigurationProperties) { if (this.requiredConfigurationProperties == null) { this.requiredConfigurationProperties = new TreeMap<>(); } this.requiredConfigurationProperties.putAll(requiredConfigurationProperties); return this; } @Beta public Bootstrap setOptionalConfigurationProperty(String key, String value) { if (this.optionalConfigurationProperties == null) { this.optionalConfigurationProperties = new TreeMap<>(); } this.optionalConfigurationProperties.put(key, value); return this; } @Beta public Bootstrap setOptionalConfigurationProperties(Map optionalConfigurationProperties) { if (this.optionalConfigurationProperties == null) { this.optionalConfigurationProperties = new TreeMap<>(); } this.optionalConfigurationProperties.putAll(optionalConfigurationProperties); return this; } @Beta public Bootstrap doNotInitializeLogging() { this.initializeLogging = false; return this; } public Bootstrap quiet() { this.quiet = true; return this; } public Bootstrap strictConfig() { this.strictConfig = true; return this; } @SuppressWarnings("unused") public Bootstrap requireExplicitBindings(boolean requireExplicitBindings) { this.requireExplicitBindings = requireExplicitBindings; return this; } public Injector initialize() throws Exception { Preconditions.checkState(!initialized, "Already initialized"); initialized = true; Logging logging = null; if (initializeLogging) { logging = Logging.initialize(); } Thread.currentThread().setUncaughtExceptionHandler((thread, throwable) -> log.error(throwable, "Uncaught exception in thread %s", thread.getName())); Map requiredProperties; ConfigurationFactory configurationFactory; if (requiredConfigurationProperties == null) { // initialize configuration log.info("Loading configuration"); ConfigurationLoader loader = new ConfigurationLoader(); requiredProperties = Collections.emptyMap(); String configFile = System.getProperty("config"); if (configFile != null) { requiredProperties = loader.loadPropertiesFrom(configFile); } } else { requiredProperties = requiredConfigurationProperties; } SortedMap properties = Maps.newTreeMap(); if (optionalConfigurationProperties != null) { properties.putAll(optionalConfigurationProperties); } properties.putAll(requiredProperties); properties.putAll(fromProperties(System.getProperties())); properties = ImmutableSortedMap.copyOf(properties); configurationFactory = new ConfigurationFactory(properties); if (logging != null) { // initialize logging log.info("Initializing logging"); LoggingConfiguration configuration = configurationFactory.build(LoggingConfiguration.class); logging.configure(configuration); } // Validate configuration List messages = processConfiguration(configurationFactory, log::warn, modules); // at this point all config file properties should be used // so we can calculate the unused properties TreeMap unusedProperties = new TreeMap<>(); unusedProperties.putAll(requiredProperties); unusedProperties.keySet().removeAll(configurationFactory.getUsedProperties()); // Log effective configuration if (!quiet) { logConfiguration(configurationFactory, unusedProperties); } // system modules Builder moduleList = ImmutableList.builder(); moduleList.add(new LifeCycleModule()); moduleList.add(new ConfigurationModule(configurationFactory)); if (!messages.isEmpty()) { moduleList.add(new ValidationErrorModule(messages)); } moduleList.add(binder -> binder.bind(WarningsMonitor.class).toInstance(log::warn)); // disable broken Guice "features" moduleList.add(Binder::disableCircularProxies); if (requireExplicitBindings) { moduleList.add(Binder::requireExplicitBindings); } // todo this should be part of the ValidationErrorModule if (strictConfig) { moduleList.add(binder -> { for (Entry unusedProperty : unusedProperties.entrySet()) { binder.addError("Configuration property '%s=%s' was not used", unusedProperty.getKey(), unusedProperty.getValue()); } }); } moduleList.addAll(modules); // create the injector Injector injector = Guice.createInjector(Stage.PRODUCTION, moduleList.build()); // Create the life-cycle manager LifeCycleManager lifeCycleManager = injector.getInstance(LifeCycleManager.class); // Start services if (lifeCycleManager.size() > 0) { lifeCycleManager.start(); } return injector; } private static final String PROPERTY_NAME_COLUMN = "PROPERTY"; private static final String DEFAULT_VALUE_COLUMN = "DEFAULT"; private static final String CURRENT_VALUE_COLUMN = "RUNTIME"; private static final String DESCRIPTION_COLUMN = "DESCRIPTION"; private void logConfiguration(ConfigurationFactory configurationFactory, Map unusedProperties) { ColumnPrinter columnPrinter = makePrinterForConfiguration(configurationFactory); try (PrintWriter out = new PrintWriter(new LoggingWriter(log, Type.INFO))) { columnPrinter.print(out); } // Warn about unused properties if (!unusedProperties.isEmpty()) { log.warn("UNUSED PROPERTIES"); for (Entry unusedProperty : unusedProperties.entrySet()) { log.warn("%s=%s", unusedProperty.getKey(), unusedProperty.getValue()); } log.warn(""); } } private static ColumnPrinter makePrinterForConfiguration(ConfigurationFactory configurationFactory) { ConfigurationInspector configurationInspector = new ConfigurationInspector(); ColumnPrinter columnPrinter = new ColumnPrinter(); columnPrinter.addColumn(PROPERTY_NAME_COLUMN); columnPrinter.addColumn(DEFAULT_VALUE_COLUMN); columnPrinter.addColumn(CURRENT_VALUE_COLUMN); columnPrinter.addColumn(DESCRIPTION_COLUMN); for (ConfigRecord record : configurationInspector.inspect(configurationFactory)) { for (ConfigAttribute attribute : record.getAttributes()) { columnPrinter.addValue(PROPERTY_NAME_COLUMN, attribute.getPropertyName()); columnPrinter.addValue(DEFAULT_VALUE_COLUMN, attribute.getDefaultValue()); columnPrinter.addValue(CURRENT_VALUE_COLUMN, attribute.getCurrentValue()); columnPrinter.addValue(DESCRIPTION_COLUMN, attribute.getDescription()); } } return columnPrinter; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy