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    
019    package org.apache.hadoop.lib.util;
020    
021    import org.apache.hadoop.classification.InterfaceAudience;
022    import org.apache.hadoop.conf.Configuration;
023    import org.w3c.dom.DOMException;
024    import org.w3c.dom.Document;
025    import org.w3c.dom.Element;
026    import org.w3c.dom.Node;
027    import org.w3c.dom.NodeList;
028    import org.w3c.dom.Text;
029    import org.xml.sax.SAXException;
030    
031    import javax.xml.parsers.DocumentBuilder;
032    import javax.xml.parsers.DocumentBuilderFactory;
033    import javax.xml.parsers.ParserConfigurationException;
034    import java.io.IOException;
035    import java.io.InputStream;
036    import java.util.Map;
037    
038    /**
039     * Configuration utilities.
040     */
041    @InterfaceAudience.Private
042    public abstract class ConfigurationUtils {
043    
044      /**
045       * Copy configuration key/value pairs from one configuration to another if a property exists in the target, it gets
046       * replaced.
047       *
048       * @param source source configuration.
049       * @param target target configuration.
050       */
051      public static void copy(Configuration source, Configuration target) {
052        Check.notNull(source, "source");
053        Check.notNull(target, "target");
054        for (Map.Entry<String, String> entry : source) {
055          target.set(entry.getKey(), entry.getValue());
056        }
057      }
058    
059      /**
060       * Injects configuration key/value pairs from one configuration to another if the key does not exist in the target
061       * configuration.
062       *
063       * @param source source configuration.
064       * @param target target configuration.
065       */
066      public static void injectDefaults(Configuration source, Configuration target) {
067        Check.notNull(source, "source");
068        Check.notNull(target, "target");
069        for (Map.Entry<String, String> entry : source) {
070          if (target.get(entry.getKey()) == null) {
071            target.set(entry.getKey(), entry.getValue());
072          }
073        }
074      }
075    
076      /**
077       * Returns a new ConfigurationUtils instance with all inline values resolved.
078       *
079       * @return a new ConfigurationUtils instance with all inline values resolved.
080       */
081      public static Configuration resolve(Configuration conf) {
082        Configuration resolved = new Configuration(false);
083        for (Map.Entry<String, String> entry : conf) {
084          resolved.set(entry.getKey(), conf.get(entry.getKey()));
085        }
086        return resolved;
087      }
088    
089      // Canibalized from FileSystemAccess <code>Configuration.loadResource()</code>.
090    
091      /**
092       * Create a configuration from an InputStream.
093       * <p/>
094       * ERROR canibalized from <code>Configuration.loadResource()</code>.
095       *
096       * @param is inputstream to read the configuration from.
097       *
098       * @throws IOException thrown if the configuration could not be read.
099       */
100      public static void load(Configuration conf, InputStream is) throws IOException {
101        try {
102          DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
103          // ignore all comments inside the xml file
104          docBuilderFactory.setIgnoringComments(true);
105          DocumentBuilder builder = docBuilderFactory.newDocumentBuilder();
106          Document doc = builder.parse(is);
107          parseDocument(conf, doc);
108        } catch (SAXException e) {
109          throw new IOException(e);
110        } catch (ParserConfigurationException e) {
111          throw new IOException(e);
112        }
113      }
114    
115      // Canibalized from FileSystemAccess <code>Configuration.loadResource()</code>.
116      private static void parseDocument(Configuration conf, Document doc) throws IOException {
117        try {
118          Element root = doc.getDocumentElement();
119          if (!"configuration".equals(root.getTagName())) {
120            throw new IOException("bad conf file: top-level element not <configuration>");
121          }
122          NodeList props = root.getChildNodes();
123          for (int i = 0; i < props.getLength(); i++) {
124            Node propNode = props.item(i);
125            if (!(propNode instanceof Element)) {
126              continue;
127            }
128            Element prop = (Element) propNode;
129            if (!"property".equals(prop.getTagName())) {
130              throw new IOException("bad conf file: element not <property>");
131            }
132            NodeList fields = prop.getChildNodes();
133            String attr = null;
134            String value = null;
135            for (int j = 0; j < fields.getLength(); j++) {
136              Node fieldNode = fields.item(j);
137              if (!(fieldNode instanceof Element)) {
138                continue;
139              }
140              Element field = (Element) fieldNode;
141              if ("name".equals(field.getTagName()) && field.hasChildNodes()) {
142                attr = ((Text) field.getFirstChild()).getData().trim();
143              }
144              if ("value".equals(field.getTagName()) && field.hasChildNodes()) {
145                value = ((Text) field.getFirstChild()).getData();
146              }
147            }
148    
149            if (attr != null && value != null) {
150              conf.set(attr, value);
151            }
152          }
153    
154        } catch (DOMException e) {
155          throw new IOException(e);
156        }
157      }
158    
159    }