Java tutorial
/* * Jopr Management Platform * Copyright (C) 2005-2012 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; import java.lang.reflect.Array; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jboss.deployers.spi.management.ManagementView; import org.jboss.deployers.spi.management.deploy.DeploymentManager; import org.jboss.deployers.spi.management.deploy.DeploymentProgress; import org.jboss.deployers.spi.management.deploy.DeploymentStatus; import org.jboss.managed.api.ComponentType; import org.jboss.managed.api.ManagedComponent; import org.jboss.managed.api.ManagedDeployment; import org.jboss.managed.api.ManagedOperation; import org.jboss.managed.api.ManagedProperty; import org.jboss.managed.api.RunState; import org.jboss.metatype.api.values.ArrayValue; import org.jboss.metatype.api.values.CollectionValue; import org.jboss.metatype.api.values.CompositeValue; import org.jboss.metatype.api.values.EnumValue; import org.jboss.metatype.api.values.MetaValue; import org.jboss.metatype.api.values.SimpleValue; import org.rhq.core.domain.configuration.Configuration; import org.rhq.core.domain.configuration.ConfigurationUpdateStatus; import org.rhq.core.domain.configuration.PropertySimple; import org.rhq.core.domain.configuration.definition.ConfigurationDefinition; import org.rhq.core.domain.measurement.AvailabilityType; import org.rhq.core.domain.measurement.DataType; import org.rhq.core.domain.measurement.MeasurementDataNumeric; import org.rhq.core.domain.measurement.MeasurementDataTrait; 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.core.pluginapi.configuration.ConfigurationFacet; import org.rhq.core.pluginapi.configuration.ConfigurationUpdateReport; import org.rhq.core.pluginapi.inventory.DeleteResourceFacet; import org.rhq.core.pluginapi.inventory.ResourceContext; import org.rhq.core.pluginapi.measurement.MeasurementFacet; import org.rhq.core.pluginapi.operation.OperationFacet; import org.rhq.core.pluginapi.operation.OperationResult; import org.rhq.core.util.exception.ThrowableUtil; import org.rhq.plugins.jbossas5.util.ConversionUtils; import org.rhq.plugins.jbossas5.util.DebugUtils; import org.rhq.plugins.jbossas5.util.DeploymentUtils; import org.rhq.plugins.jbossas5.util.ResourceComponentUtils; import org.rhq.plugins.jbossas5.util.ResourceTypeUtils; /** * Service ResourceComponent for all {@link ManagedComponent}s in a Profile. * * @author Ian Springer * @author Jason Dobies * @author Mark Spritzler */ public class ManagedComponentComponent extends AbstractManagedComponent implements ConfigurationFacet, DeleteResourceFacet, OperationFacet, MeasurementFacet { public static interface Config { String COMPONENT_TYPE = "componentType"; String COMPONENT_SUBTYPE = "componentSubtype"; String COMPONENT_NAME = "componentName"; String TEMPLATE_NAME = "templateName"; String COMPONENT_NAME_PROPERTY = "componentNameProperty"; } protected static final char PREFIX_DELIMITER = '|'; private final Log log = LogFactory.getLog(this.getClass()); /** * The availability refresh interval specifies a duration that if exceeded means a managed * component refresh is needed to perform an availability check. That duration is set * to 15 minutes. */ private static final long AVAIL_REFRESH_INTERVAL = 1000 * 60 * 15; // 15 minutes /** * The ManagedComponent is fetched from the server in {@link #getManagedComponent} throughout * the life cycle of this resource component. For example during metrics collections * when getValues is invoked, getManagedComponent is called. Any time getManagedComponent * is called the lastComponentRefresh timestamp is updated. This timestamp is used in * {@link #getAvailability} to determine whether or not a component is needed to * perform an availability check. */ private long lastComponentRefresh = 0L; private long availRefreshInterval = AVAIL_REFRESH_INTERVAL; private RunState runState = RunState.UNKNOWN; private String componentName; private ComponentType componentType; // ResourceComponent Implementation -------------------------------------------- public AvailabilityType getAvailability() { long timeSinceComponentRefresh = System.currentTimeMillis() - lastComponentRefresh; if (timeSinceComponentRefresh > availRefreshInterval) { if (log.isDebugEnabled()) { log.debug("The availability refresh interval for [resourceKey: " + getResourceContext().getResourceKey() + ", type: " + componentType + ", name: " + componentName + "] has been exceeded by " + (timeSinceComponentRefresh - availRefreshInterval) + " ms. Reloading managed component."); } getManagedComponent(); } if (runState == RunState.RUNNING) { return AvailabilityType.UP; } else { if (log.isDebugEnabled()) { log.debug(componentType + " component '" + componentName + "' was not running, state was : " + runState); } return AvailabilityType.DOWN; } } public void start(ResourceContext<ProfileServiceComponent<?>> resourceContext) throws Exception { super.start(resourceContext); componentType = ConversionUtils.getComponentType(getResourceContext().getResourceType()); Configuration pluginConfig = resourceContext.getPluginConfiguration(); componentName = pluginConfig.getSimple(Config.COMPONENT_NAME).getStringValue(); initAvailRefreshInterval(resourceContext); if (log.isTraceEnabled()) { log.trace("Started ResourceComponent for " + getResourceDescription() + ", managing " + this.componentType + " component '" + this.componentName + "'."); } } public void stop() { super.stop(); } // ConfigurationComponent Implementation -------------------------------------------- public Configuration loadResourceConfiguration() { Configuration resourceConfig; ManagedComponent managedComponent = getManagedComponent(); try { Map<String, ManagedProperty> managedProperties = managedComponent.getProperties(); Map<String, PropertySimple> customProps = ResourceComponentUtils .getCustomProperties(getResourceContext().getPluginConfiguration()); if (this.log.isDebugEnabled()) this.log.debug("*** AFTER LOAD:\n" + DebugUtils.convertPropertiesToString(managedProperties)); resourceConfig = ConversionUtils.convertManagedObjectToConfiguration(managedProperties, customProps, getResourceContext().getResourceType()); } catch (Exception e) { RunState runState = managedComponent.getRunState(); if (runState == RunState.RUNNING) { this.log.error("Failed to load configuration for " + getResourceDescription() + ".", e); } else { this.log.debug("Failed to load configuration for " + getResourceDescription() + ", but managed component is not in the RUNNING state.", e); } throw new RuntimeException(ThrowableUtil.getAllMessages(e)); } return resourceConfig; } public void updateResourceConfiguration(ConfigurationUpdateReport configurationUpdateReport) { Configuration resourceConfig = configurationUpdateReport.getConfiguration(); Configuration pluginConfig = getResourceContext().getPluginConfiguration(); try { ManagedComponent managedComponent = getManagedComponent(); Map<String, ManagedProperty> managedProperties = managedComponent.getProperties(); Map<String, PropertySimple> customProps = ResourceComponentUtils.getCustomProperties(pluginConfig); if (this.log.isDebugEnabled()) this.log.debug("*** BEFORE UPDATE:\n" + DebugUtils.convertPropertiesToString(managedProperties)); ConversionUtils.convertConfigurationToManagedProperties(managedProperties, resourceConfig, getResourceContext().getResourceType(), customProps); if (this.log.isDebugEnabled()) this.log.debug("*** AFTER UPDATE:\n" + DebugUtils.convertPropertiesToString(managedProperties)); updateComponent(managedComponent); configurationUpdateReport.setStatus(ConfigurationUpdateStatus.SUCCESS); } catch (Exception e) { this.log.error("Failed to update configuration for " + getResourceDescription() + ".", e); configurationUpdateReport.setStatus(ConfigurationUpdateStatus.FAILURE); configurationUpdateReport.setErrorMessage(ThrowableUtil.getAllMessages(e)); } } // DeleteResourceFacet Implementation -------------------------------------------- public void deleteResource() throws Exception { DeploymentManager deploymentManager = getConnection().getDeploymentManager(); if (!deploymentManager.isRedeploySupported()) throw new UnsupportedOperationException("Deletion of " + getResourceContext().getResourceType().getName() + " Resources is not currently supported."); ManagedComponent managedComponent = getManagedComponent(); log.debug("Removing " + getResourceDescription() + " with component " + toString(managedComponent) + "..."); ManagementView managementView = getConnection().getManagementView(); managementView.removeComponent(managedComponent); ManagedDeployment parentDeployment = managedComponent.getDeployment(); log.debug("Redeploying parent deployment '" + parentDeployment.getName() + "' in order to complete removal of component " + toString(managedComponent) + "..."); DeploymentProgress progress = deploymentManager.redeploy(parentDeployment.getName()); DeploymentStatus redeployStatus = DeploymentUtils.run(progress); if (redeployStatus.isFailed()) { log.error( "Failed to redeploy parent deployment '" + parentDeployment.getName() + "during removal of component " + toString(managedComponent) + " - removal may not persist when the app server is restarted.", redeployStatus.getFailure()); } managementView.load(); } // OperationFacet Implementation -------------------------------------------- public OperationResult invokeOperation(String name, Configuration parameters) throws Exception { return invokeOperation(getManagedComponent(), name, parameters); } protected OperationResult invokeOperation(ManagedComponent managedComponent, String name, Configuration parameters) throws Exception { OperationDefinition operationDefinition = getOperationDefinition(name); ManagedOperation managedOperation = getManagedOperation(managedComponent, operationDefinition); // Convert parameters into MetaValue array. MetaValue[] parameterMetaValues = ConversionUtils.convertOperationsParametersToMetaValues(managedOperation, parameters, operationDefinition); // invoke() takes a varargs, so we need to pass an empty array, rather than null. MetaValue resultMetaValue = managedOperation.invoke(parameterMetaValues); OperationResult result = new OperationResult(); // Convert result MetaValue to corresponding Property type. ConversionUtils.convertManagedOperationResults(managedOperation, resultMetaValue, result.getComplexResults(), operationDefinition); // If this is a lifecycle operation ask for an avail check boolean availCheck = name.toLowerCase().equals("stop") || name.toLowerCase().contains("start"); if (availCheck) { getResourceContext().getAvailabilityContext().requestAvailabilityCheck(); } return result; } // MeasurementFacet Implementation -------------------------------------------- public void getValues(MeasurementReport report, Set<MeasurementScheduleRequest> metrics) throws Exception { getValues(getManagedComponent(), report, metrics); } protected void getValues(ManagedComponent managedComponent, MeasurementReport report, Set<MeasurementScheduleRequest> metrics) throws Exception { RunState runState = managedComponent.getRunState(); for (MeasurementScheduleRequest request : metrics) { try { String value = getMeasurement(managedComponent, request.getName()); addValueToMeasurementReport(report, request, value); } catch (Exception e) { if (runState == RunState.RUNNING) { log.error("Failed to collect metric for " + request, e); } else { log.debug("Failed to collect metric for " + request + ", but managed component is not in the RUNNING state.", e); } } } } protected String getMeasurement(ManagedComponent component, String metricName) throws Exception { if ("runState".equals(metricName)) { return component.getRunState().name(); } else { Object value = getSimpleValue(component, metricName); return value == null ? null : toString(value); } } protected void updateComponent(ManagedComponent managedComponent) throws Exception { log.trace("Updating " + getResourceDescription() + " with component " + toString(managedComponent) + "..."); ManagementView managementView = getConnection().getManagementView(); managementView.updateComponent(managedComponent); managementView.load(); } // ------------------------------------------------------------------------------ /** * The name of the measurement schedule request (i.e. the metric name) can be in one of two forms: * <p/> * [prefix'|']simplePropertyName (e.g. "maxTime" or "ThreadPool|currentThreadCount") * [prefix'|']compositePropertyName'.'key (e.g. "consumerCount" or "messageStatistics.count") * * @param managedComponent a managed component * @param request a measurement schedule request * @return the metric value */ @Nullable protected Object getSimpleValue(ManagedComponent managedComponent, MeasurementScheduleRequest request) { String metricName = request.getName(); return getSimpleValue(managedComponent, metricName); } @Nullable protected Object getSimpleValue(ManagedComponent managedComponent, String metricName) { int pipeIndex = metricName.indexOf(PREFIX_DELIMITER); // Remove the prefix if there is one (e.g. "ThreadPool|currentThreadCount" -> "currentThreadCount"). String compositePropName = (pipeIndex == -1) ? metricName : metricName.substring(pipeIndex + 1); int dotIndex = compositePropName.indexOf('.'); String metricPropName = (dotIndex == -1) ? compositePropName : compositePropName.substring(0, dotIndex); ManagedProperty metricProp = managedComponent.getProperty(metricPropName); if (metricProp == null) { return null; } MetaValue metaValue; if (dotIndex == -1) { metaValue = metricProp.getValue(); } else { CompositeValue compositeValue = (CompositeValue) metricProp.getValue(); String key = compositePropName.substring(dotIndex + 1); metaValue = compositeValue.get(key); } return getInnerValue(metaValue); } /** * The name of the measurement schedule request (i.e. the metric name) can be in one of two forms: * <p/> * [prefix'|']simplePropertyName (e.g. "maxTime" or "ThreadPool|currentThreadCount") * [prefix'|']compositePropertyName'.'key (e.g. "consumerCount" or "messageStatistics.count") * * @param managedComponent a managed component * @param request a measurement schedule request * @return the metric value */ @Nullable protected ManagedProperty getManagedProperty(ManagedComponent managedComponent, MeasurementScheduleRequest request) { String metricName = request.getName(); int pipeIndex = metricName.indexOf(PREFIX_DELIMITER); // Remove the prefix if there is one (e.g. "ThreadPool|currentThreadCount" -> "currentThreadCount"). String compositePropName = (pipeIndex == -1) ? metricName : metricName.substring(pipeIndex + 1); int dotIndex = compositePropName.indexOf('.'); String metricPropName = (dotIndex == -1) ? compositePropName : compositePropName.substring(0, dotIndex); ManagedProperty metricProp = managedComponent.getProperty(metricPropName); return metricProp; } // TODO: Move this to a utility class. @Nullable protected static Object getInnerValue(MetaValue metaValue) { if (metaValue == null) { return null; } Object value; if (metaValue.getMetaType().isSimple()) { SimpleValue simpleValue = (SimpleValue) metaValue; value = simpleValue.getValue(); } else if (metaValue.getMetaType().isEnum()) { EnumValue enumValue = (EnumValue) metaValue; value = enumValue.getValue(); } else if (metaValue.getMetaType().isArray()) { ArrayValue arrayValue = (ArrayValue) metaValue; value = arrayValue.getValue(); } else if (metaValue.getMetaType().isCollection()) { CollectionValue collectionValue = (CollectionValue) metaValue; List list = new ArrayList(); for (MetaValue element : collectionValue.getElements()) { list.add(getInnerValue(element)); } value = list; } else { value = metaValue.toString(); } return value; } protected void addValueToMeasurementReport(MeasurementReport report, MeasurementScheduleRequest request, Object value) { if (value == null) { return; } String stringValue = toString(value); DataType dataType = request.getDataType(); switch (dataType) { case MEASUREMENT: try { MeasurementDataNumeric dataNumeric = new MeasurementDataNumeric(request, Double.valueOf(stringValue)); report.addData(dataNumeric); } catch (NumberFormatException e) { log.error("Profile service did not return a numeric value as expected for metric [" + request.getName() + "] - value returned was " + value + ".", e); } break; case TRAIT: MeasurementDataTrait dataTrait = new MeasurementDataTrait(request, stringValue); report.addData(dataTrait); break; default: throw new IllegalStateException("Unsupported measurement data type: " + dataType); } } protected ComponentType getComponentType() { return componentType; } protected String getComponentName() { return componentName; } protected ManagedComponent getManagedComponent() { ManagedComponent managedComponent; try { ManagementView managementView = getConnection().getManagementView(); managedComponent = managementView.getComponent(this.componentName, this.componentType); } catch (Exception e) { runState = RunState.UNKNOWN; throw new RuntimeException( "Failed to load [" + this.componentType + "] ManagedComponent [" + this.componentName + "].", e); } if (managedComponent == null) { runState = RunState.UNKNOWN; throw new IllegalStateException("Failed to find [" + this.componentType + "] ManagedComponent named [" + this.componentName + "]."); } if (log.isTraceEnabled()) { log.trace("Retrieved " + toString(managedComponent) + "."); } lastComponentRefresh = System.currentTimeMillis(); runState = managedComponent.getRunState(); return managedComponent; } @NotNull private OperationDefinition getOperationDefinition(String operationName) { ResourceType resourceType = getResourceContext().getResourceType(); OperationDefinition operationDefinition = ResourceTypeUtils.getOperationDefinition(resourceType, operationName); if (operationDefinition == null) throw new IllegalStateException("Operation named '" + operationName + "' is not defined for Resource type '" + resourceType.getName() + "' in the '" + resourceType.getPlugin() + "' plugin's descriptor."); return operationDefinition; } @NotNull private ManagedOperation getManagedOperation(ManagedComponent managedComponent, OperationDefinition operationDefinition) { Set<ManagedOperation> operations = managedComponent.getOperations(); for (ManagedOperation operation : operations) { ConfigurationDefinition paramsConfigDef = operationDefinition.getParametersConfigurationDefinition(); int paramCount = (paramsConfigDef != null) ? paramsConfigDef.getPropertyDefinitions().size() : 0; if (operation.getName().equals(operationDefinition.getName()) && (operation.getParameters().length == paramCount)) return operation; } throw new IllegalStateException("ManagedOperation named '" + operationDefinition.getName() + "' not found on ManagedComponent [" + managedComponent + "]."); } private static String toString(ManagedComponent managedComponent) { Map<String, ManagedProperty> properties = managedComponent.getProperties(); return managedComponent.getClass().getSimpleName() + "@" + System.identityHashCode(managedComponent) + "[" + "type=" + managedComponent.getType() + ", name=" + managedComponent.getName() + ", properties=" + properties.getClass().getSimpleName() + "@" + System.identityHashCode(properties) + "]"; } private static String toString(@NotNull Object value) { if (value.getClass().isArray()) { StringBuilder buffer = new StringBuilder(); int lastIndex = Array.getLength(value) - 1; for (int i = 0; i < Array.getLength(value); i++) { buffer.append(String.valueOf(Array.get(value, i))); if (i == lastIndex) { break; } buffer.append(", "); } return buffer.toString(); } else { return value.toString(); } } private void initAvailRefreshInterval(ResourceContext<ProfileServiceComponent<?>> context) { ProfileServiceComponent<?> component = context.getParentResourceComponent(); while (component != null) { if (component instanceof ApplicationServerComponent) { break; } component = (ProfileServiceComponent<?>) component.getResourceContext().getParentResourceComponent(); } if (component == null) { if (log.isDebugEnabled()) { log.debug("Failed to find parent " + ApplicationServerComponent.class.getSimpleName() + ". Using default component refresh interval, " + AVAIL_REFRESH_INTERVAL + " ms"); } return; } String interval = component.getResourceContext().getPluginConfiguration() .getSimpleValue("serviceAvailabilityRefreshInterval", Long.toString(AVAIL_REFRESH_INTERVAL)); availRefreshInterval = Long.parseLong(interval) * 1000 * 60; } }