Package org.sonatype.nexus.configuration.source

Source Code of org.sonatype.nexus.configuration.source.FileConfigurationSource

/*
* Sonatype Nexus (TM) Open Source Version
* Copyright (c) 2007-2014 Sonatype, Inc.
* All rights reserved. Includes the third-party code listed at http://links.sonatype.com/products/nexus/oss/attributions.
*
* This program and the accompanying materials are made available under the terms of the Eclipse Public License Version 1.0,
* which accompanies this distribution and is available at http://www.eclipse.org/legal/epl-v10.html.
*
* Sonatype Nexus (TM) Professional Version is available from Sonatype, Inc. "Sonatype" and "Sonatype Nexus" are trademarks
* of Sonatype, Inc. Apache Maven is a trademark of the Apache Software Foundation. M2eclipse is a trademark of the
* Eclipse Foundation. All other trademarks are the property of their respective owners.
*/
package org.sonatype.nexus.configuration.source;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;

import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Provider;
import javax.inject.Singleton;

import org.sonatype.configuration.ConfigurationException;
import org.sonatype.configuration.validation.InvalidConfigurationException;
import org.sonatype.configuration.validation.ValidationMessage;
import org.sonatype.configuration.validation.ValidationRequest;
import org.sonatype.configuration.validation.ValidationResponse;
import org.sonatype.nexus.SystemStatus;
import org.sonatype.nexus.configuration.ApplicationInterpolatorProvider;
import org.sonatype.nexus.configuration.application.upgrade.ApplicationConfigurationUpgrader;
import org.sonatype.nexus.configuration.model.Configuration;
import org.sonatype.nexus.configuration.model.ConfigurationHelper;
import org.sonatype.nexus.configuration.model.io.xpp3.NexusConfigurationXpp3Writer;
import org.sonatype.nexus.configuration.validator.ApplicationConfigurationValidator;
import org.sonatype.nexus.configuration.validator.ConfigurationValidator;
import org.sonatype.nexus.util.file.DirSupport;
import org.sonatype.security.events.SecurityConfigurationChanged;
import org.sonatype.sisu.goodies.common.io.FileReplacer;
import org.sonatype.sisu.goodies.common.io.FileReplacer.ContentWriter;
import org.sonatype.sisu.goodies.eventbus.EventBus;

import static com.google.common.base.Preconditions.checkNotNull;

