001/**
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018
019package org.apache.hadoop.lib.util;
020
021import org.apache.hadoop.conf.Configuration;
022import org.w3c.dom.DOMException;
023import org.w3c.dom.Document;
024import org.w3c.dom.Element;
025import org.w3c.dom.Node;
026import org.w3c.dom.NodeList;
027import org.w3c.dom.Text;
028import org.xml.sax.SAXException;
029
030import javax.xml.parsers.DocumentBuilder;
031import javax.xml.parsers.DocumentBuilderFactory;
032import javax.xml.parsers.ParserConfigurationException;
033import java.io.IOException;
034import java.io.InputStream;
035import java.util.Map;
036
037/**
038 * Configuration utilities.
039 */
040public abstract class ConfigurationUtils {
041
042  /**
043   * Copy configuration key/value pairs from one configuration to another if a property exists in the target, it gets
044   * replaced.
045   *
046   * @param source source configuration.
047   * @param target target configuration.
048   */
049  public static void copy(Configuration source, Configuration target) {
050    Check.notNull(source, "source");
051    Check.notNull(target, "target");
052    for (Map.Entry<String, String> entry : source) {
053      target.set(entry.getKey(), entry.getValue());
054    }
055  }
056
057  /**
058   * Injects configuration key/value pairs from one configuration to another if the key does not exist in the target
059   * configuration.
060   *
061   * @param source source configuration.
062   * @param target target configuration.
063   */
064  public static void injectDefaults(Configuration source, Configuration target) {
065    Check.notNull(source, "source");
066    Check.notNull(target, "target");
067    for (Map.Entry<String, String> entry : source) {
068      if (target.get(entry.getKey()) == null) {
069        target.set(entry.getKey(), entry.getValue());
070      }
071    }
072  }
073
074  /**
075   * Returns a new ConfigurationUtils instance with all inline values resolved.
076   *
077   * @return a new ConfigurationUtils instance with all inline values resolved.
078   */
079  public static Configuration resolve(Configuration conf) {
080    Configuration resolved = new Configuration(false);
081    for (Map.Entry<String, String> entry : conf) {
082      resolved.set(entry.getKey(), conf.get(entry.getKey()));
083    }
084    return resolved;
085  }
086
087  // Canibalized from FileSystemAccess <code>Configuration.loadResource()</code>.
088
089  /**
090   * Create a configuration from an InputStream.
091   * <p/>
092   * ERROR canibalized from <code>Configuration.loadResource()</code>.
093   *
094   * @param is inputstream to read the configuration from.
095   *
096   * @throws IOException thrown if the configuration could not be read.
097   */
098  public static void load(Configuration conf, InputStream is) throws IOException {
099    try {
100      DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
101      // ignore all comments inside the xml file
102      docBuilderFactory.setIgnoringComments(true);
103      DocumentBuilder builder = docBuilderFactory.newDocumentBuilder();
104      Document doc = builder.parse(is);
105      parseDocument(conf, doc);
106    } catch (SAXException e) {
107      throw new IOException(e);
108    } catch (ParserConfigurationException e) {
109      throw new IOException(e);
110    }
111  }
112
113  // Canibalized from FileSystemAccess <code>Configuration.loadResource()</code>.
114  private static void parseDocument(Configuration conf, Document doc) throws IOException {
115    try {
116      Element root = doc.getDocumentElement();
117      if (!"configuration".equals(root.getTagName())) {
118        throw new IOException("bad conf file: top-level element not <configuration>");
119      }
120      NodeList props = root.getChildNodes();
121      for (int i = 0; i < props.getLength(); i++) {
122        Node propNode = props.item(i);
123        if (!(propNode instanceof Element)) {
124          continue;
125        }
126        Element prop = (Element) propNode;
127        if (!"property".equals(prop.getTagName())) {
128          throw new IOException("bad conf file: element not <property>");
129        }
130        NodeList fields = prop.getChildNodes();
131        String attr = null;
132        String value = null;
133        for (int j = 0; j < fields.getLength(); j++) {
134          Node fieldNode = fields.item(j);
135          if (!(fieldNode instanceof Element)) {
136            continue;
137          }
138          Element field = (Element) fieldNode;
139          if ("name".equals(field.getTagName()) && field.hasChildNodes()) {
140            attr = ((Text) field.getFirstChild()).getData().trim();
141          }
142          if ("value".equals(field.getTagName()) && field.hasChildNodes()) {
143            value = ((Text) field.getFirstChild()).getData();
144          }
145        }
146
147        if (attr != null && value != null) {
148          conf.set(attr, value);
149        }
150      }
151
152    } catch (DOMException e) {
153      throw new IOException(e);
154    }
155  }
156
157}