| /* |
| * 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; |
| } |
| } |