/*
* RHQ Management Platform
* Copyright (C) 2005-2009 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.plugins.jbossas5.util;
import java.io.Serializable;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.EnumSet;
import java.util.HashSet;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
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;
import org.rhq.core.domain.configuration.definition.PropertySimpleType;
import org.rhq.core.domain.configuration.definition.constraint.FloatRangeConstraint;
import org.rhq.core.domain.configuration.definition.constraint.IntegerRangeConstraint;
import org.rhq.core.domain.measurement.DataType;
import org.rhq.core.domain.measurement.DisplayType;
import org.rhq.core.domain.measurement.MeasurementCategory;
import org.rhq.core.domain.measurement.MeasurementDefinition;
import org.rhq.core.domain.measurement.MeasurementUnits;
import org.rhq.core.domain.operation.OperationDefinition;
import org.rhq.core.domain.resource.ResourceCategory;
import org.rhq.core.domain.resource.ResourceType;
import org.rhq.core.domain.util.StringUtils;
import org.jboss.managed.api.ComponentType;
import org.jboss.managed.api.ManagedComponent;
import org.jboss.managed.api.ManagedDeployment;
import org.jboss.managed.api.ManagedObject;
import org.jboss.managed.api.ManagedOperation;
import org.jboss.managed.api.ManagedParameter;
import org.jboss.managed.api.ManagedProperty;
import org.jboss.managed.api.annotation.ViewUse;
import org.jboss.metatype.api.types.ArrayMetaType;
import org.jboss.metatype.api.types.CollectionMetaType;
import org.jboss.metatype.api.types.CompositeMetaType;
import org.jboss.metatype.api.types.MapCompositeMetaType;
import org.jboss.metatype.api.types.MetaType;
import org.jboss.metatype.api.types.PropertiesMetaType;
import org.jboss.metatype.api.types.TableMetaType;
import org.jboss.metatype.api.types.SimpleMetaType;
import org.jboss.metatype.api.values.ArrayValue;
import org.jboss.metatype.api.values.CollectionValue;
import org.jboss.metatype.api.values.GenericValue;
import org.jboss.metatype.api.values.MetaValue;
/**
* Utility class for converting JBAS5 Profile Service {@link ManagedComponent}s and {@link ManagedDeployment}s to RHQ
* {@link ResourceType}s.
*
* @author Ian Springer
*/
public class MetadataConversionUtils {
private static final Log LOG = LogFactory.getLog(MetadataConversionUtils.class);
private static final String PLUGIN_NAME = "ProfileService";
private static Map<String, PropertySimpleType> TYPE_MAP = new HashMap();
static {
TYPE_MAP.put(boolean.class.getName(), PropertySimpleType.BOOLEAN);
TYPE_MAP.put(Boolean.class.getName(), PropertySimpleType.BOOLEAN);
TYPE_MAP.put(int.class.getName(), PropertySimpleType.INTEGER);
TYPE_MAP.put(Integer.class.getName(), PropertySimpleType.INTEGER);
TYPE_MAP.put(long.class.getName(), PropertySimpleType.LONG);
TYPE_MAP.put(Long.class.getName(), PropertySimpleType.LONG);
TYPE_MAP.put(float.class.getName(), PropertySimpleType.FLOAT);
TYPE_MAP.put(Float.class.getName(), PropertySimpleType.FLOAT);
TYPE_MAP.put(double.class.getName(), PropertySimpleType.DOUBLE);
TYPE_MAP.put(Double.class.getName(), PropertySimpleType.DOUBLE);
}
public static ResourceType convertDeploymentToResourceType(String deploymentTypeName, ManagedDeployment deployment) {
LOG.debug("Creating ResourceType for ManagedDeployment type [" + deploymentTypeName + "]...");
ResourceType resourceType = new ResourceType(deploymentTypeName, PLUGIN_NAME, ResourceCategory.SERVICE, null);
Set<MeasurementDefinition> metricDefs = convertMetricPropertiesToMeasurementDefinitions(deployment);
resourceType.setMetricDefinitions(metricDefs);
ConfigurationDefinition resourceConfigDef = convertConfigurationPropertiesToConfigurationDefinition(deployment);
resourceType.setResourceConfigurationDefinition(resourceConfigDef);
return resourceType;
}
public static ResourceType convertComponentToResourceType(ManagedComponent component)
{
LOG.debug("Creating ResourceType for ManagedComponent type [" + component.getType() + "]...");
ComponentType componentType = component.getType();
String name;
if (componentType.getSubtype().equals("*"))
name = component.getName() + " " + componentType.getType();
else
name = componentType.getSubtype() + " " + componentType.getType();
ResourceType resourceType = new ResourceType(name, PLUGIN_NAME, ResourceCategory.SERVICE, null);
Set<OperationDefinition> opDefs = convertManagedOperationsToOperationDefinitions(component);
for (OperationDefinition opDef : opDefs)
resourceType.addOperationDefinition(opDef);
Set<MeasurementDefinition> metricDefs = convertMetricPropertiesToMeasurementDefinitions(component);
resourceType.setMetricDefinitions(metricDefs);
ConfigurationDefinition resourceConfigDef = convertConfigurationPropertiesToConfigurationDefinition(component);
resourceType.setResourceConfigurationDefinition(resourceConfigDef);
return resourceType;
}
private static Set<OperationDefinition> convertManagedOperationsToOperationDefinitions(ManagedComponent component) {
Set<OperationDefinition> opDefs = new TreeSet(new OperationDefinitionComparator());
Map<String,ManagedOperation> managedOperations = new HashMap();
for (ManagedOperation operation : component.getOperations()) {
ManagedOperation operationWithSameName = managedOperations.get(operation.getName());
if (operationWithSameName == null ||
operationWithSameName.getParameters().length < operation.getParameters().length) {
if (operationWithSameName != null)
LOG.info("Found more than one ManagedOperation named '" + operation.getName()
+ "' - converting only the one with the most parameters.");
managedOperations.put(operation.getName(), operation);
}
}
for (ManagedOperation operation : managedOperations.values()) {
OperationDefinition opDef = convertOperationToOperationDefinition(operation);
opDefs.add(opDef);
}
return opDefs;
}
private static OperationDefinition convertOperationToOperationDefinition(ManagedOperation operation) {
String desc = (!operation.getName().equals(operation.getDescription())) ? operation.getDescription() : null;
OperationDefinition opDef = new OperationDefinition(operation.getName(), null, desc);
opDef.setDisplayName(StringUtils.deCamelCase(operation.getName()));
ConfigurationDefinition paramsConfigDef = convertParametersToConfigurationDefinition(operation);
opDef.setParametersConfigurationDefinition(paramsConfigDef);
ConfigurationDefinition resultsConfigDef = convertResultToConfigurationDefinition(operation);
opDef.setResultsConfigurationDefinition(resultsConfigDef);
return opDef;
}
private static ConfigurationDefinition convertParametersToConfigurationDefinition(ManagedOperation operation)
{
if (operation.getParameters() == null || operation.getParameters().length == 0)
return null;
ConfigurationDefinition configDef = new ConfigurationDefinition(operation.getName(), null);
for (ManagedParameter parameter : operation.getParameters()) {
PropertyDefinition propDef = convertParameterToPropertyDefinition(parameter);
configDef.put(propDef);
}
return configDef;
}
private static PropertyDefinition convertParameterToPropertyDefinition(ManagedParameter parameter) {
PropertyDefinition propDef = convertMetaTypeToPropertyDefinition(parameter.getMetaType(), parameter.getName(),
parameter.getValue());
String desc = (!parameter.getName().equals(parameter.getDescription())) ? parameter.getDescription() : null;
propDef.setDescription(desc);
// TODO: Convert parameter.getLegalValues() to enum defs.
if (propDef instanceof PropertyDefinitionSimple) {
PropertyDefinitionSimple propDefSimple = (PropertyDefinitionSimple)propDef;
addConstraints(propDefSimple, parameter.getMinimumValue(), parameter.getMaximumValue());
}
return propDef;
}
private static PropertyDefinitionList convertMetaTypeToPropertyDefinitionList(MetaType metaType, String name,
MetaValue metaValue) {
MetaType elementType;
MetaValue elementValue = null;
if (metaType.isCollection()) {
CollectionMetaType collectionMetaType = (CollectionMetaType)metaType;
elementType = collectionMetaType.getElementType();
if (metaValue != null) {
CollectionValue collectionValue = (CollectionValue)metaValue;
MetaValue[] elements = collectionValue.getElements();
if (elements != null && elements.length != 0)
elementValue = elements[0];
}
} else if (metaType.isArray()) {
ArrayMetaType arrayMetaType = (ArrayMetaType)metaType;
elementType = arrayMetaType.getElementType();
if (metaValue != null) {
ArrayValue arrayValue = (ArrayValue)metaValue;
if (arrayValue.getLength() != 0 && arrayValue.getValue(0) instanceof MetaValue)
elementValue = (MetaValue)arrayValue.getValue(0);
}
} else {
throw new IllegalStateException("Unsupported MetaType: " + metaType);
}
PropertyDefinition elementPropDef = convertMetaTypeToPropertyDefinition(elementType, "element", elementValue);
@SuppressWarnings({"UnnecessaryLocalVariable"})
PropertyDefinitionList propDefList = new PropertyDefinitionList(name, null, true, elementPropDef);
return propDefList;
}
private static PropertyDefinitionMap convertMetaTypeToPropertyDefinitionMap(MetaType metaType, String name,
MetaValue metaValue) {
PropertyDefinitionMap propDefMap = new PropertyDefinitionMap(name, null, false);
if (metaType.isComposite()) {
if (!(metaType instanceof MapCompositeMetaType)) {
CompositeMetaType compositeMetaType = (CompositeMetaType)metaType;
for (String itemName : compositeMetaType.itemSet()) {
MetaType itemMetaType = compositeMetaType.getType(itemName);
if (itemMetaType.isComposite()) {
// Avoid StackOverflowErrors caused by recursive CompositeMetaType metadata.
if (itemMetaType == compositeMetaType)
LOG.error("CompositeMetaType " + compositeMetaType
+ " contains an item whose type is a reference to the CompositeMetaType itself!");
else
LOG.error("CompositeMetaType " + compositeMetaType
+ " contains an item whose type is another CompositeMetaType: " + itemMetaType);
continue;
}
LOG.trace("Converting item with type [" + itemMetaType + "@" + System.identityHashCode(itemMetaType)
+ "] and name [" + itemName + "]...");
PropertyDefinition itemPropDef = convertMetaTypeToPropertyDefinition(itemMetaType, itemName, null);
propDefMap.put(itemPropDef);
String desc = (!itemName.equals(compositeMetaType.getDescription(itemName))) ?
compositeMetaType.getDescription(itemName) : null;
itemPropDef.setDescription(desc);
}
}
} else if (metaType.isGeneric()) {
if (metaValue != null) {
GenericValue genericValue = (GenericValue)metaValue;
Serializable value = genericValue.getValue();
if (value != null && value instanceof ManagedObject) {
ManagedObject managedObject = (ManagedObject)value;
for (ManagedProperty managedProp : managedObject.getProperties().values()) {
PropertyDefinition itemPropDef = convertManagedPropertyToPropertyDefinition(managedProp);
propDefMap.put(itemPropDef);
}
}
}
} else if (metaType.isTable()) {
TableMetaType tableMetaType = (TableMetaType)metaType;
CompositeMetaType itemMetaType = tableMetaType.getRowType();
for (String itemName : tableMetaType.getIndexNames()) {
PropertyDefinition itemPropDef = convertMetaTypeToPropertyDefinition(itemMetaType, itemName, null);
propDefMap.put(itemPropDef);
}
} else if (metaType instanceof PropertiesMetaType) {
@SuppressWarnings({"UnusedDeclaration"})
PropertiesMetaType propertiesMetaType = (PropertiesMetaType)metaType;
}
return propDefMap;
}
private static ConfigurationDefinition convertResultToConfigurationDefinition(ManagedOperation operation)
{
MetaType returnType = operation.getReturnType();
if (returnType.getClassName().equals(Void.class.getName()))
return null;
PropertyDefinition propDef = convertMetaTypeToPropertyDefinition(returnType, "result", null);
ConfigurationDefinition configDef = new ConfigurationDefinition(operation.getName(), operation.getDescription());
configDef.put(propDef);
return configDef;
}
private static Set<MeasurementDefinition> convertMetricPropertiesToMeasurementDefinitions(ManagedDeployment deployment)
{
return convertMetricPropertiesToMeasurementDefinitions(deployment.getProperties());
}
private static Set<MeasurementDefinition> convertMetricPropertiesToMeasurementDefinitions(ManagedComponent component)
{
return convertMetricPropertiesToMeasurementDefinitions(component.getProperties());
}
private static Set<MeasurementDefinition> convertMetricPropertiesToMeasurementDefinitions(Map<String, ManagedProperty> props) {
Set<MeasurementDefinition> measurementDefs = new TreeSet(new MeasurementDefinitionComparator());
if (props == null)
return measurementDefs;
for(ManagedProperty prop : props.values()) {
if (prop.hasViewUse(ViewUse.RUNTIME) || prop.hasViewUse(ViewUse.STATISTIC)) {
MetaType metaType = prop.getMetaType();
if (metaType.isSimple() || metaType.isEnum())
{
MeasurementDefinition measurementDef = getMeasurementDefinitionForSimpleManagedProperty(prop);
measurementDefs.add(measurementDef);
}
else if (prop.getMetaType().isComposite())
{
Set<MeasurementDefinition> compositeMeasurementDefs =
getMeasurementDefinitionsForCompositeManagedProperty(prop);
measurementDefs.addAll(compositeMeasurementDefs);
}
else
{
LOG.warn("Skipping property [" + prop + "] with unsupported type [" + metaType + "].");
}
}
}
return measurementDefs;
}
private static MeasurementDefinition getMeasurementDefinitionForSimpleManagedProperty(ManagedProperty prop)
{
MetaType metaType = prop.getMetaType();
DataType dataType;
if (metaType.isSimple()) {
SimpleMetaType simpleMetaType = (SimpleMetaType)metaType;
dataType = (prop.hasViewUse(ViewUse.STATISTIC) && MetaTypeUtils.isNumeric(simpleMetaType)) ?
DataType.MEASUREMENT : DataType.TRAIT;
} else { // metaType.isEnum()
// Enum values are always Strings.
dataType = DataType.TRAIT;
}
int defaultInterval = (dataType == DataType.MEASUREMENT) ? 60000 : 600000;
DisplayType displayType = (dataType == DataType.MEASUREMENT) ? DisplayType.DETAIL : DisplayType.SUMMARY;
MeasurementDefinition measurementDef = new MeasurementDefinition(prop.getName(),
MeasurementCategory.PERFORMANCE, MeasurementUnits.NONE, dataType, true, defaultInterval, displayType);
measurementDef.setDisplayName(StringUtils.deCamelCase(prop.getName()));
String desc = (!prop.getName().equals(prop.getDescription())) ? prop.getDescription() : null;
measurementDef.setDescription(desc);
return measurementDef;
}
private static Set<MeasurementDefinition> getMeasurementDefinitionsForCompositeManagedProperty(ManagedProperty property) {
Set<MeasurementDefinition> measurementDefs = new HashSet();
CompositeMetaType compositeMetaType = (CompositeMetaType)property.getMetaType();
Set<String> itemNames = compositeMetaType.keySet();
for (String itemName : itemNames) {
MetaType itemType = compositeMetaType.getType(itemName);
if (itemType.isSimple() || itemType.isEnum()) {
String metricName = property.getName() + "." + itemName;
DataType dataType = (itemType.getClassName().equals(String.class.getName())) ?
DataType.TRAIT : DataType.MEASUREMENT;
MeasurementDefinition measurementDef = new MeasurementDefinition(metricName,
MeasurementCategory.PERFORMANCE, MeasurementUnits.NONE, dataType, true, 60000,
DisplayType.DETAIL);
measurementDefs.add(measurementDef);
measurementDef.setDisplayName(StringUtils.deCamelCase(itemName));
} else {
LOG.warn("Composite stat property [" + property.getName() + "] contains non-simple item with type ["
+ itemType + "] - skipping..." );
}
}
return measurementDefs;
}
private static ConfigurationDefinition convertConfigurationPropertiesToConfigurationDefinition(String configName, Map<String, ManagedProperty> managedProps)
{
Set<PropertyDefinition> propDefs = new TreeSet(new PropertyDefinitionComparator());
for(ManagedProperty prop : managedProps.values()) {
EnumSet<ViewUse> viewUses = ManagedComponentUtils.getViewUses(prop);
// Assume a property with no view uses is a config prop.
if (viewUses.contains(ViewUse.CONFIGURATION) || viewUses.contains(ViewUse.RUNTIME) || viewUses.isEmpty()) {
PropertyDefinition propDef = convertManagedPropertyToPropertyDefinition(prop);
propDefs.add(propDef);
}
}
if (propDefs.isEmpty())
return null;
ConfigurationDefinition configDef = new ConfigurationDefinition(configName, null);
for (PropertyDefinition propDef : propDefs)
configDef.getPropertyDefinitions().put(propDef.getName(), propDef);
return configDef;
}
private static PropertyDefinition convertManagedPropertyToPropertyDefinition(ManagedProperty prop) {
PropertyDefinition propDef;
propDef = convertMetaTypeToPropertyDefinition(prop.getMetaType(), prop.getName(), prop.getValue());
String desc = (!prop.getName().equals(prop.getDescription())) ? prop.getDescription() : null;
propDef.setDescription(desc);
propDef.setRequired(prop.isMandatory());
propDef.setReadOnly(prop.isReadOnly());
// TODO: Convert prop.getLegalValues() to enum defs.
if (propDef instanceof PropertyDefinitionSimple) {
PropertyDefinitionSimple propDefSimple = (PropertyDefinitionSimple)propDef;
addConstraints(propDefSimple, prop.getMinimumValue(), prop.getMaximumValue());
}
return propDef;
}
private static PropertyDefinition convertMetaTypeToPropertyDefinition(MetaType metaType, String propName,
MetaValue metaValue) {
PropertyDefinition propDef;
if (metaType.isSimple() || metaType.isEnum()) {
PropertySimpleType propType = convertClassToPropertySimpleType(metaType.getClassName());
propDef = new PropertyDefinitionSimple(propName, null, false, propType);
} else if (metaType.isCollection() || metaType.isArray()) {
propDef = convertMetaTypeToPropertyDefinitionList(metaType, propName, metaValue);
} else if (metaType.isComposite() || metaType.isGeneric() || metaType.isTable() ||
metaType instanceof PropertiesMetaType) {
LOG.trace("Converting map with type [" + metaType + "@" + System.identityHashCode(metaType) + "], name ["
+ propName + "], and value [" + metaValue + "]...");
propDef = convertMetaTypeToPropertyDefinitionMap(metaType, propName, metaValue);
} else {
throw new IllegalStateException("Unsupported MetaType: " + metaType);
}
propDef.setDisplayName(StringUtils.deCamelCase(propName));
return propDef;
}
private static ConfigurationDefinition convertConfigurationPropertiesToConfigurationDefinition(ManagedDeployment deployment)
{
return convertConfigurationPropertiesToConfigurationDefinition(deployment.getName() + " resource config",
deployment.getProperties());
}
private static ConfigurationDefinition convertConfigurationPropertiesToConfigurationDefinition(ManagedComponent component)
{
return convertConfigurationPropertiesToConfigurationDefinition(component.getName() + " resource config",
component.getProperties());
}
private static PropertySimpleType convertClassToPropertySimpleType(String className) {
PropertySimpleType simpleType = TYPE_MAP.get(className);
return (simpleType != null) ? simpleType : PropertySimpleType.STRING;
}
private static void addConstraints(PropertyDefinitionSimple propDefSimple, Comparable<?> minValue,
Comparable<?> maxValue) {
if (minValue != null || maxValue != null) {
if (propDefSimple.getType() == PropertySimpleType.INTEGER ||
propDefSimple.getType() == PropertySimpleType.LONG) {
Long min = (minValue != null) ? ((Number)minValue).longValue() : null;
Long max = (maxValue != null) ? ((Number)maxValue).longValue() : null;
IntegerRangeConstraint constraint = new IntegerRangeConstraint(min, max);
propDefSimple.addConstraints(constraint);
} else if (propDefSimple.getType() == PropertySimpleType.FLOAT ||
propDefSimple.getType() == PropertySimpleType.DOUBLE) {
Double min = (minValue != null) ? ((Number)minValue).doubleValue() : null;
Double max = (maxValue != null) ? ((Number)maxValue).doubleValue() : null;
FloatRangeConstraint constraint = new FloatRangeConstraint(min, max);
propDefSimple.addConstraints(constraint);
}
}
}
private static class OperationDefinitionComparator implements Comparator<OperationDefinition> {
public int compare(OperationDefinition opDef1, OperationDefinition opDef2) {
return opDef1.getName().compareTo(opDef2.getName());
}
}
private static class MeasurementDefinitionComparator implements Comparator<MeasurementDefinition> {
public int compare(MeasurementDefinition metricDef1, MeasurementDefinition metricDef2) {
return metricDef1.getName().compareTo(metricDef2.getName());
}
}
private static class PropertyDefinitionComparator implements Comparator<PropertyDefinition> {
public int compare(PropertyDefinition propDef1, PropertyDefinition propDef2) {
return propDef1.getName().compareTo(propDef2.getName());
}
}
}