/*
* RHQ Management Platform
* Copyright (C) 2005-2010 Red Hat, Inc.
* All rights reserved.
*
* 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.core.gui.configuration.propset;
import java.util.ArrayList;
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 ConfigurationSet {
private ConfigurationDefinition configurationDefinition;
private List<ConfigurationSetMember> members;
private Configuration groupConfiguration;
public ConfigurationSet(ConfigurationDefinition configurationDefinition, List<ConfigurationSetMember> members) {
if (configurationDefinition == null)
throw new IllegalArgumentException("configurationDefinition parameter is null.");
this.configurationDefinition = configurationDefinition;
if (members == null)
throw new IllegalArgumentException("members parameter is null.");
this.members = members;
this.groupConfiguration = new Configuration();
calculateGroupConfiguration();
}
public void calculateGroupConfiguration() {
this.groupConfiguration.getMap().clear();
if (this.members.isEmpty())
return;
Map<String, PropertyDefinition> childPropertyDefinitions = this.configurationDefinition
.getPropertyDefinitions();
List<AbstractPropertyMap> sourceParentPropertyMaps = new ArrayList<AbstractPropertyMap>();
for (ConfigurationSetMember member : this.members)
sourceParentPropertyMaps.add(member.getConfiguration());
for (PropertyDefinition childPropertyDefinition : childPropertyDefinitions.values())
calculateGroupProperty(childPropertyDefinition, sourceParentPropertyMaps, this.groupConfiguration);
}
public void applyGroupConfiguration() {
if (this.members.isEmpty())
return;
Map<String, PropertyDefinition> childPropertyDefinitions = this.configurationDefinition
.getPropertyDefinitions();
List<AbstractPropertyMap> sourceParentPropertyMaps = new ArrayList<AbstractPropertyMap>();
for (ConfigurationSetMember member : this.members)
sourceParentPropertyMaps.add(member.getConfiguration());
for (PropertyDefinition childPropertyDefinition : childPropertyDefinitions.values())
mergeProperty(childPropertyDefinition, sourceParentPropertyMaps, this.groupConfiguration);
}
public ConfigurationDefinition getConfigurationDefinition() {
return configurationDefinition;
}
public List<ConfigurationSetMember> getMembers() {
return members;
}
public Configuration getGroupConfiguration() {
return groupConfiguration;
}
private static void calculateGroupProperty(PropertyDefinition propertyDefinition,
List<AbstractPropertyMap> sourceParentPropertyMaps, AbstractPropertyMap targetParentPropertyMap) {
if (propertyDefinition instanceof PropertyDefinitionSimple) {
String sampleValue = getSimpleValue(sourceParentPropertyMaps.get(0), propertyDefinition.getName());
boolean valuesHomogenous = 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))) {
valuesHomogenous = false;
break;
}
}
PropertySimple propertySimple = new PropertySimple(propertyDefinition.getName(),
(valuesHomogenous) ? sampleValue : null);
targetParentPropertyMap.put(propertySimple);
if (valuesHomogenous)
// Set override to true so the config renderer will know the prop is homogenous.
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);
calculateGroupPropertyMap((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 calculateGroupPropertyMap(PropertyDefinitionMap propertyDefinitionMap,
List<AbstractPropertyMap> sourceParentPropertyMaps, AbstractPropertyMap targetParentPropertyMap) {
Map<String, PropertyDefinition> childPropertyDefinitions = propertyDefinitionMap.getMap();
if (!childPropertyDefinitions.isEmpty()) {
for (PropertyDefinition childPropertyDefinition : childPropertyDefinitions.values())
calculateGroupProperty(childPropertyDefinition, sourceParentPropertyMaps, targetParentPropertyMap);
} else {
calculateGroupOpenPropertyMap(sourceParentPropertyMaps, targetParentPropertyMap);
}
}
private static void calculateGroupOpenPropertyMap(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 void mergeProperty(PropertyDefinition propertyDefinition,
List<AbstractPropertyMap> memberParentPropertyMaps, AbstractPropertyMap groupParentPropertyMap) {
if (propertyDefinition instanceof PropertyDefinitionSimple) {
PropertySimple propertySimple = groupParentPropertyMap.getSimple(propertyDefinition.getName());
if (propertySimple != null && propertySimple.getOverride() != null && propertySimple.getOverride()) {
for (AbstractPropertyMap sourceParentPropertyMap : memberParentPropertyMaps) {
PropertySimple sourcePropertySimple = sourceParentPropertyMap.getSimple(propertyDefinition
.getName());
if (sourcePropertySimple == null) {
sourcePropertySimple = new PropertySimple(propertyDefinition.getName(), propertySimple
.getStringValue());
sourceParentPropertyMap.put(sourcePropertySimple);
} else {
sourcePropertySimple.setStringValue(propertySimple.getStringValue());
}
}
}
}
// If the property is a Map, recurse into it and merge its child properties.
else if (propertyDefinition instanceof PropertyDefinitionMap) {
List<AbstractPropertyMap> nestedSourceParentPropertyMaps = new ArrayList<AbstractPropertyMap>();
for (AbstractPropertyMap sourceParentPropertyMap : memberParentPropertyMaps)
nestedSourceParentPropertyMaps.add(sourceParentPropertyMap.getMap(propertyDefinition.getName()));
PropertyMap groupPropertyMap = groupParentPropertyMap.getMap(propertyDefinition.getName());
groupParentPropertyMap.put(groupPropertyMap);
mergePropertyMap((PropertyDefinitionMap) propertyDefinition, nestedSourceParentPropertyMaps,
groupPropertyMap);
} else if (propertyDefinition instanceof PropertyDefinitionList) {
PropertyDefinitionList propertyDefinitionList = (PropertyDefinitionList) propertyDefinition;
PropertyDefinition listMemberPropertyDefinition = propertyDefinitionList.getMemberDefinition();
PropertyList groupPropertyList = groupParentPropertyMap.getList(propertyDefinition.getName());
if (listMemberPropertyDefinition instanceof PropertyDefinitionMap) {
PropertyDefinitionMap propertyDefinitionMap = (PropertyDefinitionMap) listMemberPropertyDefinition;
// TODO: How do we merge Lists of Maps? Not trivial...
}
}
}
private static void mergePropertyMap(PropertyDefinitionMap propertyDefinitionMap,
List<AbstractPropertyMap> memberParentPropertyMaps, AbstractPropertyMap groupParentPropertyMap) {
Map<String, PropertyDefinition> childPropertyDefinitions = propertyDefinitionMap.getMap();
if (!childPropertyDefinitions.isEmpty()) {
for (PropertyDefinition childPropertyDefinition : childPropertyDefinitions.values())
mergeProperty(childPropertyDefinition, memberParentPropertyMaps, groupParentPropertyMap);
} else {
mergeOpenPropertyMap(memberParentPropertyMaps, groupParentPropertyMap);
}
}
private static void mergeOpenPropertyMap(List<AbstractPropertyMap> memberParentPropertyMaps,
AbstractPropertyMap groupParentPropertyMap) {
for (String groupMemberPropertyName : groupParentPropertyMap.getMap().keySet()) {
PropertySimple groupMemberProperty = groupParentPropertyMap.getSimple(groupMemberPropertyName);
if (groupMemberProperty != null && groupMemberProperty.getOverride() != null
&& groupMemberProperty.getOverride()) {
for (AbstractPropertyMap sourceParentPropertyMap : memberParentPropertyMaps) {
PropertySimple sourcePropertySimple = sourceParentPropertyMap.getSimple(groupMemberPropertyName);
if (sourcePropertySimple == null) {
sourcePropertySimple = new PropertySimple(groupMemberPropertyName, groupMemberProperty
.getStringValue());
sourceParentPropertyMap.put(sourcePropertySimple);
} else {
sourcePropertySimple.setStringValue(groupMemberProperty.getStringValue());
}
}
}
}
}
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;
}
}