| /* |
| * 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.util.Collection; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.Map; |
| import java.util.Set; |
| |
| import org.apache.ambari.server.AmbariException; |
| import org.apache.ambari.server.state.PropertyInfo; |
| |
| |
| /** |
| * Configuration module which provides functionality related to parsing and fully |
| * resolving a configuration from the stack definition. Each instance is specific |
| * to a configuration type. |
| */ |
| public class ConfigurationModule extends BaseModule<ConfigurationModule, ConfigurationInfo> implements Validable{ |
| /** |
| * Configuration type |
| */ |
| private String configType; |
| |
| /** |
| * Associated configuration info |
| */ |
| ConfigurationInfo info; |
| |
| /** |
| * Specifies whether this configuration is marked as deleted |
| */ |
| private boolean isDeleted; |
| |
| /** |
| * validity flag |
| */ |
| protected boolean valid = true; |
| |
| private Set<String> errorSet = new HashSet<>(); |
| |
| @Override |
| public void addError(String error) { |
| errorSet.add(error); |
| } |
| |
| @Override |
| public Collection<String> getErrors() { |
| return errorSet; |
| } |
| |
| /** |
| * Constructor. |
| * |
| * @param configType configuration type |
| * @param info configuration info |
| */ |
| public ConfigurationModule(String configType, ConfigurationInfo info) { |
| this.configType = configType; |
| this.info = info; |
| if (info != null && !info.isValid()){ |
| setValid(info.isValid()); |
| addErrors(info.getErrors()); |
| } |
| } |
| |
| @Override |
| public void resolve(ConfigurationModule parent, Map<String, StackModule> allStacks, |
| Map<String, ServiceModule> commonServices, Map<String, ExtensionModule> extensions) throws AmbariException { |
| // merge properties also removes deleted props so should be called even if extension is disabled |
| if (parent != null) { |
| if (parent.info != null) { |
| if (!parent.isValid() || !parent.info.isValid()) { |
| setValid(false); |
| info.setValid(false); |
| addErrors(parent.getErrors()); |
| addErrors(parent.info.getErrors()); |
| info.addErrors(parent.getErrors()); |
| info.addErrors(parent.info.getErrors()); |
| } |
| } |
| |
| mergeProperties(parent); |
| |
| if (isExtensionEnabled()) { |
| mergeAttributes(parent); |
| } |
| } |
| } |
| |
| @Override |
| public ConfigurationInfo getModuleInfo() { |
| return info; |
| } |
| |
| @Override |
| public boolean isDeleted() { |
| return isDeleted; |
| } |
| |
| @Override |
| public String getId() { |
| return getConfigType(); |
| } |
| |
| /** |
| * Obtain the configuration type. |
| * |
| * @return configuration type |
| */ |
| public String getConfigType() { |
| return configType; |
| } |
| |
| |
| /** |
| * Set the deleted flag. |
| * |
| * @param isDeleted whether the configuration has been marked for deletion |
| */ |
| public void setDeleted(boolean isDeleted) { |
| this.isDeleted = isDeleted; |
| } |
| |
| /** |
| * Merge configuration properties with the configurations parent. |
| * |
| * @param parent parent configuration module |
| */ |
| private void mergeProperties(ConfigurationModule parent) { |
| Collection<String> existingProps = new HashSet<>(); |
| Iterator<PropertyInfo> iter = info.getProperties().iterator(); |
| while (iter.hasNext()) { |
| PropertyInfo prop = iter.next(); |
| existingProps.add(prop.getFilename() + "/" + prop.getName()); |
| if (prop.isDeleted()) { |
| iter.remove(); |
| } |
| } |
| |
| if (isExtensionEnabled()) { |
| for (PropertyInfo prop : parent.info.getProperties()) { |
| if (! existingProps.contains(prop.getFilename() + "/" + prop.getName())) { |
| info.getProperties().add(prop); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Merge configuration attributes with the parent configuration. |
| * |
| * @param parent parent configuration module |
| */ |
| private void mergeAttributes(ConfigurationModule parent) { |
| |
| for (Map.Entry<String, Map<String, String>> parentCategoryEntry : parent.info.getAttributes().entrySet()) { |
| String category = parentCategoryEntry.getKey(); |
| Map<String, String> categoryAttributeMap = info.getAttributes().get(category); |
| if (categoryAttributeMap == null) { |
| categoryAttributeMap = new HashMap<>(); |
| info.getAttributes().put(category, categoryAttributeMap); |
| } |
| for (Map.Entry<String, String> parentAttributeEntry : parentCategoryEntry.getValue().entrySet()) { |
| String attributeName = parentAttributeEntry.getKey(); |
| if (! categoryAttributeMap.containsKey(attributeName)) { |
| categoryAttributeMap.put(attributeName, parentAttributeEntry.getValue()); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Determine if the configuration should extend the parents configuration. |
| * |
| * @return true if this configuration should extend the parents; false otherwise |
| */ |
| //todo: is this valuable as a generic module concept? |
| private boolean isExtensionEnabled() { |
| Map<String, String> supportsMap = getModuleInfo().getAttributes().get(ConfigurationInfo.Supports.KEYWORD); |
| if (supportsMap == null) { |
| return true; |
| } |
| |
| String val = supportsMap.get(ConfigurationInfo.Supports.DO_NOT_EXTEND.getPropertyName()); |
| return val == null || val.equals("false"); |
| } |
| |
| @Override |
| public boolean isValid() { |
| return valid; |
| } |
| |
| @Override |
| public void setValid(boolean valid) { |
| this.valid = valid; |
| } |
| |
| @Override |
| public void addErrors(Collection<String> errors) { |
| this.errorSet.addAll(errors); |
| } |
| } |