Package com.opengamma.component

Source Code of com.opengamma.component.ComponentConfigIniLoader

/**
* Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.component;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang.StringUtils;
import org.springframework.core.io.Resource;

import com.opengamma.OpenGammaRuntimeException;
import com.opengamma.util.ArgumentChecker;
import com.opengamma.util.ResourceUtils;

/**
* Loads configuration from the INI format file.
* <p>
* The format is line-based as follows:<br>
<code>#</code> or <code>;</code> for comment lines (at the start of the line)<br>
<code>${key}</code> is replaced by an earlier replacement declaration<br>
<code>[group]</code> defines the start of a named group of configs<br>
<code>key = value</code> defines a single config element within a group<br>
<code>MANAGER.INCLUDE = resource</code> declares a resource to be included immediately<br>
*  the "global" group is used to add keys to the set of properties used for replacement<br>
*  Everything is trimmed as necessary.
<p>
*  The specified properties are used in two ways.
*  Firstly, they are used to substitute sections that have defined the '<code>${key}</code>' notation.
*  Secondly, they can directly override properties in an INI group, if the property has a
*  key of the format '{@code [group].key}'.
*/
public class ComponentConfigIniLoader extends AbstractComponentConfigLoader {

  /**
   * The pattern to match [group].key
   */
  private static final Pattern GROUP_OVERRIDE = Pattern.compile("\\[" + "([^\\]]+)" + "\\]" + "[.]" + "(.+)");

  /**
   * Creates an instance.
   *
   * @param logger  the logger, not null
   * @param properties  the properties in use, not null
   */
  public ComponentConfigIniLoader(ComponentLogger logger, ConcurrentMap<String, String> properties) {
    super(logger, properties);
  }

  //-------------------------------------------------------------------------
  /**
   * Loads the INI file.
   * <p>
   * Loads the configuration defining components from the specified resource.
   *
   * @param resource  the config resource to load, not null
   * @param depth  the depth of the properties file, used for logging
   * @param config  the config being loaded, not null
   */
  public void load(final Resource resource, final int depth, final ComponentConfig config) {
    ArgumentChecker.notNull(resource, "resource");
    ArgumentChecker.notNull(config, "config");
    try {
      doLoad(resource, depth, config);
      overrideProperties(config);
     
    } catch (RuntimeException ex) {
      throw new OpenGammaRuntimeException("Unable to load INI file: " + resource, ex);
    }
  }

  /**
   * Loads the INI file.
   * <p>
   * Loads the configuration defining components from the specified resource.
   *
   * @param resource  the config resource to load, not null
   * @param depth  the depth of the properties file, used for logging
   * @param config  the config being loaded, not null
   * @return the config, not null
   */
  private void doLoad(final Resource resource, final int depth, final ComponentConfig config) {
    List<String> lines = readLines(resource);
    String group = null;
    int lineNum = 0;
    for (String line : lines) {
      lineNum++;
      line = line.trim();
      if (line.length() == 0 || line.startsWith("#") || line.startsWith(";")) {
        continue;
      }
      if (line.startsWith("[") && line.endsWith("]")) {
        group = line.substring(1, line.length() - 1);
       
      } else if (group == null) {
        throw new OpenGammaRuntimeException("Invalid format, properties must be specified within a [group], line " + lineNum);
       
      } else {
        int equalsPosition = line.indexOf('=');
        if (equalsPosition < 0) {
          throw new OpenGammaRuntimeException("Invalid format, line " + lineNum);
        }
        String key = line.substring(0, equalsPosition).trim();
        String value = line.substring(equalsPosition + 1).trim();
        if (key.length() == 0) {
          throw new IllegalArgumentException("Invalid empty key, line " + lineNum);
        }
        if (config.contains(group, key)) {
          throw new IllegalArgumentException("Invalid file, key '" + key + "' specified twice, line " + lineNum);
        }
       
        // resolve ${} references
        value = resolveProperty(value, lineNum);
       
        // handle includes
        if (key.equals(ComponentManager.MANAGER_INCLUDE)) {
          handleInclude(resource, value, depth, config);
        } else {
          // store property
          config.put(group, key, value);
          if (group.equals("global")) {
            getProperties().put(key, value);
          }
        }
      }
    }
  }

  /**
   * Handle the inclusion of another file.
   *
   * @param baseResource  the base resource, not null
   * @param includeFile  the resource to include, not null
   * @param depth  the depth of the properties file, used for logging
   * @param config  the config being loaded, not null
   */
  private void handleInclude(final Resource baseResource, String includeFile, final int depth, final ComponentConfig config) {
    // find resource
    Resource include;
    try {
      include = ResourceUtils.createResource(includeFile);
    } catch (Exception ex) {
      try {
        include = baseResource.createRelative(includeFile);
      } catch (Exception ex2) {
        throw new OpenGammaRuntimeException(ex2.getMessage(), ex2);
      }
    }
   
    // load and merge
    getLogger().logInfo(StringUtils.repeat(" ", depth) + "   Including item: " + ResourceUtils.getLocation(include));
    try {
      doLoad(include, depth + 1, config);
    } catch (RuntimeException ex) {
      throw new OpenGammaRuntimeException("Unable to load INI file: " + include, ex);
    }
  }

  //-------------------------------------------------------------------------
  /**
   * Override config using the properties.
   * <p>
   * Any property that has a key of the form '[group].key' will replace the
   * specified key within the group.
   *
   * @param config  the config to update, not null
   */
  private void overrideProperties(final ComponentConfig config) {
    List<String[]> iniProperties = extractIniOverrideProperties();
    for (String[] array : iniProperties) {
      config.getGroup(array[0])// validate group (but returns a copy of the inner map)
      config.put(array[0], array[1], array[2]);
      getLogger().logDebug("  Replacing group property: [" + array[0] + "]." + array[1] + "=" + array[2]);
    }
  }

  /**
   * Extracts any properties that match the group name style "[group].key".
   * <p>
   * These directly override any INI file settings.
   *
   * @return the extracted set of INI properties, not null
   */
  private List<String[]> extractIniOverrideProperties() {
    List<String[]> extracted = new ArrayList<String[]>();
    for (String key : getProperties().keySet()) {
      Matcher matcher = GROUP_OVERRIDE.matcher(key);
      if (matcher.matches()) {
        String group = matcher.group(1);
        String propertyKey = matcher.group(2);
        String[] array = {group, propertyKey, getProperties().get(key)};
        extracted.add(array);
      }
    }
    return extracted;
  }

}
TOP

Related Classes of com.opengamma.component.ComponentConfigIniLoader

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.