/* * Jopr 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, version 2, as * published by the Free Software Foundation, and/or the GNU Lesser * General Public License, version 2.1, also as published by the Free * Software Foundation. * * 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 and the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU General Public License * and the GNU Lesser General Public License along with this program; * if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package org.rhq.plugins.jbossas5.util; import java.util.HashMap; import java.util.Map; import java.util.Set; import java.util.HashSet; import java.io.Serializable; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jboss.deployers.spi.management.KnownDeploymentTypes; import org.jboss.managed.api.ManagedOperation; import org.jboss.managed.api.ManagedParameter; import org.jboss.managed.api.ManagedProperty; import org.jboss.managed.api.ComponentType; import org.jboss.managed.api.annotation.ViewUse; import org.jboss.metatype.api.types.MetaType; import org.jboss.metatype.api.types.MapCompositeMetaType; import org.jboss.metatype.api.types.SimpleMetaType; import org.jboss.metatype.api.values.MetaValue; import org.jboss.metatype.api.values.SimpleValue; import org.jboss.metatype.api.values.EnumValue; import org.rhq.core.domain.configuration.Configuration; import org.rhq.core.domain.configuration.Property; 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.PropertyDefinitionSimple; import org.rhq.core.domain.configuration.definition.PropertySimpleType; import org.rhq.core.domain.configuration.definition.PropertyDefinitionList; import org.rhq.core.domain.configuration.definition.PropertyDefinitionMap; import org.rhq.core.domain.configuration.definition.ConfigurationTemplate; import org.rhq.core.domain.measurement.MeasurementDefinition; import org.rhq.core.domain.measurement.MeasurementReport; import org.rhq.core.domain.measurement.MeasurementScheduleRequest; import org.rhq.core.domain.operation.OperationDefinition; import org.rhq.core.domain.resource.ResourceType; import org.rhq.plugins.jbossas5.adapter.api.MeasurementAdapter; import org.rhq.plugins.jbossas5.adapter.api.MeasurementAdapterFactory; import org.rhq.plugins.jbossas5.adapter.api.PropertyAdapter; import org.rhq.plugins.jbossas5.adapter.api.PropertyAdapterFactory; import org.rhq.plugins.jbossas5.ManagedComponentComponent; import org.rhq.plugins.jbossas5.AbstractManagedDeploymentComponent; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; /** * Utility class to convert some basic Profile Service objects to JON objects, and some basic * manipulation and data gathering of Profile Service objects. * <p/> * This should not include converting between Property objects and ManagedProperties. Those conversions * should be in the corresponding Adapter classes. * * @author Ian Springer * @author Mark Spritzler */ public class ConversionUtils { private static final Log LOG = LogFactory.getLog(ConversionUtils.class); private static final Map<String, ComponentType> COMPONENT_TYPE_CACHE = new HashMap<String, ComponentType>(); private static final Map<String, KnownDeploymentTypes> DEPLOYMENT_TYPE_CACHE = new HashMap<String, KnownDeploymentTypes>(); private static final Map<String, Configuration> DEFAULT_PLUGIN_CONFIG_CACHE = new HashMap<String, Configuration>(); protected static final String PLUGIN = "ProfileService"; public static ComponentType getComponentType(@NotNull ResourceType resourceType) { String resourceTypeName = resourceType.getName(); if (COMPONENT_TYPE_CACHE.containsKey(resourceTypeName)) return COMPONENT_TYPE_CACHE.get(resourceTypeName); Configuration defaultPluginConfig; if (DEFAULT_PLUGIN_CONFIG_CACHE.containsKey(resourceTypeName)) defaultPluginConfig = DEFAULT_PLUGIN_CONFIG_CACHE.get(resourceTypeName); else { defaultPluginConfig = getDefaultPluginConfiguration(resourceType); DEFAULT_PLUGIN_CONFIG_CACHE.put(resourceTypeName, defaultPluginConfig); } String type = defaultPluginConfig.getSimpleValue(ManagedComponentComponent.COMPONENT_TYPE_PROPERTY, null); if (type == null || type.equals("")) throw new IllegalStateException("Required plugin configuration property '" + ManagedComponentComponent.COMPONENT_TYPE_PROPERTY + "' is not defined in default template."); String subtype = defaultPluginConfig.getSimpleValue(ManagedComponentComponent.COMPONENT_SUBTYPE_PROPERTY, null); if (subtype == null || subtype.equals("")) throw new IllegalStateException("Required plugin configuration property '" + ManagedComponentComponent.COMPONENT_SUBTYPE_PROPERTY + "' is not defined in default template."); ComponentType componentType = new ComponentType(type, subtype); COMPONENT_TYPE_CACHE.put(resourceTypeName, componentType); return componentType; } public static KnownDeploymentTypes getDeploymentType(@NotNull ResourceType resourceType) { String resourceTypeName = resourceType.getName(); if (DEPLOYMENT_TYPE_CACHE.containsKey(resourceTypeName)) return DEPLOYMENT_TYPE_CACHE.get(resourceTypeName); Configuration defaultPluginConfig; if (DEFAULT_PLUGIN_CONFIG_CACHE.containsKey(resourceTypeName)) defaultPluginConfig = DEFAULT_PLUGIN_CONFIG_CACHE.get(resourceTypeName); else { defaultPluginConfig = getDefaultPluginConfiguration(resourceType); DEFAULT_PLUGIN_CONFIG_CACHE.put(resourceTypeName, defaultPluginConfig); } String typeName = defaultPluginConfig.getSimpleValue(AbstractManagedDeploymentComponent.DEPLOYMENT_TYPE_NAME_PROPERTY, null); if (typeName == null || typeName.equals("")) throw new IllegalStateException("Required plugin configuration property '" + ManagedComponentComponent.COMPONENT_TYPE_PROPERTY + "' is not defined in default template."); KnownDeploymentTypes deploymentType = KnownDeploymentTypes.valueOf(typeName); DEPLOYMENT_TYPE_CACHE.put(resourceTypeName, deploymentType); return deploymentType; } private static Configuration getDefaultPluginConfiguration(ResourceType resourceType) { ConfigurationDefinition definition = resourceType.getPluginConfigurationDefinition(); if (definition != null) { ConfigurationTemplate template = definition.getDefaultTemplate(); if (template != null) { return template.getConfiguration().deepCopy(); } } return new Configuration(); // there is no default plugin config defined - return an empty one } public static Configuration convertManagedObjectToConfiguration(Map<String, ManagedProperty> managedProperties, Map<String, PropertySimple> customProps, ResourceType resourceType) { Configuration config = new Configuration(); ConfigurationDefinition configDef = resourceType.getResourceConfigurationDefinition(); Map<String, PropertyDefinition> propDefs = configDef.getPropertyDefinitions(); Set<String> propNames = managedProperties.keySet(); for (String propName : propNames) { PropertyDefinition propertyDefinition = propDefs.get(propName); ManagedProperty managedProperty = managedProperties.get(propName); if (propertyDefinition == null) { if (!managedProperty.hasViewUse(ViewUse.STATISTIC)) LOG.debug(resourceType + " does not define a property corresponding to ManagedProperty '" + propName + "'."); continue; } if (managedProperty == null) { // This should never happen, but don't let it blow us up. LOG.error("ManagedProperty '" + propName + "' has a null value in the ManagedProperties Map."); continue; } MetaValue metaValue = managedProperty.getValue(); if (managedProperty.isRemoved() || metaValue == null) { // Don't even add a Property to the Configuration if the ManagedProperty is flagged as removed or has a // null value. continue; } PropertySimple customProp = customProps.get(propName); PropertyAdapter propertyAdapter = PropertyAdapterFactory.getCustomPropertyAdapter(customProp); if (propertyAdapter == null) propertyAdapter = PropertyAdapterFactory.getPropertyAdapter(metaValue); if (propertyAdapter == null) { LOG.error("Unable to find a PropertyAdapter for ManagedProperty '" + propName + "' with MetaType [" + metaValue.getMetaType() + "] for ResourceType '" + resourceType.getName() + "'."); continue; } Property property = propertyAdapter.convertToProperty(metaValue, propertyDefinition); config.put(property); } return config; } public static void convertConfigurationToManagedProperties(Map<String, ManagedProperty> managedProperties, Configuration configuration, ResourceType resourceType, Map<String, PropertySimple> customProps) { ConfigurationDefinition configDefinition = resourceType.getResourceConfigurationDefinition(); Set<String> missingManagedPropertyNames = new HashSet(); for (Property property : configuration.getProperties()) { String propertyName = property.getName(); ManagedProperty managedProperty = managedProperties.get(propertyName); PropertyDefinition propertyDefinition = configDefinition.get(propertyName); if (managedProperty == null) { // NOTE: We expect the Profile Service to always return templates that contain *all* ManagedProperties // that are defined for the ComponentType, so this is considered an error. We could build a // ManagedProperty from scratch based on only a PropertyDefinition anyway, since a propDef could // map to multiple different types of MetaValues (e.g. a PropertyList could potentially map to // either an ArrayValue or a CollectionValue). missingManagedPropertyNames.add(propertyName); } else { populateManagedPropertyFromProperty(property, propertyDefinition, managedProperty, customProps.get(propertyName)); } if (!missingManagedPropertyNames.isEmpty()) throw new IllegalStateException("***** The following properties are defined in this plugin's " + "descriptor but have no coresponding ManagedProperties: " + missingManagedPropertyNames); } return; } private static void populateManagedPropertyFromProperty(Property property, PropertyDefinition propertyDefinition, @NotNull ManagedProperty managedProperty, @Nullable PropertySimple customProperty) { if (property == null || (property instanceof PropertySimple && ((PropertySimple)property).getStringValue() == null)) { // The property is unset, which translates to "removed" in Profile Service lingo. // We will also set the ManagedProperty's MetaValue to a default value - this will be handled by the // conversion performed below by the property's adapter. managedProperty.setRemoved(true); } // If the ManagedProperty defines a default value, assume it's more definitive than any default value that may // have been defined in the plugin descriptor, and update the PropertyDefinition to use that as its default // value. MetaValue defaultValue = managedProperty.getDefaultValue(); if (defaultValue != null) updateDefaultValueOnPropertyDefinition(propertyDefinition, defaultValue); // See if there is a custom adapter defined for this property. PropertyAdapter propertyAdapter = PropertyAdapterFactory.getCustomPropertyAdapter(customProperty); MetaValue metaValue = managedProperty.getValue(); if (metaValue != null) { LOG.trace("Populating existing MetaValue of type " + metaValue.getMetaType() + " from RHQ property " + property + " with definition " + propertyDefinition + "..."); if (propertyAdapter == null) propertyAdapter = PropertyAdapterFactory.getPropertyAdapter(metaValue); propertyAdapter.populateMetaValueFromProperty(property, metaValue, propertyDefinition); } else { MetaType metaType = managedProperty.getMetaType(); if (propertyAdapter == null) propertyAdapter = PropertyAdapterFactory.getPropertyAdapter(metaType); LOG.trace("Converting property " + property + " with definition " + propertyDefinition + " to MetaValue of type " + metaType + "..."); metaValue = propertyAdapter.convertToMetaValue(property, propertyDefinition, metaType); managedProperty.setValue(metaValue); } } private static void updateDefaultValueOnPropertyDefinition(PropertyDefinition propertyDefinition, @NotNull MetaValue defaultValue) { if (!(propertyDefinition instanceof PropertyDefinitionSimple)) { LOG.debug("Cannot update default value on non-simple property definition " + propertyDefinition + "(default value is " + defaultValue + ")."); return; } MetaType metaType = defaultValue.getMetaType(); if (!metaType.isSimple() && !metaType.isEnum()) { LOG.debug("Cannot update default value on " + propertyDefinition + ", because default value's type (" + metaType + ") is not simple or enum."); return; } PropertyDefinitionSimple propertyDefinitionSimple = (PropertyDefinitionSimple)propertyDefinition; if (metaType.isSimple()) { SimpleValue defaultSimpleValue = (SimpleValue)defaultValue; Serializable value = defaultSimpleValue.getValue(); propertyDefinitionSimple.setDefaultValue((value != null) ? value.toString() : null); } else { // defaultValueMetaType.isEnum() EnumValue defaultEnumValue = (EnumValue)defaultValue; Serializable value = defaultEnumValue.getValue(); propertyDefinitionSimple.setDefaultValue((value != null) ? value.toString() : null); } } public static MetaType convertPropertyDefinitionToMetaType(PropertyDefinition propDef) { MetaType memberMetaType; if (propDef instanceof PropertyDefinitionSimple) { PropertySimpleType propSimpleType = ((PropertyDefinitionSimple)propDef).getType(); memberMetaType = convertPropertySimpleTypeToSimpleMetaType(propSimpleType); } else if (propDef instanceof PropertyDefinitionList) { // TODO (very low priority, since lists of lists are not going to be at all common) memberMetaType = null; } else if (propDef instanceof PropertyDefinitionMap) { Map<String,PropertyDefinition> memberPropDefs = ((PropertyDefinitionMap)propDef).getPropertyDefinitions(); if (memberPropDefs.isEmpty()) throw new IllegalStateException("PropertyDefinitionMap doesn't contain any member PropertyDefinitions."); // NOTE: We assume member prop defs are all of the same type, since for MapCompositeMetaTypes, they have to be. PropertyDefinition mapMemberPropDef = memberPropDefs.values().iterator().next(); MetaType mapMemberMetaType = convertPropertyDefinitionToMetaType(mapMemberPropDef); memberMetaType = new MapCompositeMetaType(mapMemberMetaType); } else { throw new IllegalStateException("List member PropertyDefinition has unknown type: " + propDef.getClass().getName()); } return memberMetaType; } private static MetaType convertPropertySimpleTypeToSimpleMetaType(PropertySimpleType memberSimpleType) { MetaType memberMetaType; Class memberClass; switch (memberSimpleType) { case BOOLEAN: memberClass = Boolean.class; break; case INTEGER: memberClass = Integer.class; break; case LONG: memberClass = Long.class; break; case FLOAT: memberClass = Float.class; break; case DOUBLE: memberClass = Double.class; break; default: memberClass = String.class; break; } memberMetaType = SimpleMetaType.resolve(memberClass.getName()); return memberMetaType; } /** * Takes the Configuration parameter object and converts it into a MetaValue array, which can them be passed * in with the invoke method to the ProfileService to fire the operation of a resource. * * @param managedOperation Operation that will be fired and stores the parameter types for the operation * @param parameters set of Parameter Values that the OperationFacet sent to the Component * @param operationDefinition the RHQ operation definition * @return MetaValue[] array of MetaValues representing the parameters; if there are no parameters, an empty array * will be returned */ @NotNull public static MetaValue[] convertOperationsParametersToMetaValues(@NotNull ManagedOperation managedOperation, @NotNull Configuration parameters, @NotNull OperationDefinition operationDefinition) { ConfigurationDefinition paramsConfigDef = operationDefinition.getParametersConfigurationDefinition(); if (paramsConfigDef == null) return new MetaValue[0]; ManagedParameter[] managedParams = managedOperation.getParameters(); // this is guaranteed to be non-null Map<String, PropertyDefinition> paramPropDefs = paramsConfigDef.getPropertyDefinitions(); MetaValue[] paramMetaValues = new MetaValue[managedParams.length]; for (int i = 0; i < managedParams.length; i++) { ManagedParameter managedParam = managedParams[i]; String paramName = managedParam.getName(); Property paramProp = parameters.get(paramName); PropertyDefinition paramPropDef = paramPropDefs.get(paramName); MetaType metaType = managedParam.getMetaType(); PropertyAdapter propertyAdapter = PropertyAdapterFactory.getPropertyAdapter(metaType); LOG.trace("Converting RHQ operation param property " + paramProp + " with definition " + paramPropDef + " to MetaValue of type " + metaType + "..."); MetaValue paramMetaValue = propertyAdapter.convertToMetaValue(paramProp, paramPropDef, metaType); // NOTE: There's no need to set the value on the ManagedParameter, since the invoke() API takes an array of // MetaValues. paramMetaValues[i] = paramMetaValue; } return paramMetaValues; } public static void convertManagedOperationResults(ManagedOperation operation, MetaValue resultMetaValue, Configuration complexResults, OperationDefinition operationDefinition) { ConfigurationDefinition resultConfigDef = operationDefinition.getResultsConfigurationDefinition(); // Don't return any results if we have no definition with which to display them if (resultConfigDef == null || resultConfigDef.getPropertyDefinitions().isEmpty()) { if (resultMetaValue != null) { LOG.error("Plugin error: Operation [" + operationDefinition.getName() + "] is defined as returning no results, but it returned non-null results: " + resultMetaValue.toString()); } return; } else { Map<String, PropertyDefinition> resultPropDefs = resultConfigDef.getPropertyDefinitions(); // There should and must be only one property definition to map to the results from the Profile Service, // otherwise there will be a huge mismatch. if (resultPropDefs.size() > 1) LOG.error("Operation [" + operationDefinition.getName() + "] is defined with multiple result properties: " + resultPropDefs.values()); PropertyDefinition resultPropDef = resultPropDefs.values().iterator().next(); // Don't return any results, if the actual result object is null. if (resultMetaValue == null) { // Check if result is required or not, and if it is, log an error. if (resultPropDef.isRequired()) { LOG.error("Plugin error: Operation [" + operationDefinition.getName() + "] is defined as returning a required result, but it returned null."); } return; } MetaType resultMetaType = operation.getReturnType(); if (!MetaTypeUtils.instanceOf(resultMetaValue, resultMetaType)) LOG.debug("Profile Service Error: Result type (" + resultMetaType + ") of [" + operation.getName() + "] ManagedOperation does not match the type of the value returned by invoke() (" + resultMetaValue + ")."); PropertyAdapter propertyAdapter = PropertyAdapterFactory.getPropertyAdapter(resultMetaValue); Property resultProp = propertyAdapter.convertToProperty(resultMetaValue, resultPropDef); complexResults.put(resultProp); } } public static void convertMetricValuesToMeasurement(MeasurementReport report, ManagedProperty metricProperty, MeasurementScheduleRequest request, ResourceType resourceType, String deploymentName) { String metricName = metricProperty.getName(); MetaType type = metricProperty.getMetaType(); MetaValue value = metricProperty.getValue(); if (value != null) { MeasurementAdapter measurementAdapter = MeasurementAdapterFactory.getMeasurementPropertyAdapter(type); MeasurementDefinition measurementDefinition = ResourceTypeUtils.getMeasurementDefinition(resourceType, metricName); if (measurementDefinition != null) { measurementAdapter.setMeasurementData(report, value, request, measurementDefinition); } } else { LOG.debug("Unable to obtain metric data for resource: " + deploymentName + " metric: " + metricName); } } }