/*
* RHQ Management Platform
* Copyright (C) 2005-2011 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.enterprise.server.xmlschema;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import javax.xml.bind.JAXBElement;
import javax.xml.namespace.QName;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.rhq.core.clientapi.agent.metadata.ConfigurationMetadataParser;
import org.rhq.core.clientapi.agent.metadata.InvalidPluginDescriptorException;
import org.rhq.core.clientapi.descriptor.configuration.ConfigurationDescriptor;
import org.rhq.core.clientapi.descriptor.configuration.ConfigurationProperty;
import org.rhq.core.clientapi.descriptor.configuration.ListProperty;
import org.rhq.core.clientapi.descriptor.configuration.MapProperty;
import org.rhq.core.clientapi.descriptor.configuration.MeasurementUnitsDescriptor;
import org.rhq.core.clientapi.descriptor.configuration.Option;
import org.rhq.core.clientapi.descriptor.configuration.PropertyOptions;
import org.rhq.core.clientapi.descriptor.configuration.PropertyType;
import org.rhq.core.clientapi.descriptor.configuration.SimpleProperty;
import org.rhq.core.domain.configuration.Configuration;
import org.rhq.core.domain.configuration.Property;
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.PropertyDefinitionEnumeration;
import org.rhq.core.domain.configuration.definition.PropertyDefinitionList;
import org.rhq.core.domain.configuration.definition.PropertyDefinitionMap;
import org.rhq.core.domain.configuration.definition.PropertyDefinitionSimple;
import org.rhq.core.domain.configuration.definition.PropertySimpleType;
import org.rhq.core.domain.measurement.MeasurementUnits;
import org.rhq.enterprise.server.xmlschema.generated.configuration.instance.ComplexValueDescriptor;
import org.rhq.enterprise.server.xmlschema.generated.configuration.instance.ComplexValueListDescriptor;
import org.rhq.enterprise.server.xmlschema.generated.configuration.instance.ComplexValueMapDescriptor;
import org.rhq.enterprise.server.xmlschema.generated.configuration.instance.ComplexValueSimpleDescriptor;
import org.rhq.enterprise.server.xmlschema.generated.configuration.instance.ConfigurationInstanceDescriptor;
import org.rhq.enterprise.server.xmlschema.generated.configuration.instance.ListPropertyInstanceDescriptor;
import org.rhq.enterprise.server.xmlschema.generated.configuration.instance.MapPropertyInstanceDescriptor;
import org.rhq.enterprise.server.xmlschema.generated.configuration.instance.PropertyValuesDescriptor;
import org.rhq.enterprise.server.xmlschema.generated.configuration.instance.SimplePropertyInstanceDescriptor;
/**
*
*
* @author Lukas Krejci
*/
public class ConfigurationInstanceDescriptorUtil {
public static final String NS_CONFIGURATION_INSTANCE = "urn:xmlns:rhq-configuration-instance";
public static final String NS_CONFIGURATION = "urn:xmlns:rhq-configuration";
private static final Log LOG = LogFactory.getLog(ConfigurationInstanceDescriptorUtil.class);
private ConfigurationInstanceDescriptorUtil() {
}
public static class ConfigurationAndDefinition {
public Configuration configuration;
public ConfigurationDefinition definition;
}
protected static QName getTagName(ConfigurationProperty descriptor) {
if (descriptor instanceof SimplePropertyInstanceDescriptor) {
return new QName(NS_CONFIGURATION_INSTANCE, "simple-property");
} else if (descriptor instanceof ListPropertyInstanceDescriptor) {
return new QName(NS_CONFIGURATION_INSTANCE, "list-property");
} else if (descriptor instanceof MapPropertyInstanceDescriptor) {
return new QName(NS_CONFIGURATION_INSTANCE, "map-property");
} else if (descriptor instanceof SimpleProperty) {
return new QName(NS_CONFIGURATION, "simple-property");
} else if (descriptor instanceof ListProperty) {
return new QName(NS_CONFIGURATION, "list-property");
} else if (descriptor instanceof MapProperty) {
return new QName(NS_CONFIGURATION, "map-property");
}
throw new IllegalArgumentException("Unknown descriptor type: " + descriptor.getClass());
}
private static QName getTagName(ComplexValueDescriptor value) {
if (value instanceof ComplexValueSimpleDescriptor) {
return new QName(NS_CONFIGURATION_INSTANCE, "simple-value");
} else if (value instanceof ComplexValueListDescriptor) {
return new QName(NS_CONFIGURATION_INSTANCE, "list-value");
} else if (value instanceof ComplexValueMapDescriptor) {
return new QName(NS_CONFIGURATION_INSTANCE, "map-value");
}
throw new IllegalArgumentException("Unknown value descriptor type: " + value.getClass());
}
private static class ToDescriptor {
public static ConfigurationInstanceDescriptor createConfigurationInstance(ConfigurationDefinition definition,
Configuration configuration) {
ConfigurationInstanceDescriptor ret = new ConfigurationInstanceDescriptor();
addAll(ret.getConfigurationProperty(), definition.getPropertyDefinitions(), configuration.getMap());
return ret;
}
private static void addAll(List<JAXBElement<?>> descriptors, Map<String, PropertyDefinition> defs,
Map<String, Property> props) {
for (Map.Entry<String, PropertyDefinition> e : defs.entrySet()) {
String propName = e.getKey();
PropertyDefinition def = e.getValue();
Property prop = props.get(propName);
addSingle(descriptors, def, prop);
}
}
private static void addSingle(List<JAXBElement<?>> descriptors, PropertyDefinition def, Property prop) {
ConfigurationProperty descriptor = null;
QName tagName = null;
descriptor = createDescriptor(def, prop);
tagName = getTagName(descriptor);
addToJAXBElementList(descriptors, Object.class, descriptor, tagName);
}
private static ConfigurationProperty createDescriptor(PropertyDefinition def, Property prop) {
ConfigurationProperty ret = null;
if (def instanceof PropertyDefinitionSimple) {
ret = createSimple((PropertyDefinitionSimple) def, (PropertySimple) prop);
} else if (def instanceof PropertyDefinitionList) {
ret = createList((PropertyDefinitionList) def, (PropertyList) prop);
} else if (def instanceof PropertyDefinitionMap) {
ret = createMap((PropertyDefinitionMap) def, (PropertyMap) prop);
}
return ret;
}
private static SimplePropertyInstanceDescriptor createSimple(PropertyDefinitionSimple def, PropertySimple prop) {
SimplePropertyInstanceDescriptor ret = new SimplePropertyInstanceDescriptor();
setCommonProps(ret, def, true);
//these are prohibited, because they make no sense on the property instance
//ret.setDefaultValue(def.getDefaultValue());
//ret.setInitialValue(prop.getStringValue());
//ret.setActivationPolicy(pds.getActivationPolicy());
ret.setPropertyOptions(convert(def.getEnumeratedValues()));
ret.setType(convert(def.getType()));
ret.setUnits(convert(def.getUnits()));
if (prop != null) {
ret.setValue(prop.getStringValue());
}
return ret;
}
private static ListPropertyInstanceDescriptor createList(PropertyDefinitionList def, PropertyList prop) {
ListPropertyInstanceDescriptor ret = new ListPropertyInstanceDescriptor();
setCommonProps(ret, def, true);
ConfigurationProperty memberDef = convertDefinition(def.getMemberDefinition());
ret.setConfigurationProperty(new JAXBElement<ConfigurationProperty>(getTagName(memberDef),
ConfigurationProperty.class, memberDef));
if (prop != null) {
PropertyValuesDescriptor values = new PropertyValuesDescriptor();
ret.setValues(values);
for (Property el : prop.getList()) {
ComplexValueDescriptor value = convertValue(el);
//we don't need the property-name in lists, because the list has just a single member definition
value.setPropertyName(null);
addToJAXBElementList(values.getComplexValue(), Object.class, value, getTagName(value));
}
}
return ret;
}
private static MapPropertyInstanceDescriptor createMap(PropertyDefinitionMap def, PropertyMap prop) {
MapPropertyInstanceDescriptor ret = new MapPropertyInstanceDescriptor();
setCommonProps(ret, def, true);
for (PropertyDefinition mem : def.getOrderedPropertyDefinitions()) {
ConfigurationProperty memDef = convertDefinition(mem);
addToJAXBElementList(ret.getConfigurationProperty(), ConfigurationProperty.class, memDef,
getTagName(memDef));
}
if (prop != null) {
PropertyValuesDescriptor values = new PropertyValuesDescriptor();
ret.setValues(values);
for (Property el : prop.getMap().values()) {
ComplexValueDescriptor value = convertValue(el);
addToJAXBElementList(values.getComplexValue(), Object.class, value, getTagName(value));
}
}
return ret;
}
private static void setCommonProps(ConfigurationProperty target, PropertyDefinition source,
boolean creatingInstance) {
target.setName(source.getName());
//let's always use long description
//target.setDescription(source.getDescription());
target.setLongDescription(source.getDescription());
target.setDisplayName(source.getDisplayName());
//these are prohibited on the instance because they make no sense there
if (!creatingInstance) {
target.setRequired(source.isRequired());
target.setReadOnly(source.isReadOnly());
target.setSummary(source.isSummary());
}
}
private static PropertyOptions convert(List<PropertyDefinitionEnumeration> options) {
if (options.isEmpty()) {
return null;
}
PropertyOptions ret = new PropertyOptions();
ArrayList<PropertyDefinitionEnumeration> opts = new ArrayList<PropertyDefinitionEnumeration>(options);
Collections.sort(opts, new Comparator<PropertyDefinitionEnumeration>() {
public int compare(PropertyDefinitionEnumeration o1, PropertyDefinitionEnumeration o2) {
return o1.getOrderIndex() - o2.getOrderIndex();
}
});
for (PropertyDefinitionEnumeration option : opts) {
ret.getOption().add(convert(option));
}
return ret;
}
private static Option convert(PropertyDefinitionEnumeration option) {
Option ret = new Option();
ret.setName(option.getName());
ret.setValue(option.getValue());
return ret;
}
private static PropertyType convert(PropertySimpleType type) {
if (type == null) {
return null;
}
try {
return PropertyType.valueOf(type.name());
} catch (IllegalArgumentException e) {
LOG.warn("Failed to convert a PropertySimpleType instance '" + type.name() + "' into a PropertyType.",
e);
throw e;
}
}
private static MeasurementUnitsDescriptor convert(MeasurementUnits unit) {
//XXX there actually are some differences in the available values for these
//two enums:
//Missing in MeasurementUnitsDescriptor:
//MeasurementUnits.JIFFY, MeasurementUnits.PETA_BYTES
if (unit == null) {
return null;
}
String value = unit.name();
try {
return MeasurementUnitsDescriptor.valueOf(value);
} catch (IllegalArgumentException e) {
LOG.warn("Failed to convert a MeasurementUnits instance '" + unit.getName()
+ "' into a MeasurementUnitsDescriptor.", e);
throw e;
}
}
private static ConfigurationProperty convertDefinition(PropertyDefinition def) {
if (def instanceof PropertyDefinitionSimple) {
return convertSimple((PropertyDefinitionSimple) def);
} else if (def instanceof PropertyDefinitionList) {
return convertList((PropertyDefinitionList) def);
} else if (def instanceof PropertyDefinitionMap) {
return convertMap((PropertyDefinitionMap) def);
}
throw new IllegalArgumentException("Unsupported property definition type: " + def.getClass());
}
private static SimpleProperty convertSimple(PropertyDefinitionSimple def) {
SimpleProperty ret = new SimpleProperty();
setCommonProps(ret, def, false);
ret.setDefaultValue(def.getDefaultValue());
ret.setPropertyOptions(convert(def.getEnumeratedValues()));
ret.setType(convert(def.getType()));
ret.setUnits(convert(def.getUnits()));
return ret;
}
private static ListProperty convertList(PropertyDefinitionList def) {
ListProperty ret = new ListProperty();
setCommonProps(ret, def, false);
ConfigurationProperty memberDefinition = convertDefinition(def.getMemberDefinition());
ret.setConfigurationProperty(new JAXBElement<ConfigurationProperty>(getTagName(memberDefinition),
ConfigurationProperty.class, memberDefinition));
return ret;
}
private static MapProperty convertMap(PropertyDefinitionMap def) {
MapProperty ret = new MapProperty();
setCommonProps(ret, def, false);
List<JAXBElement<? extends ConfigurationProperty>> elements = ret.getConfigurationProperty();
for (PropertyDefinition el : def.getOrderedPropertyDefinitions()) {
ConfigurationProperty prop = convertDefinition(el);
QName tagName = getTagName(prop);
addToJAXBElementList(elements, ConfigurationProperty.class, prop, tagName);
}
return ret;
}
private static ComplexValueDescriptor convertValue(Property prop) {
if (prop instanceof PropertySimple) {
return convertSimpleValue((PropertySimple) prop);
} else if (prop instanceof PropertyList) {
return convertListValue((PropertyList) prop);
} else if (prop instanceof PropertyMap) {
return convertMapValue((PropertyMap) prop);
}
throw new IllegalArgumentException("Unsupported property type to convert to a value descriptor: "
+ prop.getClass());
}
private static ComplexValueSimpleDescriptor convertSimpleValue(PropertySimple prop) {
ComplexValueSimpleDescriptor ret = new ComplexValueSimpleDescriptor();
ret.setPropertyName(prop.getName());
ret.setValue(prop.getStringValue());
return ret;
}
private static ComplexValueListDescriptor convertListValue(PropertyList prop) {
ComplexValueListDescriptor ret = new ComplexValueListDescriptor();
ret.setPropertyName(prop.getName());
for (Property el : prop.getList()) {
ComplexValueDescriptor value = convertValue(el);
addToJAXBElementList(ret.getComplexValue(), Object.class, value, getTagName(value));
}
return ret;
}
private static ComplexValueMapDescriptor convertMapValue(PropertyMap prop) {
ComplexValueMapDescriptor ret = new ComplexValueMapDescriptor();
ret.setPropertyName(prop.getName());
for (Property el : prop.getMap().values()) {
ComplexValueDescriptor value = convertValue(el);
addToJAXBElementList(ret.getComplexValue(), Object.class, value, getTagName(value));
}
return ret;
}
private static <T> void addToJAXBElementList(List<JAXBElement<? extends T>> list, Class<T> baseClass,
T property, QName tagName) {
JAXBElement<? extends T> el = new JAXBElement<T>(tagName, baseClass, property);
list.add(el);
}
}
private static class ToConfigurationAndDefinition {
public static ConfigurationAndDefinition createConfigurationAndDefinition(
ConfigurationInstanceDescriptor descriptor) {
ConfigurationAndDefinition ret = new ConfigurationAndDefinition();
Configuration configuration = new Configuration();
ConfigurationDefinition definition = new ConfigurationDefinition("tmp", null);
ret.configuration = configuration;
ret.definition = definition;
for (JAXBElement<?> el : descriptor.getConfigurationProperty()) {
Object childDescriptor = el.getValue();
add(definition, configuration, null, null, childDescriptor);
}
return ret;
}
private static void add(ConfigurationDefinition configurationDefinition, Configuration configuration,
PropertyDefinition parentDef, Property parentProp, Object propertyInstance) {
Property prop = null;
PropertyDefinition def = null;
if (propertyInstance instanceof SimplePropertyInstanceDescriptor) {
def = convert((ConfigurationProperty) propertyInstance);
def.setConfigurationDefinition(configurationDefinition);
SimplePropertyInstanceDescriptor simpleInstance = (SimplePropertyInstanceDescriptor) propertyInstance;
PropertySimple simpleProp = new PropertySimple(simpleInstance.getName(), simpleInstance.getValue());
prop = simpleProp;
} else if (propertyInstance instanceof ListPropertyInstanceDescriptor) {
def = convert((ConfigurationProperty) propertyInstance);
def.setConfigurationDefinition(configurationDefinition);
ListPropertyInstanceDescriptor listInstance = (ListPropertyInstanceDescriptor) propertyInstance;
PropertyList listProp = new PropertyList(listInstance.getName());
PropertyDefinition memberDefinition = ((PropertyDefinitionList) def).getMemberDefinition();
if (listInstance.getValues() != null) {
for (JAXBElement<?> val : listInstance.getValues().getComplexValue()) {
ComplexValueDescriptor valDesc = (ComplexValueDescriptor) val.getValue();
Property child = convert(memberDefinition, valDesc);
listProp.add(child);
}
}
prop = listProp;
} else if (propertyInstance instanceof MapPropertyInstanceDescriptor) {
def = convert((ConfigurationProperty) propertyInstance);
def.setConfigurationDefinition(configurationDefinition);
MapPropertyInstanceDescriptor mapInstance = (MapPropertyInstanceDescriptor) propertyInstance;
PropertyMap mapProp = new PropertyMap(mapInstance.getName());
if (mapInstance.getValues() != null) {
for (JAXBElement<?> val : mapInstance.getValues().getComplexValue()) {
ComplexValueDescriptor valueDesc = (ComplexValueDescriptor) val.getValue();
PropertyDefinition valueDefinition = ((PropertyDefinitionMap) def).get(valueDesc
.getPropertyName());
Property child = convert(valueDefinition, valueDesc);
mapProp.put(child);
}
}
prop = mapProp;
} else {
throw new IllegalArgumentException("Unsupported property instance type: " + propertyInstance.getClass());
}
if (parentDef != null) {
if (parentDef instanceof PropertyDefinitionList) {
def.setParentPropertyListDefinition((PropertyDefinitionList) parentDef);
} else if (parentDef instanceof PropertyDefinitionMap) {
def.setParentPropertyMapDefinition((PropertyDefinitionMap) parentDef);
}
} else {
configurationDefinition.put(def);
}
prop.setConfiguration(configuration);
if (parentProp != null) {
if (parentProp instanceof PropertyList) {
prop.setParentList((PropertyList) parentProp);
} else if (parentProp instanceof PropertyMap) {
prop.setParentMap((PropertyMap) parentProp);
}
} else {
configuration.put(prop);
}
}
private static PropertyDefinition convert(ConfigurationProperty def) {
try {
ConfigurationDescriptor tmp = new ConfigurationDescriptor();
tmp.getConfigurationProperty().add(
new JAXBElement<ConfigurationProperty>(getTagName(def), ConfigurationProperty.class, def));
ConfigurationDefinition configDef = ConfigurationMetadataParser.parse("null", tmp);
return configDef.getPropertyDefinitions().values().iterator().next();
} catch (InvalidPluginDescriptorException e) {
throw new IllegalArgumentException(e);
}
}
private static Property convert(PropertyDefinition definition, ComplexValueDescriptor value) {
Property ret = null;
if (value instanceof ComplexValueSimpleDescriptor) {
ret = new PropertySimple(value.getPropertyName(), ((ComplexValueSimpleDescriptor) value).getValue());
} else if (value instanceof ComplexValueListDescriptor) {
ComplexValueListDescriptor listValue = (ComplexValueListDescriptor) value;
PropertyDefinitionList listDefinition = (PropertyDefinitionList) definition;
PropertyList list = new PropertyList(value.getPropertyName());
for (JAXBElement<?> val : listValue.getComplexValue()) {
Property child = convert(listDefinition.getMemberDefinition(),
(ComplexValueDescriptor) val.getValue());
list.add(child);
}
ret = list;
} else if (value instanceof ComplexValueMapDescriptor) {
ComplexValueMapDescriptor mapValue = (ComplexValueMapDescriptor) value;
PropertyMap map = new PropertyMap(value.getPropertyName());
PropertyDefinitionMap mapDefinition = (PropertyDefinitionMap) definition;
for (JAXBElement<?> val : mapValue.getComplexValue()) {
ComplexValueDescriptor childDesc = (ComplexValueDescriptor) val.getValue();
PropertyDefinition childDefinition = mapDefinition.get(childDesc.getPropertyName());
Property child = convert(childDefinition, childDesc);
map.put(child);
}
ret = map;
}
if (ret.getName() == null) {
ret.setName(definition.getName());
}
return ret;
}
}
/**
* A configuration instance is a combination of a configuration definition and a concrete
* configuration instance with defined values. This is used during the config synchronization
* to output the default configuration of an importer directly in the export file so that the
* users have an easy way of modifying that configuration.
*
* @param definition
* @param configuration
* @return
*/
public static ConfigurationInstanceDescriptor createConfigurationInstance(ConfigurationDefinition definition,
Configuration configuration) {
return ToDescriptor.createConfigurationInstance(definition, configuration);
}
public static ConfigurationAndDefinition createConfigurationAndDefinition(ConfigurationInstanceDescriptor descriptor) {
return ToConfigurationAndDefinition.createConfigurationAndDefinition(descriptor);
}
}