/* * RHQ Management Platform * Copyright 2010, Red Hat Middleware LLC, and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation version 2 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ package org.rhq.coregui.client.components.configuration; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import org.rhq.core.domain.configuration.AbstractPropertyMap; import org.rhq.core.domain.configuration.Configuration; import org.rhq.core.domain.configuration.PropertyList; import org.rhq.core.domain.configuration.PropertyMap; import org.rhq.core.domain.configuration.PropertySimple; import org.rhq.core.domain.configuration.definition.ConfigurationDefinition; import org.rhq.core.domain.configuration.definition.PropertyDefinition; import org.rhq.core.domain.configuration.definition.PropertyDefinitionList; import org.rhq.core.domain.configuration.definition.PropertyDefinitionMap; import org.rhq.core.domain.configuration.definition.PropertyDefinitionSimple; /** * @author Ian Springer */ public class AggregateConfigurationBuilder { public static Configuration buildAggregateConfiguration(List<Configuration> configurations, ConfigurationDefinition configurationDefinition) { Configuration aggregateConfiguration = new Configuration(); if (configurations.isEmpty()) { return aggregateConfiguration; } Map<String, PropertyDefinition> childPropertyDefinitions = configurationDefinition.getPropertyDefinitions(); for (PropertyDefinition childPropertyDefinition : childPropertyDefinitions.values()) { buildAggregateProperty(childPropertyDefinition, configurations, aggregateConfiguration); } return aggregateConfiguration; } private static void buildAggregateProperty(PropertyDefinition propertyDefinition, List<? extends AbstractPropertyMap> sourceParentPropertyMaps, AbstractPropertyMap targetParentPropertyMap) { if (propertyDefinition instanceof PropertyDefinitionSimple) { String sampleValue = getSimpleValue(sourceParentPropertyMaps.get(0), propertyDefinition.getName()); boolean valuesHomogeneous = true; for (int i = 1; i < sourceParentPropertyMaps.size(); i++) { String value = getSimpleValue(sourceParentPropertyMaps.get(i), propertyDefinition.getName()); if ((value == null && sampleValue != null) || (value != null && !value.equals(sampleValue))) { valuesHomogeneous = false; break; } } PropertySimple propertySimple = new PropertySimple(propertyDefinition.getName(), (valuesHomogeneous) ? sampleValue : null); targetParentPropertyMap.put(propertySimple); if (valuesHomogeneous) { // Set override to true so the config renderer will know the prop is homogeneous. propertySimple.setOverride(true); } } // If the property is a Map, recurse into it and group together its child properties. else if (propertyDefinition instanceof PropertyDefinitionMap) { List<AbstractPropertyMap> nestedSourceParentPropertyMaps = new ArrayList<AbstractPropertyMap>(); for (AbstractPropertyMap sourceParentPropertyMap : sourceParentPropertyMaps) { PropertyMap nestedSourceParentPropertyMap = sourceParentPropertyMap .getMap(propertyDefinition.getName()); nestedSourceParentPropertyMaps .add((nestedSourceParentPropertyMap != null) ? nestedSourceParentPropertyMap : new PropertyMap( propertyDefinition.getName())); } PropertyMap targetPropertyMap = new PropertyMap(propertyDefinition.getName()); targetParentPropertyMap.put(targetPropertyMap); buildAggregatePropertyMap((PropertyDefinitionMap) propertyDefinition, nestedSourceParentPropertyMaps, targetPropertyMap); } else if (propertyDefinition instanceof PropertyDefinitionList) { PropertyDefinitionList propertyDefinitionList = (PropertyDefinitionList) propertyDefinition; PropertyDefinition listMemberPropertyDefinition = propertyDefinitionList.getMemberDefinition(); PropertyList targetPropertyList = new PropertyList(propertyDefinition.getName()); targetParentPropertyMap.put(targetPropertyList); if (listMemberPropertyDefinition instanceof PropertyDefinitionMap) { PropertyDefinitionMap propertyDefinitionMap = (PropertyDefinitionMap) listMemberPropertyDefinition; // TODO: How do we group together Lists of Maps? Not trivial... } } } private static void buildAggregatePropertyMap(PropertyDefinitionMap propertyDefinitionMap, List<AbstractPropertyMap> sourceParentPropertyMaps, AbstractPropertyMap targetParentPropertyMap) { Collection<PropertyDefinition> childPropertyDefinitions = propertyDefinitionMap.getOrderedPropertyDefinitions(); if (!childPropertyDefinitions.isEmpty()) { for (PropertyDefinition childPropertyDefinition : childPropertyDefinitions) buildAggregateProperty(childPropertyDefinition, sourceParentPropertyMaps, targetParentPropertyMap); } else { buildAggregateOpenPropertyMap(sourceParentPropertyMaps, targetParentPropertyMap); } } private static void buildAggregateOpenPropertyMap(List<AbstractPropertyMap> sourceParentPropertyMaps, AbstractPropertyMap targetParentPropertyMap) { Map<String, Map<String, Integer>> memberNameValueFrequenciesMap = createMemberNameValueFrequenciesMap(sourceParentPropertyMaps); for (String memberName : memberNameValueFrequenciesMap.keySet()) { // Add each unique member to the target map, so the renderer will be able to display it on the main // config page. PropertySimple member = new PropertySimple(memberName, null); targetParentPropertyMap.put(member); // Also add it to each of the source config maps that don't already contain it, so that they can be // rendered as unset on the propSet page. for (AbstractPropertyMap map : sourceParentPropertyMaps) { if (map.get(memberName) == null) map.put(new PropertySimple(memberName, null)); } Map<String, Integer> valueFrequencies = memberNameValueFrequenciesMap.get(memberName); if (valueFrequencies.size() == 1 && valueFrequencies.values().iterator().next() == sourceParentPropertyMaps.size()) { // Set override to true so the renderers will know the prop is homogenous. member.setOverride(true); // And set the value, so it can be displayed on the main config page. member.setStringValue(valueFrequencies.keySet().iterator().next()); } } } private static Map<String, Map<String, Integer>> createMemberNameValueFrequenciesMap( List<AbstractPropertyMap> sourceParentPropertyMaps) { Map<String, Map<String, Integer>> nameValueFrequenciesMap = new HashMap<String, Map<String, Integer>>(); for (AbstractPropertyMap map : sourceParentPropertyMaps) { for (String propertyName : map.getMap().keySet()) { PropertySimple propertySimple = map.getSimple(propertyName); String propertyValue = (propertySimple != null) ? propertySimple.getStringValue() : null; Map<String, Integer> valueFrequencies = nameValueFrequenciesMap.get(propertyName); if (valueFrequencies == null) { valueFrequencies = new HashMap<String, Integer>(); nameValueFrequenciesMap.put(propertyName, valueFrequencies); } Integer valueFrequency = (valueFrequencies.containsKey(propertyValue)) ? (valueFrequencies .get(propertyValue) + 1) : 1; valueFrequencies.put(propertyValue, valueFrequency); } } return nameValueFrequenciesMap; } private static String getSimpleValue(AbstractPropertyMap parentPropertyMap, String propertyName) { PropertySimple samplePropertySimple = parentPropertyMap.getSimple(propertyName); return (samplePropertySimple != null) ? samplePropertySimple.getStringValue() : null; } private AggregateConfigurationBuilder() { } }