/* * RHQ Management Platform * Copyright (C) 2005-2008 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.perftest; import java.net.URL; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBElement; import javax.xml.bind.JAXBException; import javax.xml.bind.Unmarshaller; import javax.xml.bind.util.ValidationEventCollector; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.rhq.plugins.perftest.calltime.CalltimeFactory; import org.rhq.plugins.perftest.calltime.ConfigurableCallTimeDataFactory; import org.rhq.plugins.perftest.calltime.EmptyCalltimeFactory; import org.rhq.plugins.perftest.calltime.SimpleCallTimeDataFactory; import org.rhq.plugins.perftest.configuration.ConfigurationFactory; import org.rhq.plugins.perftest.configuration.SimpleConfigurationFactory; import org.rhq.plugins.perftest.content.ContentFactory; import org.rhq.plugins.perftest.content.SimpleContentFactory; import org.rhq.plugins.perftest.measurement.EmptyMeasurementFactory; import org.rhq.plugins.perftest.measurement.MeasurementFactory; import org.rhq.plugins.perftest.measurement.OOBNumericMeasurementFactory; import org.rhq.plugins.perftest.measurement.SimpleNumericMeasurementFactory; import org.rhq.plugins.perftest.resource.EmptyResourceFactory; import org.rhq.plugins.perftest.resource.ResourceFactory; import org.rhq.plugins.perftest.resource.SimpleResourceFactory; import org.rhq.plugins.perftest.scenario.CalltimeGenerator; import org.rhq.plugins.perftest.scenario.ConfigurableCallTimeDataGenerator; import org.rhq.plugins.perftest.scenario.ConfigurationGenerator; import org.rhq.plugins.perftest.scenario.ContentGenerator; import org.rhq.plugins.perftest.scenario.MeasurementGenerator; import org.rhq.plugins.perftest.scenario.OOBNumericMeasurementGenerator; import org.rhq.plugins.perftest.scenario.Resource; import org.rhq.plugins.perftest.scenario.ResourceGenerator; import org.rhq.plugins.perftest.scenario.Scenario; import org.rhq.plugins.perftest.scenario.SimpleCallTimeDataGenerator; import org.rhq.plugins.perftest.scenario.SimpleConfigurationGenerator; import org.rhq.plugins.perftest.scenario.SimpleContentGenerator; import org.rhq.plugins.perftest.scenario.SimpleNumericMeasurementGenerator; import org.rhq.plugins.perftest.scenario.SimpleResourceGenerator; import org.rhq.plugins.perftest.scenario.SimpleTraitMeasurementGenerator; import org.rhq.plugins.perftest.scenario.TraitGenerator; import org.rhq.plugins.perftest.trait.EmptyTraitFactory; import org.rhq.plugins.perftest.trait.SimpleTraitFactory; import org.rhq.plugins.perftest.trait.TraitFactory; /** * Loads performance testing scenarios and parses into usable components by the RHQ resource components. * * @author Jason Dobies */ public class ScenarioManager { // Constants -------------------------------------------- private static final ScenarioManager INSTANCE = new ScenarioManager(); /** * System property that must be set to indicate what scenario to use. The value of this property should be the file * name of the scenario, minus the ".xml". For example, to use the scenario defined in high-servers.xml, this * property should be set to "high-servers". */ public static final String SCENARIO_PROPERTY = "rhq.perftest.scenario"; /** * Resource factory used when a scenario doesn't define any resources of a particular type. */ private static final EmptyResourceFactory EMPTY_RESOURCE_FACTORY = new EmptyResourceFactory(); /** * Measurement factory used when a scenario doesn't define any metrics for a particular resource type. */ private static final EmptyMeasurementFactory EMPTY_MEASUREMENT_FACTORY = new EmptyMeasurementFactory(); /** * Calltime factory used when a scenario doesn't define any metrics for a particular resource type. */ private static final EmptyCalltimeFactory EMPTY_CALLTIME_FACTORY = new EmptyCalltimeFactory(); /** * Trait factory used when a scenario doesn't define any metrics for a particular resource type. */ private static final TraitFactory EMPTY_TRAIT_FACTORY = new EmptyTraitFactory(); // Attributes -------------------------------------------- private final Log log = LogFactory.getLog(ScenarioManager.class); /** * JAXB representation of the loaded scenario. */ private Scenario scenario; /** * Mapping of resource type name to resource factory used in discovery. */ private Map<String, ResourceFactory> resourceFactories = new HashMap<String, ResourceFactory>(); /** * Mapping of resource type name to measurement factory to field all of its configured measurements. If we * eventually want to be able to configure the value for each metric on a resource type, this will need to be * changed. */ private Map<String, MeasurementFactory> measurementFactories = new HashMap<String, MeasurementFactory>(); private Map<String, CalltimeFactory> calltimeFactories = new HashMap<String, CalltimeFactory>(); private Map<String, TraitFactory> traitFactories = new HashMap<String, TraitFactory>(); /** * Mapping of resource type name to configuration factory to populate the plugin configuration for newly discovered * resources. If we eventually want to customize the plugin configuration for each resource of this type, this will * need to be changed. */ private Map<String, ConfigurationFactory> pluginConfigurationFactories = new HashMap<String, ConfigurationFactory>(); /** * Mapping of package type name to content factory to field requests to discover content. This implementation has * the limitation that each type in the plugin descriptor has a unique name. */ private Map<String, ContentFactory> contentFactories = new HashMap<String, ContentFactory>(); // Constructors -------------------------------------------- /** * Singleton constructor. */ private ScenarioManager() { loadScenario(); } // Public -------------------------------------------- /** * Returns an instance of this class. * * @return instance of this class */ public static ScenarioManager getInstance() { return INSTANCE; } public boolean isEnabled() { return this.scenario != null; } /** * Returns the resource factory defined in the scenario for the specified resource type. * * @param resourceTypeName indicates which resource factory to return * * @return resource factory instance to use to generate the discovery for resources of this type; this will never be * <code>null</code>. */ public ResourceFactory getResourceFactory(String resourceTypeName) { ResourceFactory resourceFactory = resourceFactories.get(resourceTypeName); // Lazy load the factory if (resourceFactory == null) { Resource resource = findResource(resourceTypeName); if (resource == null) { resourceFactory = EMPTY_RESOURCE_FACTORY; } else { ResourceGenerator generator = resource.getResourceGenerator().getValue(); resourceFactory = createResourceFactory(generator); } resourceFactories.put(resourceTypeName, resourceFactory); } return resourceFactory; } /** * Returns the measurement factory defined in the scenario for the specified resource type. * * @param resourceTypeName indicates the resource for which we're retrieving metrics * * @return measurement factory instance used to generate measurement values; this will never be <code>null</code>. */ public MeasurementFactory getMeasurementFactory(String resourceTypeName) { MeasurementFactory measurementFactory = measurementFactories.get(resourceTypeName); // Lazy load the factory if (measurementFactory == null) { Resource resource = findResource(resourceTypeName); if (resource == null) { measurementFactory = EMPTY_MEASUREMENT_FACTORY; } else { JAXBElement<? extends MeasurementGenerator> element = resource.getMeasurementGenerator(); if (element == null) { measurementFactory = EMPTY_MEASUREMENT_FACTORY; } else { MeasurementGenerator generator = element.getValue(); measurementFactory = createMeasurementFactory(generator); } } measurementFactories.put(resourceTypeName, measurementFactory); } return measurementFactory; } public CalltimeFactory getCalltimeFactory(String resourceTypeName) { CalltimeFactory calltimeFactory= calltimeFactories.get(resourceTypeName); if (calltimeFactory == null ) { Resource resource = findResource(resourceTypeName); if (resource == null) { calltimeFactory = EMPTY_CALLTIME_FACTORY; } else { JAXBElement<? extends CalltimeGenerator> element = resource.getCalltimeGenerator(); if (element == null) { calltimeFactory = EMPTY_CALLTIME_FACTORY; } else { CalltimeGenerator generator = element.getValue(); calltimeFactory = createCalltimeFactory(generator); } } calltimeFactories.put(resourceTypeName, calltimeFactory); } return calltimeFactory; } public TraitFactory getTraitFactory(String resourceTypeName) { TraitFactory traitFactory = traitFactories.get(resourceTypeName); if (traitFactory == null) { Resource resource = findResource(resourceTypeName); if (resource == null) { traitFactory = EMPTY_TRAIT_FACTORY; } else { JAXBElement<? extends TraitGenerator> element = resource.getTraitGenerator(); if (element == null) { traitFactory = EMPTY_TRAIT_FACTORY; } else { TraitGenerator generator = element.getValue(); traitFactory = createTraitFactory(generator); } } traitFactories.put(resourceTypeName,traitFactory); } return traitFactory; } /** * Returns the configuration factory defined in the scenario for creating plugin configurations for the specified * resource type. * * @param resourceTypeName indicates the resource for which we're retriving the plugin configuration * * @return configuration factory instance used to generate the plugin configurations; this may be <code>null</code> * if the resource does not define a generator for its plugin configuration */ public ConfigurationFactory getPluginConfigurationFactory(String resourceTypeName) { ConfigurationFactory configurationFactory = pluginConfigurationFactories.get(resourceTypeName); // Lazy load the factory if (configurationFactory == null) { Resource resource = findResource(resourceTypeName); if (resource != null) { JAXBElement<? extends ConfigurationGenerator> element = resource.getPluginConfigurationGenerator(); if (element != null) { ConfigurationGenerator generator = element.getValue(); configurationFactory = createConfigurationFactory(generator); pluginConfigurationFactories.put(resourceTypeName, configurationFactory); } } } return configurationFactory; } /** * Returns the content factory defined in the scenario for discovering packages of the specified type. * * @param resourceTypeName indicates the resource in which the type is defined * @param packageTypeName indicated the type being discovered * * @return factory used for discovery; this may be <code>null</code> if the scenario does not define a generator for * a particular type */ public ContentFactory getContentFactory(String resourceTypeName, String packageTypeName) { ContentFactory contentFactory = contentFactories.get(packageTypeName); // Lazy load the factory if (contentFactory == null) { Resource resource = findResource(resourceTypeName); if (resource != null) { List<JAXBElement<? extends ContentGenerator>> elements = resource.getContentGenerator(); if (elements != null) { for (JAXBElement<? extends ContentGenerator> element : elements) { ContentGenerator generator = element.getValue(); if (generator.getPackageType().equals(packageTypeName)) { contentFactory = createContentFactory(generator); contentFactories.put(packageTypeName, contentFactory); } } } } } return contentFactory; } // Private -------------------------------------------- /** * Creates the appropriate resource factory instance based on the provided generator. * * @param generator read from the scenario * * @return resource factory instance */ private ResourceFactory createResourceFactory(ResourceGenerator generator) { if (generator instanceof SimpleResourceGenerator) { return new SimpleResourceFactory((SimpleResourceGenerator) generator); } log.warn("No factory for generator " + generator.toString() + " specified"); return null; } /** * Creates the appropriate measurement factory instance based on the provided generator. * * @param generator read from the scenario * * @return measurement factory instance */ private MeasurementFactory createMeasurementFactory(MeasurementGenerator generator) { if (generator instanceof SimpleNumericMeasurementGenerator) { return new SimpleNumericMeasurementFactory(); } else if (generator instanceof OOBNumericMeasurementGenerator) { return new OOBNumericMeasurementFactory(); } return null; } /** * Creates the appropriate calltime factory instance based on the provided generator. * * @param generator read from the scenario * * @return calltime factory instance */ private CalltimeFactory createCalltimeFactory(CalltimeGenerator generator) { if (generator instanceof SimpleCallTimeDataGenerator) { return new SimpleCallTimeDataFactory(); } else if (generator instanceof ConfigurableCallTimeDataGenerator) { return new ConfigurableCallTimeDataFactory((ConfigurableCallTimeDataGenerator)generator); } return null; } /** * Creates an appropriate Traits factory based on the provided generator. * @param generator read from the scenario * @return TraitFactory instance */ private TraitFactory createTraitFactory(TraitGenerator generator) { if (generator instanceof SimpleTraitMeasurementGenerator) { return new SimpleTraitFactory(); } return null; } /** * Creates the appropriate configuration factory instance based on the provided generator. * * @param generator read from the scenario * * @return configuration factory instance */ private ConfigurationFactory createConfigurationFactory(ConfigurationGenerator generator) { if (generator instanceof SimpleConfigurationGenerator) { return new SimpleConfigurationFactory(); } return null; } /** * Creates the appropriate content factory instance based on the provided generator. * * @param generator read from the scenario * * @return factory instance */ private ContentFactory createContentFactory(ContentGenerator generator) { if (generator instanceof SimpleContentGenerator) { SimpleContentGenerator simpleGenerator = (SimpleContentGenerator) generator; return new SimpleContentFactory(simpleGenerator); } return null; } /** * Searches through the scenario for the resource type indicated. * * @param resourceType being loaded from the scenario * * @return scenario resource object describing how to generate resources of this type */ private Resource findResource(String resourceType) { List<Resource> allResources = scenario.getResource(); for (Resource resource : allResources) { if (resource.getType().equals(resourceType)) { return resource; } } return null; } /** * Determines what scenario to load and loads the JAXB objects representing the scenario. */ private void loadScenario() { // Determine scenario String scenarioName = System.getProperty(SCENARIO_PROPERTY); if (scenarioName == null) { log.info("Cannot find scenario name. Make sure the system property " + SCENARIO_PROPERTY + " is set."); return; } log.info("Loading Performance Testing Scenario [" + scenarioName + "]..."); ClassLoader loader = this.getClass().getClassLoader(); URL scenarioUrl = loader.getResource(scenarioName + ".xml"); // Load the JAXB stuff Class objectFactoryClass = null; try { objectFactoryClass = loader.loadClass("org.rhq.plugins.perftest.scenario.ObjectFactory"); } catch (ClassNotFoundException e) { log.error("Error finding class ObjectFactory", e); return; } JAXBContext jaxbContext; try { jaxbContext = JAXBContext.newInstance(objectFactoryClass); } catch (JAXBException e) { log.error("Could not instantiate JAXB context", e); return; } // Load the scenario try { Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); ValidationEventCollector vec = new ValidationEventCollector(); unmarshaller.setEventHandler(vec); this.scenario = (Scenario) unmarshaller.unmarshal(scenarioUrl); } catch (JAXBException e) { log.error("Scenario [" + scenarioName + "] could not be loaded from [" + scenarioUrl + "]." , e); return; } } }