An error occurred while loading the file. Please try again.
-
marvin authoredb300d23e
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
Adapter.java 10.96 KiB
import java.io.*;
import java.util.*;
import org.jdom2.*;
import org.jdom2.filter.Filters;
import org.jdom2.input.SAXBuilder;
import org.jdom2.output.XMLOutputter;
import org.jdom2.xpath.*;
/**
* Takes a featuremodel.xml file generated using FeatureModelConfigurator and a given
* ROS/ Gazebo .gazebo.xacro file.
* The .gazebo.xacro file is modified to support the features specified in the
* featuremodel.xml file.
*/
public class Adapter {
/**
* Reads an .xml file from file path and returns a JDOM document.
*
* @param src The .xml file path
* @return JDOM document
* @throws JDOMException
* @throws IOException
*/
public static Document readXml(String src) throws JDOMException, IOException {
File file = new File(src);
SAXBuilder saxBuilder = new SAXBuilder();
Document doc = saxBuilder.build(file);
return doc;
}
/**
* Saves the given Document as XML to the given path.
*
* @param oDoc The JDOM document
* @param sPath The output path
* @throws IOException
*/
public static void saveAsXml(Document oDoc, String sPath) throws IOException {
FileOutputStream dest = new FileOutputStream(sPath);
XMLOutputter xmlOutput = new XMLOutputter();
xmlOutput.output(oDoc, dest);
}
/**
* Executes given XPath expression for elements with JDOM Document as source.
*
* @param doc The JDOM Document
* @param xPath XPath expression
* @return List with all elements found or empty list if no match found
*/
public static List<Element> xQueryElements(Document doc, String xPath) {
XPathFactory xFactory = XPathFactory.instance();
XPathExpression<Element> expr = xFactory.compile(xPath, Filters.element());
List<Element> result = expr.evaluate(doc);
return result;
}
/**
* Executes given XPath expression for elements with Element as source.
*
* @param elem The Element
* @param xPath XPath expression
* @return List with all elements found or empty list if no match found
*/
public static List<Element> xQueryElements(Element elem, String xPath) {
XPathFactory xFactory = XPathFactory.instance();
XPathExpression<Element> expr = xFactory.compile(xPath, Filters.element());
List<Element> result = expr.evaluate(elem);
return result;
}
/**
* Executes given XPath expression for attributes.
*
* @param doc The JDOM Document
* @param xPath XPath expression
* @return List with all attributes found or empty list if no match found
*/
public static List<Attribute> xQueryAttributes(Document doc, String xPath) {
XPathFactory xFactory = XPathFactory.instance();
XPathExpression<Attribute> expr = xFactory.compile(xPath, Filters.attribute());
List<Attribute> result = expr.evaluate(doc);
return result;
}
/**
* Searches a document for the first occurrence of an xml tag.
*
* @param doc The JDOM Document
* @param elementName Name of the xml tag
* @return First element found or NULL if no match found
*/
public static Element searchFirstElement(Document doc, String elementName) {
//XPath index starts with 1; [] has a higher precedence than //
List<Element> query= xQueryElements(doc, "(//"+elementName+")[1]");
if(query.isEmpty()) return null;
return query.get(0);
}
/**
* Searches a document for all occurrences of an xml tag.
*
* @param doc The JDOM Document
* @param elementName Name of the xml tag
* @return List with all elements found or empty list if no match found
*/
public static List<Element> searchAllElements(Document doc, String elementName) {
return xQueryElements(doc, "//"+elementName);
}
/**
* Checks whether two elements have an equal xml tag.
* (Name of the xml tag and all attributes including their order must be equal)
*
* @param element1 Element1
* @param element2 Element2
* @return true if of equal tag or false if not
*/
public static boolean equalTag(Element element1, Element element2) {
List<Attribute> attributeList1 = element1.getAttributes();
List<Attribute> attributeList2 = element2.getAttributes();
if(!element1.getName().equals(element2.getName())) return false;
if(attributeList1.size()!=attributeList2.size()) return false;
for(int i=0; i<attributeList1.size(); i++) {
if(!attributeList1.get(i).getName().equals(attributeList2.get(i).getName())) return false;
if(!attributeList1.get(i).getValue().equals(attributeList2.get(i).getValue())) return false;
}
return true;
}
/**
* Recursive replacement of all text values in destElements with their corresponding
* new ones from srcElements.
* (srcElements and destElements must be matching tags!)
*
* TODO maybe add tags that are in srcElements but not yet in destElements
*
* @param srcElements Element list with new values
* @param destElements Element list with values to be replaced
* @return true if reached deepest Element or false if not
*/
public static boolean replace(List<Element> srcElements, List<Element> destElements) {
if(srcElements.isEmpty()&&destElements.isEmpty()) return true;
if(srcElements.isEmpty()^destElements.isEmpty()) {
System.err.println("Error during value replacement: Sensor xml trees have mismatching deph (maybe tags with no value)");
System.exit(-1);
}
for(Element src : srcElements) {
for(Element dest : destElements) {
if(equalTag(src, dest)) {
boolean deadEnd = replace(src.getChildren(), dest.getChildren());
if(deadEnd) dest.setText(src.getText());
break;
}
}
}
return false;
}
/**
* Obtains the path attribute for the input/ output files as specified in adapterconfig.xml.
*
* @param doc The JDOM Document (adapterconfig.xml)
* @param str {input or output}/{entity}
* @return path as specified in adapterconfig.xml
*/
private static String getConfigPath(Document doc, String str) {
List<Attribute> pathList = xQueryAttributes(doc, "//"+str+"/@path");
if(pathList.size()!=1) {
System.err.println("Error while reading input/ output path from adapterconfig.xml");
System.exit(-1);
}
return pathList.get(0).getValue();
}
/**
* Obtains the name attribute for the input/ output files as specified in adapterconfig.xml.
*
* @param doc The JDOM Document (adapterconfig.xml)
* @param str {input or output}/{entity}
* @return name as specified in adapterconfig.xml
*/
private static String getConfigName(Document doc, String str) {
List<Attribute> nameList = xQueryAttributes(doc, "//"+str+"/@name");
if(nameList.size()!=1) {
System.err.println("Error while reading input/ output name from adapterconfig.xml");
System.exit(-1);
}
return nameList.get(0).getValue();
}
/**
* @param args
*/
public static void main(String[] args) {
try {
//TODO##### Input ###############################
Document adapterConfig = readXml("./adapterconfig.xml");
String in_fmPath = getConfigPath(adapterConfig, "input/featuremodel");
String in_scPath = getConfigPath(adapterConfig, "input/sensorconfig");
String in_gmPath = getConfigPath(adapterConfig, "input/gazebomodel");
String out_gmPath = getConfigPath(adapterConfig, "output/gazebomodel");
//String in_gmName =
String out_gmName = getConfigName(adapterConfig, "output/gazebomodel");
Document featureModel = readXml(in_fmPath);
Document sensorConfig = readXml(in_scPath);
Document gazeboModel = null;
//TODO CustomBot not supported for now
List<Attribute> botList = xQueryAttributes(featureModel, "//module[@types='TurtleBot']/@name");
String botName = "";
String fileName = "";
switch(botList.size()) {
case 0:
System.err.println("Invalid input: No bot selected");
System.exit(-1);
break;
case 1:
botName = botList.get(0).getValue();
break;
default:
System.err.println("Invalid input: Multiple bots selected");
System.exit(-1);
}
//TODO get all .gazebo.xacro file names from /turtlebot3_description/urdf/ directory; match botName; select file
switch(botName) {
case "Burger":
fileName = "turtlebot3_burger.gazebo.xacro";
break;
case "Waffle":
fileName = "turtlebot3_waffle.gazebo.xacro";
break;
case "WafflePi":
fileName = "turtlebot3_waffle_pi.gazebo.xacro";
break;
default:
System.err.println("Cannot handle \'"+botName+"\': No input file known.");
System.exit(-1);
}
gazeboModel = readXml(in_gmPath+fileName);
//###############################################
//TODO##### Operate on .gazebo.xacro ############
List<Element> cSensorList = xQueryElements(sensorConfig, "//sensor");
List<Element> gSensorList = xQueryElements(gazeboModel, "//sensor");
boolean match = false;
if(cSensorList.isEmpty()) {
System.out.println("No new sensor values in sensorconfig.xml");
System.exit(-1);
}
if(gSensorList.isEmpty()) {
System.out.println("No sensors found in "+fileName);
System.exit(-1);
}
for(Element cSensor : cSensorList) {
for(Element gSensor : gSensorList) {
if(equalTag(cSensor, gSensor)) {
replace(cSensor.getChildren(),gSensor.getChildren());
match = true;
}
}
}
if(!match) System.out.println("No matching sensors could be found in sensorconfig.xml and "+fileName);
//###############################################
//######### Output result #######################
saveAsXml(gazeboModel, out_gmPath+out_gmName);
System.out.println("Adapter finished.");
//###############################################
} catch (JDOMException | IOException e) {
e.printStackTrace();
}
}
}
//Example dump
//hard-coded and only for demo purposes
//List<Element> cSensorList = xQueryElements(sensorConfig, "//sensor[@type='ray' and @name='lds_lfcd_sensor']");
//Element cSensor = cSensorList.get(0);
//
//List<Element> gSensorList = xQueryElements(gazeboModel, "//sensor[@type='ray' and @name='lds_lfcd_sensor']");
//Element gSensor = gSensorList.get(0);
//
//String new_min = cSensor.getChild("range").getChild("min").getText();
//String new_max = cSensor.getChild("range").getChild("max").getText();
//
//gSensor.getChild("ray").getChild("range").getChild("min").setText(new_min);
//gSensor.getChild("ray").getChild("range").getChild("max").setText(new_max);
//XPathExamples
//XPathFactory xFactory = XPathFactory.instance();
//XPathExpression<Element> xExpr = xFactory.compile("robot/gazebo/sensor/ray/range/min", Filters.element());
//Element test = xExpr.evaluateFirst(gazeboModel);
//List<Element> test2 = searchAllElements(gazeboModel, "min");
//List<Element> test3 = searchAllElements(gazeboModel, "max");
//Element test4 = searchFirstElement(gazeboModel, "plugin");
//List<Attribute> test5 = xQueryAttributes(gazeboModel, "(//plugin)[1]/@*");
//
//if(test != null) xmlOutput.output(test, System.out);
//System.out.println("\n");
//xmlOutput.output(test2, System.out);
//System.out.println("\n");
//xmlOutput.output(test3, System.out);
//System.out.println("\n");
//if(test4 != null) xmlOutput.output(test4, System.out);
//System.out.println("\n");
//for(Attribute a : test5) System.out.println(a.getName()+"="+a.getValue());