blob: cf5a6783f6fa9e1416c69e7968b76481b5b71a7e [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.ambari.server.stack;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.xml.bind.JAXBException;
import javax.xml.bind.UnmarshalException;
import javax.xml.namespace.QName;
import org.apache.ambari.server.state.ConfigHelper;
import org.apache.ambari.server.state.PropertyInfo;
import org.apache.ambari.server.state.stack.ConfigurationXml;
import org.apache.ambari.server.utils.JsonUtils;
import org.apache.ambari.server.utils.XmlUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.SAXParseException;
/**
* Encapsulates IO operations on a stack definition configuration directory.
*/
public class ConfigurationDirectory extends StackDefinitionDirectory {
/**
* Used to unmarshal a stack definition configuration to an object representation
*/
private static ModuleFileUnmarshaller unmarshaller = new ModuleFileUnmarshaller();
/**
* Map of configuration type to configuration module.
* One entry for each configuration file in this configuration directory.
*/
private Map<String, ConfigurationModule> configurationModules = new HashMap<>();
/**
* Logger instance
*/
private final static Logger LOG = LoggerFactory.getLogger(ConfigurationDirectory.class);
/**
* Properties directory
*/
protected File propertiesDirFile;
/**
* Constructor.
*
* @param directoryName configuration directory name
*/
public ConfigurationDirectory(String directoryName, String propertiesDirectoryName) {
super(directoryName);
if(!StringUtils.isBlank(propertiesDirectoryName)) {
propertiesDirFile = new File(propertiesDirectoryName);
}
parsePath();
}
/**
* Obtain a collection of of configuration modules representing each configuration
* file contained in this configuration directory.
*
* @return collection of configuration modules
*/
public Collection<ConfigurationModule> getConfigurationModules() {
return configurationModules.values();
}
/**
* Parse the configuration directory.
*/
private void parsePath() {
File[] configFiles = directory.listFiles(StackDirectory.FILENAME_FILTER);
if (configFiles != null) {
for (File configFile : configFiles) {
if (configFile.getName().endsWith(StackDirectory.SERVICE_CONFIG_FILE_NAME_POSTFIX)) {
String configType = ConfigHelper.fileNameToConfigType(configFile.getName());
ConfigurationXml config = null;
try {
config = unmarshaller.unmarshal(ConfigurationXml.class, configFile);
ConfigurationInfo configInfo = new ConfigurationInfo(parseProperties(config,
configFile.getName()), parseAttributes(config));
ConfigurationModule module = new ConfigurationModule(configType, configInfo);
configurationModules.put(configType, module);
} catch (Exception e) {
String error = null;
if (e instanceof JAXBException || e instanceof UnmarshalException || e instanceof SAXParseException) {
error = "Could not parse XML " + configFile + ": " + e;
} else {
error = "Could not load configuration for " + configFile;
}
config = new ConfigurationXml();
config.setValid(false);
config.addError(error);
ConfigurationInfo configInfo = new ConfigurationInfo(parseProperties(config,
configFile.getName()), parseAttributes(config));
configInfo.setValid(false);
configInfo.addError(error);
ConfigurationModule module = new ConfigurationModule(configType, configInfo);
configurationModules.put(configType, module);
}
}
}
}
}
/**
* Parse a configurations properties.
*
* @param configuration object representation of a configuration file
* @param fileName configuration file name
*
* @return collection of properties
*/
private Collection<PropertyInfo> parseProperties(ConfigurationXml configuration, String fileName) {
List<PropertyInfo> props = new ArrayList<>();
for (PropertyInfo pi : configuration.getProperties()) {
pi.setFilename(fileName);
if(pi.getPropertyTypes().contains(PropertyInfo.PropertyType.VALUE_FROM_PROPERTY_FILE)) {
if(propertiesDirFile != null && propertiesDirFile.exists() && propertiesDirFile.isDirectory() ) {
String propertyFileName = pi.getPropertyValueAttributes().getPropertyFileName();
String propertyFileType = pi.getPropertyValueAttributes().getPropertyFileType();
String propertyFilePath = propertiesDirFile.getAbsolutePath() + File.separator + propertyFileName;
File propertyFile = new File(propertyFilePath);
if (propertyFile.exists() && propertyFile.isFile()) {
try {
String propertyValue = FileUtils.readFileToString(propertyFile);
boolean valid = true;
switch (propertyFileType.toLowerCase()) {
case "xml" :
if (!XmlUtils.isValidXml(propertyValue)) {
valid = false;
LOG.error("Failed to load value from property file. Property file {} is not a valid XML file", propertyFilePath);
}
break;
case "json":
if (!JsonUtils.isValidJson(propertyValue)) {
valid = false;
LOG.error("Failed to load value from property file. Property file {} is not a valid JSON file", propertyFilePath);
}
break;
case "text":
// fallthrough
default:
// no validity check
break;
}
if (valid) {
pi.setValue(propertyValue);
}
} catch (IOException e) {
LOG.error("Failed to load value from property file {}. Error Message {}", propertyFilePath, e.getMessage());
}
} else {
LOG.error("Failed to load value from property file. Properties file {} does not exist", propertyFilePath);
}
} else {
LOG.error("Failed to load value from property file. Properties directory {} does not exist", propertiesDirFile.getAbsolutePath());
}
}
props.add(pi);
}
return props; }
/**
* Parse a configurations type attributes.
*
* @param configuration object representation of a configuration file
*
* @return collection of attributes for the configuration type
*/
private Map<String, String> parseAttributes(ConfigurationXml configuration) {
Map<String, String> attributes = new HashMap<>();
for (Map.Entry<QName, String> attribute : configuration.getAttributes().entrySet()) {
attributes.put(attribute.getKey().getLocalPart(), attribute.getValue());
}
return attributes;
}
}