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 }