/**
* The default configuration source powered by Modello. It will try to load configuration, upgrade if needed and
* validate it. It also holds the one and only existing Configuration object.
*
* @author cstamas
*/
@Singleton
@Named("file")
public class FileConfigurationSource
    extends AbstractApplicationConfigurationSource
{

  private final EventBus eventBus;

  private final Provider<SystemStatus> systemStatusProvider;

  /**
   * The configuration file.
   */
  private final File configurationFile;

  /**
   * The configuration validator.
   */
  private final ApplicationConfigurationValidator configurationValidator;

  /**
   * The configuration upgrader.
   */
  private final ApplicationConfigurationUpgrader configurationUpgrader;

  /**
   * The nexus defaults configuration source.
   */
  private final ApplicationConfigurationSource nexusDefaults;

  private final ConfigurationHelper configHelper;

  /**
   * Flag to mark defaulted config
   */
  private boolean configurationDefaulted;

  @Inject
  public FileConfigurationSource(final ApplicationInterpolatorProvider interpolatorProvider,
                                 final EventBus eventBus,
                                 final Provider<SystemStatus> systemStatusProvider,
                                 final @Named("${nexus-work}/etc/nexus.xml") File configurationFile,
                                 final ApplicationConfigurationValidator configurationValidator,
                                 final ApplicationConfigurationUpgrader configurationUpgrader,
                                 final @Named("static") ApplicationConfigurationSource nexusDefaults,
                                 final ConfigurationHelper configHelper)
  {
    super(interpolatorProvider);
    this.eventBus = checkNotNull(eventBus);
    this.systemStatusProvider = checkNotNull(systemStatusProvider);
    this.configurationFile = checkNotNull(configurationFile);
    this.configurationValidator = checkNotNull(configurationValidator);
    this.configurationUpgrader = checkNotNull(configurationUpgrader);
    this.nexusDefaults = checkNotNull(nexusDefaults);
    this.configHelper = checkNotNull(configHelper);
  }

  /**
   * Gets the configuration validator.
   *
   * @return the configuration validator
   */
  public ConfigurationValidator getConfigurationValidator() {
    return configurationValidator;
  }

  /**
   * Gets the configuration file.
   *
   * @return the configuration file
   */
  public File getConfigurationFile() {
    return configurationFile;
  }

  @Override
  public Configuration loadConfiguration()
      throws ConfigurationException, IOException
  {
    // propagate call and fill in defaults too
    nexusDefaults.loadConfiguration();

    if (getConfigurationFile() == null || getConfigurationFile().getAbsolutePath().contains("${")) {
      throw new ConfigurationException("The configuration file is not set or resolved properly: "
          + getConfigurationFile().getAbsolutePath());
    }

    if (!getConfigurationFile().exists()) {
      log.warn("No configuration file in place, copying the default one and continuing with it.");

      // get the defaults and stick it to place
      setConfiguration(nexusDefaults.getConfiguration());

      saveConfiguration(getConfigurationFile());

      configurationDefaulted = true;
    }
    else {
      configurationDefaulted = false;
    }

    try {
      loadConfiguration(getConfigurationFile());

      // was able to load configuration w/o upgrading it
      setConfigurationUpgraded(false);
    }
    catch (ConfigurationException e) {
      log.info("Configuration file is outdated, begin upgrade");

      upgradeConfiguration(getConfigurationFile());

      // had to upgrade configuration before I was able to load it
      setConfigurationUpgraded(true);

      loadConfiguration(getConfigurationFile());

      // if the configuration is upgraded we need to reload the security.
      // it would be great if this was put somewhere else, but I am out of ideas.
      // the problem is the default security was already loaded with the security-system component was loaded
      // so it has the defaults, the upgrade from 1.0.8 -> 1.4 moves security out of the nexus.xml
      // and we cannot use the 'correct' way of updating the info, because that would cause an infinit loop
      // loading the nexus.xml
      this.eventBus.post(new SecurityConfigurationChanged());
    }

    upgradeNexusVersion();

    ValidationResponse vResponse =
        getConfigurationValidator().validateModel(new ValidationRequest(getConfiguration()));

    dumpValidationErrors(vResponse);

    setValidationResponse(vResponse);

    if (vResponse.isValid()) {
      if (vResponse.isModified()) {
        log.info("Validation has modified the configuration, storing the changes.");

        storeConfiguration();
      }

      return getConfiguration();
    }
    else {
      throw new InvalidConfigurationException(vResponse);
    }
  }

  protected void dumpValidationErrors(final ValidationResponse response) {
    // summary
    if (response.getValidationErrors().size() > 0 || response.getValidationWarnings().size() > 0) {
      log.error("* * * * * * * * * * * * * * * * * * * * * * * * * *");

      log.error("Nexus configuration has validation errors/warnings");

      log.error("* * * * * * * * * * * * * * * * * * * * * * * * * *");

      if (response.getValidationErrors().size() > 0) {
        log.error("The ERRORS:");

        for (ValidationMessage msg : response.getValidationErrors()) {
          log.error(msg.toString());
        }
      }

      if (response.getValidationWarnings().size() > 0) {
        log.error("The WARNINGS:");

        for (ValidationMessage msg : response.getValidationWarnings()) {
          log.error(msg.toString());
        }
      }

      log.error("* * * * * * * * * * * * * * * * * * * * *");
    }
    else {
      log.info("Nexus configuration validated successfully.");
    }
  }

  protected void upgradeNexusVersion()
      throws IOException
  {
    final String currentVersion = checkNotNull(systemStatusProvider.get().getVersion());
    final String previousVersion = getConfiguration().getNexusVersion();
    if (currentVersion.equals(previousVersion)) {
      setInstanceUpgraded(false);
    }
    else {
      setInstanceUpgraded(true);
      getConfiguration().setNexusVersion(currentVersion);
      storeConfiguration();
    }

  }

  @Override
  public void storeConfiguration()
      throws IOException
  {
    saveConfiguration(getConfigurationFile());
  }

  @Override
  public InputStream getConfigurationAsStream()
      throws IOException
  {
    return new FileInputStream(getConfigurationFile());
  }

  @Override
  public ApplicationConfigurationSource getDefaultsSource() {
    return nexusDefaults;
  }

  protected void upgradeConfiguration(File file)
      throws IOException, ConfigurationException
  {
    log.info("Trying to upgrade the configuration file " + file.getAbsolutePath());

    setConfiguration(configurationUpgrader.loadOldConfiguration(file));

    // after all we should have a configuration
    if (getConfiguration() == null) {
      throw new ConfigurationException("Could not upgrade Nexus configuration! Please replace the "
          + file.getAbsolutePath() + " file with a valid Nexus configuration file.");
    }

    log.info("Creating backup from the old file and saving the upgraded configuration.");

    backupConfiguration();

    saveConfiguration(file);
  }

  /**
   * Load configuration.
   *
   * @param file the file
   * @return the configuration
   * @throws IOException Signals that an I/O exception has occurred.
   */
  private void loadConfiguration(File file)
      throws IOException, ConfigurationException
  {
    log.debug("Loading Nexus configuration from " + file.getAbsolutePath());

    FileInputStream fis = null;
    try {
      fis = new FileInputStream(file);

      loadConfiguration(fis);

      // seems a bit dirty, but the config might need to be upgraded.
      if (this.getConfiguration() != null) {
        // decrypt the passwords
        setConfiguration(configHelper.encryptDecryptPasswords(getConfiguration(), false));
      }
    }
    finally {
      if (fis != null) {
        fis.close();
      }
    }
  }

  /**
   * Save configuration.
   *
   * @param file the file
   * @throws IOException Signals that an I/O exception has occurred.
   */
  private void saveConfiguration(final File file)
      throws IOException
  {
    // Create the dir if doesn't exist, throw runtime exception on failure
    // bad bad bad
    try {
      DirSupport.mkdir(file.getParentFile().toPath());
    }
    catch (IOException e) {
      String message =
          "\r\n******************************************************************************\r\n"
              + "* Could not create configuration file [ " + file.toString() + "]!!!! *\r\n"
              + "* Nexus cannot start properly until the process has read+write permissions to this folder *\r\n"
              + "******************************************************************************";

      log.error(message, e);
      throw new IOException("Could not create configuration file " + file.getAbsolutePath(), e);
    }

    // Clone the conf so we can encrypt the passwords
    final Configuration configuration = configHelper.encryptDecryptPasswords(getConfiguration(), true);
    log.debug("Saving configuration: {}", file);
    final FileReplacer fileReplacer = new FileReplacer(file);
    // we save this file many times, don't litter backups
    fileReplacer.setDeleteBackupFile(true);
    fileReplacer.replace(new ContentWriter()
    {
      @Override
      public void write(final BufferedOutputStream output)
          throws IOException
      {
        new NexusConfigurationXpp3Writer().write(output, configuration);
      }
    });
  }

  /**
   * Was the active configuration fetched from config file or from default source? True if it from default source.
   */
  @Override
  public boolean isConfigurationDefaulted() {
    return configurationDefaulted;
  }

  @Override
  public void backupConfiguration()
      throws IOException
  {
    File file = getConfigurationFile();

    // backup the file
    File backup = new File(file.getParentFile(), file.getName() + ".bak");
    Files.copy(file.toPath(), backup.toPath(), StandardCopyOption.REPLACE_EXISTING);
  }
}
TOP

Related Classes of org.sonatype.nexus.configuration.source.FileConfigurationSource

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.