com.mgmtp.perfload.core.common.config.XmlConfigReader.java Source code

Java tutorial

Introduction

Here is the source code for com.mgmtp.perfload.core.common.config.XmlConfigReader.java

Source

/*
 * Copyright (c) 2002-2014 mgm technology partners GmbH
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.mgmtp.perfload.core.common.config;

import static com.google.common.collect.Lists.newArrayListWithCapacity;
import static com.google.common.collect.Lists.newArrayListWithExpectedSize;
import static com.google.common.collect.Maps.newHashMapWithExpectedSize;
import static com.google.common.io.Files.toByteArray;
import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.startsWith;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Pattern;

import javax.xml.transform.stream.StreamSource;

import org.apache.commons.lang3.text.StrTokenizer;
import org.dom4j.Document;
import org.dom4j.Element;
import org.xml.sax.InputSource;

import com.google.common.base.Charsets;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ListMultimap;
import com.mgmtp.perfload.core.common.util.PropertiesMap;
import com.mgmtp.perfload.core.common.xml.Dom4jReader;

/**
 * Reads the test configuration from an XML file. The XML file may use XIncludes. It is validated
 * against the schema {@code config.xsd}.
 * 
 * @author rnaegele
 */
public class XmlConfigReader {

    private static final String SCHEMA_RESOURCE = "perfload-testplan.xsd";
    private static final Pattern MARKER_PATTERN = Pattern.compile("\\d+;\\[\\[marker\\]\\];[^;]*;(left|right);");

    private final File baseDir;
    private final File testplansDir;
    private final File testplanFile;

    /**
     * @param testplanFileName
     *            the path to the XML config file
     */
    public XmlConfigReader(final File baseDir, final String testplanFileName) {
        this.baseDir = baseDir;
        this.testplansDir = new File(baseDir, "testplans");
        this.testplanFile = new File(testplansDir, testplanFileName);
    }

    /**
     * Reads the contents of the XML file into a {@link TestplanConfig} object.
     * 
     * @return the Config object
     */
    public TestplanConfig readConfig() throws Exception {
        Element testplan = loadDocument().getRootElement();

        ListMultimap<ProcessKey, LoadProfileEvent> loadProfileEvents = readLoadProfileEvents(testplan);
        List<TestJar> testJars = readTestJars(testplan);

        int totalProcessCount = loadProfileEvents.keySet().size();
        int totalThreadCount = loadProfileEvents.size();

        String guiceModule = testplan.elementTextTrim("module");
        PropertiesMap properties = readProperties(testplan);

        Map<ProcessKey, TestConfig> testConfigs = newHashMapWithExpectedSize(totalProcessCount);
        for (Entry<ProcessKey, Collection<LoadProfileEvent>> entry : loadProfileEvents.asMap().entrySet()) {
            ProcessKey key = entry.getKey();
            Collection<LoadProfileEvent> events = entry.getValue();
            testConfigs.put(key, new TestConfig(key.getProcessId(), guiceModule, properties, events));
        }

        long startTimeOfLastEvent = 0;
        for (LoadProfileEvent loadProfileEvent : loadProfileEvents.values()) {
            startTimeOfLastEvent = Math.max(startTimeOfLastEvent, loadProfileEvent.getStartTime());
        }

        List<String> jvmArgs = readJvmArgs(testplan);

        List<ProcessConfig> processConfigs = newArrayListWithCapacity(loadProfileEvents.keySet().size());
        for (ProcessKey key : loadProfileEvents.keySet()) {
            processConfigs.add(new ProcessConfig(key.getProcessId(), key.getDaemonId(), jvmArgs));
        }

        return new TestplanConfig(testplanFile, loadProfileEvents, testJars, testConfigs, processConfigs,
                totalProcessCount, totalThreadCount, startTimeOfLastEvent);
    }

    // Loads the DOM document
    private Document loadDocument() throws Exception {
        String schemaUrl = Thread.currentThread().getContextClassLoader().getResource(SCHEMA_RESOURCE).toString();
        String xmlFileUrl = testplanFile.toURI().toString();
        return Dom4jReader.loadDocument(new InputSource(xmlFileUrl), new StreamSource(schemaUrl),
                Charsets.UTF_8.name());
    }

    private ListMultimap<ProcessKey, LoadProfileEvent> readLoadProfileEvents(final Element testplan)
            throws IOException {
        ListMultimap<ProcessKey, LoadProfileEvent> eventsByProcess = ArrayListMultimap.create();
        String loadProfile = testplan.elementTextTrim("loadProfile");

        // relative to testplan
        File loadProfileConfigFile = new File(new File(testplanFile.getParentFile(), "loadprofiles"), loadProfile);

        try (BufferedReader br = new BufferedReader(
                new InputStreamReader(new FileInputStream(loadProfileConfigFile), "UTF-8"))) {
            StrTokenizer st = StrTokenizer.getCSVInstance();
            st.setDelimiterChar(';');

            for (String line = null; (line = br.readLine()) != null;) {
                // ignore line that are blank, commented out, or represent markers
                if (isBlank(line) || startsWith(line, "#") || MARKER_PATTERN.matcher(line).matches()) {
                    continue;
                }

                st.reset(line);
                String[] tokens = st.getTokenArray();

                long startTime = Long.parseLong(tokens[0]);
                String operation = tokens[1];
                String target = tokens[2];
                int daemonId = Integer.parseInt(tokens[3]);
                int processId = Integer.parseInt(tokens[4]);

                eventsByProcess.put(new ProcessKey(daemonId, processId),
                        new LoadProfileEvent(startTime, operation, target, daemonId, processId));
            }
        }

        return eventsByProcess;
    }

    private List<TestJar> readTestJars(final Element testplan) throws IOException {
        File jarDir = new File(baseDir, "test-lib");
        @SuppressWarnings("unchecked")
        List<Element> jarElems = testplan.element("testJars").elements();
        List<TestJar> result = newArrayListWithCapacity(jarElems.size());
        for (Element jarElem : jarElems) {
            String fileName = jarElem.getTextTrim();
            byte[] jarBytes = toByteArray(new File(jarDir, fileName));
            result.add(new TestJar(fileName, jarBytes));
        }
        return ImmutableList.copyOf(result);
    }

    private PropertiesMap readProperties(final Element testplan) {
        PropertiesMap properties = new PropertiesMap();
        Element element = testplan.element("properties");
        if (element != null) {
            @SuppressWarnings("unchecked")
            List<Element> propsElems = element.elements();
            for (Element propsElem : propsElems) {
                String name = propsElem.attributeValue("name");
                String value = propsElem.getText();
                properties.put(name, value);
            }
        }
        return properties;
    }

    private List<String> readJvmArgs(final Element testplan) {
        List<String> result = newArrayListWithExpectedSize(2);
        Element element = testplan.element("jvmargs");
        if (element != null) {
            @SuppressWarnings("unchecked")
            List<Element> propsElems = element.elements();
            for (Element propsElem : propsElems) {
                result.add(propsElem.getTextTrim());
            }
        }
        return ImmutableList.copyOf(result);
    }
}