package org.radargun.config; import org.radargun.Version; import org.radargun.stages.ScenarioCleanupStage; import org.radargun.stages.ScenarioDestroyStage; import org.radargun.stages.ScenarioInitStage; import org.w3c.dom.Element; /** * Generates XSD file describing RadarGun 3.0 configuration. * <p/> * There are basically two parts: hand-coded stable configuration * (such as cluster & configuration definitions), and stage lists * with properties, converters etc. When stages are added/removed * or properties change, the XSD file is automatically updated to * reflect this. * <p/> * This file is expected to be run from command-line, or rather * build script. * * @author Radim Vansa <rvansa@redhat.com> */ public class BenchmarkSchemaGenerator extends SchemaGenerator implements ConfigSchema { protected static final String NAMESPACE = "urn:radargun:benchmark:" + Version.SCHEMA_VERSION; protected static final String CORE_NAMESPACE = StageHelper.NAMESPACE_ROOT + "core:" + Version.SCHEMA_VERSION; private static final String CORE_PREFIX = "core:"; private static final String TYPE_CLUSTER_BASE = "cluster_base"; private static final String TYPE_CLUSTER = "cluster"; private static final String TYPE_PROPERTY = "property"; private static final String TYPE_INIT = "init"; private static final String TYPE_DESTROY = "destroy"; private static final String TYPE_CLEANUP = "cleanup"; private static final String TYPE_SETUP_BASE = "setup_base"; public BenchmarkSchemaGenerator() { super(null, NAMESPACE, "radargun-"); } /** * Generates benchmark scheme file */ @Override protected void generate() { createSchemaElement(NAMESPACE); addImport(CORE_NAMESPACE, "radargun-core-" + Version.SCHEMA_VERSION + ".xsd", "core"); intType = generateSimpleType(int.class, DefaultConverter.class); Element benchmarkElement = doc.createElementNS(NS_XS, XS_ELEMENT); benchmarkElement.setAttribute(XS_NAME, ELEMENT_BENCHMARK); schema.appendChild(benchmarkElement); Element benchmarkComplex = doc.createElementNS(NS_XS, XS_COMPLEX_TYPE); benchmarkElement.appendChild(benchmarkComplex); Element benchmarkSequence = createSequence(benchmarkComplex); Element masterComplex = createComplexElement(benchmarkSequence, ELEMENT_MASTER, 0, 1, null); addAttribute(masterComplex, ATTR_BIND_ADDRESS, false); addAttribute(masterComplex, ATTR_PORT, intType.toString(), null, false); Element clustersChoice = createChoice(benchmarkSequence, 0, 1); Element clustersComplex = createComplexElement(clustersChoice, ELEMENT_CLUSTERS, 0, 1, null); Element clusterChoice = createChoice(clustersComplex, 1, -1); Element baseClusterType = createComplexType(TYPE_CLUSTER_BASE, null, true, false, null); Element groupComplex = createComplexElement(createSequence(baseClusterType), ELEMENT_GROUP, 0, -1, null); Element sizedClusterType = createComplexType(TYPE_CLUSTER, THIS_PREFIX + TYPE_CLUSTER_BASE, true, false, null); Element scaleElement = createComplexElement(clusterChoice, ELEMENT_SCALE, 0, -1, null); createReference(clusterChoice, ELEMENT_CLUSTER, THIS_PREFIX + TYPE_CLUSTER); createReference(createSequence(scaleElement), ELEMENT_CLUSTER, THIS_PREFIX + TYPE_CLUSTER_BASE); addAttribute(groupComplex, ATTR_NAME, true); addAttribute(groupComplex, ATTR_SIZE, intType.toString(), null, true); addAttribute(sizedClusterType, ATTR_SIZE, intType.toString(), null, false); addAttribute(scaleElement, ATTR_FROM, intType.toString(), null, true); addAttribute(scaleElement, ATTR_TO, intType.toString(), null, true); addAttribute(scaleElement, ATTR_INC, intType.toString(), null, false); Element propertyType = createComplexType(TYPE_PROPERTY, "string", false, false, null); addAttribute(propertyType, ATTR_NAME, true); Element configurationsComplex = createComplexElement(benchmarkSequence, ELEMENT_CONFIGURATIONS, 1, 1, null); Element configSequence = createSequence(configurationsComplex); Element setupBase = createComplexType(TYPE_SETUP_BASE, null, true, true, "Common base for setup and setup template"); Element setupBaseSequence = createSequence(setupBase); addAttribute(setupBase, ATTR_BASE, false); Element templateComplex = createComplexElement(configSequence, ELEMENT_TEMPLATE, 0, -1, THIS_PREFIX + TYPE_SETUP_BASE, "Setup template"); addAttribute(templateComplex, ATTR_NAME, true); Element configComplex = createComplexElement(configSequence, ELEMENT_CONFIG, 1, -1, null); Element setupComplex = createComplexElement(createSequence(configComplex), ELEMENT_SETUP, 1, -1, THIS_PREFIX + TYPE_SETUP_BASE, null); Element env = createComplexElement(setupBaseSequence, ELEMENT_ENVIRONMENT, 0, 1, "Environment variables."); Element envSequence = createSequence(env); Element var = createComplexElement(envSequence, ELEMENT_VAR, 1, 1, "Environment variable definition."); addAttribute(var, ATTR_NAME, true); addAttribute(var, ATTR_VALUE, true); XmlType vmArgsType = generateClass(VmArgs.class); createReference(setupBase, ELEMENT_VM_ARGS, vmArgsType.toString(), 0, 1); createAny(setupBase); addAttribute(configComplex, ATTR_NAME, true); addAttribute(setupComplex, ATTR_PLUGIN, true); addAttribute(setupComplex, ATTR_GROUP, false); createComplexType(TYPE_INIT, CORE_PREFIX + class2xmlId(ScenarioInitStage.class), true, false, null); createReference(benchmarkSequence, ELEMENT_INIT, THIS_PREFIX + TYPE_INIT, 0, 1); ScenarioSchemaGenerator scenarioSchemaGenerator = new ScenarioSchemaGenerator(); scenarioSchemaGenerator.setDocSchema(doc, schema); scenarioSchemaGenerator.intType = intType; scenarioSchemaGenerator.generateStagesType(0); Element scenarioType = createComplexType(TYPE_SCENARIO, THIS_PREFIX + TYPE_STAGES, true, false, null); addAttribute(scenarioType, ATTR_URL, false); createReference(benchmarkSequence, ELEMENT_SCENARIO, THIS_PREFIX + TYPE_SCENARIO); createComplexType(TYPE_DESTROY, CORE_PREFIX + class2xmlId(ScenarioDestroyStage.class), true, false, null); createReference(benchmarkSequence, ELEMENT_DESTROY, THIS_PREFIX + TYPE_DESTROY, 0, 1); createComplexType(TYPE_CLEANUP, CORE_PREFIX + class2xmlId(ScenarioCleanupStage.class), true, false, null); createReference(benchmarkSequence, ELEMENT_CLEANUP, THIS_PREFIX + TYPE_CLEANUP, 0, 1); Element reportsComplex = createComplexElement(benchmarkSequence, ELEMENT_REPORTS, 0, 1, null); Element reporterComplex = createComplexElement(createSequence(reportsComplex), ELEMENT_REPORTER, 1, -1, null); Element reporterSequence = createSequence(reporterComplex); createAny(reporterSequence); Element reportComplex = createComplexElement(reporterSequence, ELEMENT_REPORT, 0, -1, null); Element reportSequence = createSequence(reportComplex); createAny(reportSequence); addAttribute(reporterComplex, ATTR_TYPE, true); } @Override protected String findDocumentation(Class<?> clazz) { org.radargun.config.Stage stageAnnotation = (org.radargun.config.Stage) clazz.getAnnotation(org.radargun.config.Stage.class); if (stageAnnotation != null) return stageAnnotation.doc(); return null; } /** * Generate the XSD file. First argument is directory where the XSD file should be placed * (it will be named radargun-{version}.xsd. */ public static void main(String[] args) { if (args.length < 1 || args[0] == null) throw new IllegalArgumentException("No schema location directory specified!"); new BenchmarkSchemaGenerator().generate(args[0], String.format("radargun-benchmark-%s.xsd", Version.SCHEMA_VERSION)); } }