/*******************************************************************************
* gMix open source project - https://svs.informatik.uni-hamburg.de/gmix/
* Copyright (C) 2014 SVS
*
* 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, either version 3 of the License, or
* (at your option) any later version.
*
* 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, see <http://www.gnu.org/licenses/>.
*******************************************************************************/
package staticContent.evaluation.testbed.plan;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.log4j.Logger;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import staticContent.evaluation.testbed.plan.global.GlobalExecutionPlan;
import staticContent.evaluation.testbed.plan.global.SimpleExecutionPlan;
import staticContent.evaluation.testbed.plan.global.GlobalExecutionPlan.Network_Mode;
import staticContent.evaluation.testbed.plan.node.Application;
import staticContent.evaluation.testbed.plan.node.NodeExecutionPlan;
import staticContent.evaluation.testbed.plan.node.VirtualNodeApplication;
import staticContent.evaluation.testbed.statistic.Metric;
public class XMLtoObject {
protected static Logger logger = Logger.getLogger(XMLtoObject.class);
protected static int numOfRuns = 0;
protected static List<String> nodesList;
protected static Map<String, String> hostnameIpAssignments;
public static GlobalExecutionPlan createGlobalExecutionPlan(Element globalXML) throws UnknownHostException {
String experimentType = globalXML.getAttribute("type");
Network_Mode networkMode = (experimentType.equals("real")) ? Network_Mode.REAL : Network_Mode.MODELNET;
File sourceFile = new File(System.getProperty("user.dir") +"/dist/" +globalXML.getAttribute("source"));
NodeList applicationsList = globalXML.getElementsByTagName("applications");
NodeList variableParamsList = globalXML.getElementsByTagName("variableParams");
NodeList runConfigList = globalXML.getElementsByTagName("runConfig");
NodeList nodesXMLList = globalXML.getElementsByTagName("testnodes");
Element testnodes = (Element) nodesXMLList.item(0);
NodeList nodesElementList = testnodes.getElementsByTagName("node");
nodesList = new ArrayList<String>();
hostnameIpAssignments = new HashMap<String,String>();
for (int i = 0; i < nodesElementList.getLength(); i++) {
Element currentNode = (Element) nodesElementList.item(i);
String hostname = currentNode.getAttribute("hostname");
// get IP of hostname
InetAddress address = InetAddress.getByName(hostname);
String hostAddress = address.getHostAddress();
nodesList.add(Integer.parseInt(currentNode.getAttribute("idx")), hostAddress);
hostnameIpAssignments.put(hostname, hostAddress);
}
Element applications = (Element) applicationsList.item(0);
Element variableParams = (Element) variableParamsList.item(0);
Element runConfig = (Element) runConfigList.item(0);
SimpleExecutionPlan globalPlan = new SimpleExecutionPlan(networkMode);
globalPlan.setTestnodeNames(hostnameIpAssignments.keySet());
if (!runConfig.getAttribute("executionTime").equals("")) {
globalPlan.setExecutionTime(Long.parseLong(runConfig.getAttribute("executionTime")));
}
if (!runConfig.getAttribute("settlingTime").equals("")) {
globalPlan.setSettlingTime(Long.parseLong(runConfig.getAttribute("settlingTime")));
}
if (!runConfig.getAttribute("terminationEvents").equals("")) {
globalPlan.setTerminationEvents(readTerminationEvents(runConfig));
}
for (int i = 0; i < nodesList.size(); i++) {
NodeExecutionPlan nodeExecutionPlan = createNodeExecutionPlan(globalPlan, experimentType, sourceFile, runConfig, applications, variableParams, nodesList, i);
globalPlan.addNodePlan(nodeExecutionPlan);
}
readEvalMetrics(globalXML, globalPlan);
globalPlan.setNumOfExperiments(numOfRuns);
if (networkMode == Network_Mode.MODELNET) {
readModelnetTopology(globalXML, globalPlan);
}
return globalPlan;
}
protected static Set<String> readTerminationEvents(Element runConfig) {
Set<String> result = new HashSet<String>();
if (!runConfig.getAttribute("terminationEvents").equals("")) {
List<String> values = Arrays.asList(runConfig.getAttribute("terminationEvents").split(","));
for (String string : values) {
result.add(string);
}
}
return result;
}
public static NodeExecutionPlan createNodeExecutionPlan(GlobalExecutionPlan globalPlan, String experimentType, File sourceFile, Element runConfigXML, Element applicationsXML, Element variableParamsXML, List<String> nodesList, int nodeIndex) {
NodeExecutionPlan nodePlan = new NodeExecutionPlan(globalPlan, nodesList.get(nodeIndex), sourceFile);
NodeList runList = runConfigXML.getElementsByTagName("run");
NodeList appList = applicationsXML.getElementsByTagName("app");
List<Element> appElementList = new ArrayList<Element>();
for (int i = 0; i < appList.getLength(); i++) {
Element currentApp = (Element) appList.item(i);
appElementList.add(Integer.parseInt(currentApp.getAttribute("idx")), currentApp);
}
Map<String,List<String>> variableParams = readVariableParams(variableParamsXML);
globalPlan.setVariableParameters(variableParams);
for (int i = 0; i < runList.getLength(); i++) {
Element currentRun = (Element) runList.item(i);
int currentNodeIndex = Integer.parseInt(currentRun.getAttribute("nodeIdx"));
int currentAppIndex = Integer.parseInt(currentRun.getAttribute("appIdx"));
// if run belongs to the selected node, add the application to the nodePlan
if (currentNodeIndex == nodeIndex) {
Element appElement = appElementList.get(currentAppIndex);
Application currentApplication = createApplication(experimentType, nodesList, appElement, currentRun, nodeIndex);
currentApplication.setVariableParameters(variableParams);
nodePlan.addApplication(currentApplication);
}
}
return nodePlan;
}
public static Application createApplication(String experimentType, List<String> nodesList, Element appElementXML, Element currentRunXML, int nodeIndex) {
String classpath = appElementXML.getAttribute("classpath");
String className = appElementXML.getAttribute("className");
Map<String,String> environmentVariables = createArgumentMap("environmentVariables", appElementXML, currentRunXML);
Map<String,String> appArguments = createArgumentMap("appArgs", appElementXML, currentRunXML);
Map<String,String> vmArguments = createArgumentMap("vmArgs", appElementXML, currentRunXML);
// System.out.println("classpath: " + classpath + " className: " + className);
// System.out.println("env: " + environmentVariables + " args: " + appArguments +" vmArgs: "+vmArguments);
switch(experimentType) {
case "modelnet":
return new VirtualNodeApplication(classpath, className, environmentVariables, appArguments, vmArguments, nodesList.get(nodeIndex));
default:
return new Application(classpath, className, environmentVariables, appArguments, vmArguments, nodesList.get(nodeIndex));
}
}
public static Map<String,String> createArgumentMap(String argumentClass, Element appXML, Element runXML) {
NodeList appEnvVarList = appXML.getElementsByTagName(argumentClass);
NodeList runEnvVarList = runXML.getElementsByTagName(argumentClass);
if (runEnvVarList.getLength() > 0) {
Element runEnvVarElement = (Element) runEnvVarList.item(0);
NodeList runEnvVarArgList = runEnvVarElement.getElementsByTagName("arg");
if (runEnvVarArgList.getLength() > 0) {
return createArgumentMap(runEnvVarArgList);
}
else if (appEnvVarList.getLength() > 0) {
Element appEnvVarElement = (Element) appEnvVarList.item(0);
NodeList appEnvVarArgList = appEnvVarElement.getElementsByTagName("arg");
if (appEnvVarArgList.getLength() > 0) {
return createArgumentMap(appEnvVarArgList);
}
}
}
else if (appEnvVarList.getLength() > 0) {
Element appEnvVarElement = (Element) appEnvVarList.item(0);
NodeList appEnvVarArgList = appEnvVarElement.getElementsByTagName("arg");
if (appEnvVarArgList.getLength() > 0) {
return createArgumentMap(appEnvVarArgList);
}
}
return new HashMap<String,String>();
}
public static Map<String,String> createArgumentMap(NodeList elementsXML) {
Map<String,String> result = new HashMap<String,String>();
for (int i = 0; i < elementsXML.getLength(); i++) {
Element currentArg = (Element) elementsXML.item(i);
result.put(currentArg.getAttribute("name"), currentArg.getAttribute("value"));
}
return result;
}
protected static void readEvalMetrics(Element globalXML, GlobalExecutionPlan globalPlan) {
NodeList evalMetricsList = globalXML.getElementsByTagName("evalMetrics");
Element evalMetrics = (Element) evalMetricsList.item(0);
if (evalMetrics == null) {
logger.error("Section 'evalMetrics' in configuration is missing. No metrics are defined.");
System.exit(1);
}
NodeList metricList = evalMetrics.getElementsByTagName("metric");
if (metricList.getLength() == 0) {
logger.error("No metrics in section 'evalMetrics' of the configuration are defined.");
System.exit(1);
}
HashSet<Metric> wantedMetrics = new HashSet<Metric>();
for (int i = 0; i < metricList.getLength(); i++) {
Element currentMetric = (Element) metricList.item(i);
wantedMetrics.add(Metric.valueOf(currentMetric.getAttribute("name")));
}
globalPlan.setEvalMetrics(wantedMetrics);
}
protected static Map<String,List<String>> readVariableParams(Element variableParamsXML) {
Map<String,List<String>> result = new HashMap<String,List<String>>();
NodeList variableParamsList = variableParamsXML.getElementsByTagName("param");
int minNumOfValues = -1;
for (int i = 0; i < variableParamsList.getLength(); i++) {
Element currentParam = (Element) variableParamsList.item(i);
String content = currentParam.getTextContent().trim();
if (content.length() == 0) {
minNumOfValues = 0;
continue;
}
List<String> values = new ArrayList<String>(Arrays.asList(content.split(",")));
result.put(currentParam.getAttribute("name"), values);
if (minNumOfValues == -1) {
minNumOfValues = values.size();
}
else {
minNumOfValues = Math.min(minNumOfValues, values.size());
}
}
if (minNumOfValues == 0) {
result = new HashMap<String,List<String>>();
}
else {
for (String paramName: result.keySet()) {
List<String> values = result.get(paramName);
for (int i = values.size()-1; i >= minNumOfValues; i--) {
values.remove(i);
}
result.put(paramName, values);
}
}
numOfRuns = minNumOfValues;
return result;
}
public static Map<String, Set<String>> createNodeVirtualIpAssignment(Element virtualModelXML) throws XMLConfigException {
if (hostnameIpAssignments == null || hostnameIpAssignments.isEmpty()) {
throw new XMLConfigException("No host nodes are configured. Call method 'createGlobalExecutionPlan' first.");
}
Map<String, Set<String>> result = new HashMap<String, Set<String>>();
NodeList hostList = virtualModelXML.getElementsByTagName("host");
for (int i = 0; i < hostList.getLength(); i++) {
Element currentHost = (Element) hostList.item(i);
String hostAddress = hostnameIpAssignments.get(currentHost.getAttribute("hostname"));
NodeList virtualNodeList = currentHost.getElementsByTagName("virtnode");
for (int j = 0; j < virtualNodeList.getLength(); j++) {
Element currentNode = (Element) virtualNodeList.item(j);
if (!result.containsKey(hostAddress)) {
result.put(hostAddress, new HashSet<String>());
}
result.get(hostAddress).add(currentNode.getAttribute("vip"));
}
}
return result;
}
protected static void readModelnetTopology(Element globalXML, GlobalExecutionPlan globalPlan) {
NodeList virtualTopologyList = globalXML.getElementsByTagName("virtualTopology");
Element virtualTopologyElement = (Element) virtualTopologyList.item(0);
File virtualTopologyPath = new File(System.getProperty("user.dir") +"/inputOutput/testbed/experimentDefinitions/" +virtualTopologyElement.getAttribute("path"));
if (!virtualTopologyPath.exists()) {
logger.error("Virtual topology file: "+virtualTopologyPath.getAbsolutePath()+" does not exist.");
System.exit(1);
}
globalPlan.setVirtualTopologyFile(virtualTopologyPath);
NodeList emulatorNodesXml = globalXML.getElementsByTagName("emulatornodes");
Element emulatorNodeList = (Element) emulatorNodesXml.item(0);
NodeList emulatorNodes = emulatorNodeList.getElementsByTagName("node");
Set<String> emulatorNames = new HashSet<String>();
for (int i = 0; i < emulatorNodes.getLength(); i++) {
Element currentNode = (Element) emulatorNodes.item(i);
emulatorNames.add(currentNode.getAttribute("hostname"));
}
globalPlan.setModelnetEmulatorNames(emulatorNames);
NodeList testnodesXML = globalXML.getElementsByTagName("testnodes");
Element testnodeList = (Element) testnodesXML.item(0);
NodeList testnodes = testnodeList.getElementsByTagName("node");
generateModelnetRealTopologyFile(emulatorNodes, testnodes, globalPlan);
}
public static void generateModelnetRealTopologyFile(NodeList emulatorNodesXML, NodeList testodesXML, GlobalExecutionPlan globalPlan) {
String topologyFileName = System.getProperty("user.dir") +"/inputOutput/testbed/tmp/real_topology.xml";
Writer writer = null;
try {
writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(topologyFileName), "utf-8"));
writer.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
writer.write("<hardware>\n");
for (int i = 0; i < emulatorNodesXML.getLength(); i++) {
Element currentNode = (Element) emulatorNodesXML.item(i);
String netIfParam = (currentNode.getAttribute("netdev") != null) ? " netdev=\""+currentNode.getAttribute("netdev")+"\"" : "";
writer.write("<emul hostname=\""+currentNode.getAttribute("hostname")+"\""+netIfParam+" />\n");
}
for (int i = 0; i < testodesXML.getLength(); i++) {
Element currentNode = (Element) testodesXML.item(i);
String netIfParam = (currentNode.getAttribute("netdev") != null) ? " netdev=\""+currentNode.getAttribute("netdev")+"\"" : "";
writer.write("<host hostname=\""+currentNode.getAttribute("hostname")+"\""+netIfParam+" />\n");
}
writer.write("</hardware>\n");
} catch (IOException ex) {
// report
} finally {
try {writer.close();} catch (Exception ex) {}
}
globalPlan.setRealTopologyFile(new File(topologyFileName));
}
}