import java.io.*; import java.util.*; import org.jdom2.*; /** * 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 extends XMLHelper { /** * Obtains an attribute value of the input/ output entries specified in adapter.config. * * @param doc The JDOM Document (adapter.config) * @param entry String formed as "{input or output}/{entity}" * @param val Attribute name as string * @return path as specified in adapter.config */ private static String getConfigVal(Document doc, String str, String val) { List<Attribute> valList = xQueryAttributes(doc, "//"+str+"/@"+val); if(valList.size()!=1) { System.err.println("Error while reading input/ output "+val+" value from adapter.config."); System.exit(-1); } return valList.get(0).getValue(); } public Adapter() { System.out.println("Adapter started."); try { //######### Input ############################### Document adapterConfig = readXml("./adapter.config"); String in_fmPath = getConfigVal(adapterConfig, "input/featuremodel", "path"); String in_scPath = getConfigVal(adapterConfig, "input/sensorconfig", "path"); String in_gmPath = getConfigVal(adapterConfig, "input/gazebomodel", "path"); String out_gmPath = getConfigVal(adapterConfig, "output/gazebomodel", "path"); String out_bnPath = getConfigVal(adapterConfig, "output/botname", "path"); String in_fmName = getConfigVal(adapterConfig, "input/featuremodel", "name"); String in_gmName = ""; String out_gmName = getConfigVal(adapterConfig, "output/gazebomodel", "name"); String out_bnName = getConfigVal(adapterConfig, "output/botname", "name"); Document featureModel = readXml(in_fmPath+in_fmName); List<Document> sensorConfigList = new ArrayList<Document>(); Document gazeboModel = null; //Get the selected mode (either NO_CHANGE or Custom) as String String mode = ""; List<Attribute> modeList = xQueryAttributes(featureModel, "//mode/@param"); if(modeList.size()==1) { mode = modeList.get(0).getValue(); } else { System.err.println("Invalid input in \'"+in_fmName+"\': NO_CHANGE/ Custom parameter could not be parsed."); System.exit(-1); } //Get all selected sensorconfig files as List<Document> switch(mode) { case "NO_CHANGE": break; case "Custom": List<Attribute> sensorList = xQueryAttributes(featureModel, "//sensor/@name"); List<String> scList = getFileNames(in_scPath); for(Attribute sensor : sensorList) { boolean inDirectory = false; for(String fileName : scList) { if(fileName.equals(sensor.getValue()+".xml")) inDirectory = true; } if(!inDirectory) { System.err.println("Cannot handle \'"+sensor.getValue()+"\': No input file known."); System.exit(-1); } } for(Attribute sensor : sensorList) { sensorConfigList.add(readXml(in_scPath+sensor.getValue()+".xml")); } break; default: System.err.println("Invalid input in \'"+in_fmName+"\': NO_CHANGE/ Custom parameter could not be parsed."); System.exit(-1); } //Get the selected .gazebo.xacro file as Document String botName = ""; List<Attribute> botList = xQueryAttributes(featureModel, "//templates/@name"); if(botList.size()==1) { botName = botList.get(0).getValue(); } else { System.err.println("Invalid input in \'"+in_fmName+"\': No or multiple bots selected."); System.exit(-1); } in_gmName = botName+".gazebo.xacro"; List<String> gmList = getFileNames(in_gmPath); boolean inDirectory = false; for(String fileName : gmList) { if(fileName.equals(in_gmName)) inDirectory = true; } if(!inDirectory) { System.err.println("Cannot handle \'"+botName+"\': No input file known."); System.exit(-1); } gazeboModel = readXml(in_gmPath+in_gmName); //############################################### //######### Operate on .gazebo.xacro ############ switch(mode) { case "NO_CHANGE": break; case "Custom": //Remove all existing sensors in template List<Element> removableSensorsList = xQueryElements(gazeboModel, "//sensor"); for(Element sensor : removableSensorsList) { Element entry = sensor.getParentElement(); if(entry.getName().equals("gazebo")) { entry.detach(); } else { System.out.println("Found a <sensor> element in \'"+in_gmName+ "\' that does not have a <gazebo> element as immediate parent. It was not removed, as this input is unexpected."); } } //Insert selected sensors into template for(Document sensorConfig : sensorConfigList) { List<Element> sensorList = xQueryElements(sensorConfig, "//gazebo"); if(sensorList.size()==1) { Element sensor = sensorList.get(0); //Warn if a sensor still contains $(arg ...) values List<Element> tagList = xQueryElements(sensor, "//*"); for(Element tag : tagList) { String text = tag.getText(); if(text.contains("$")) { System.out.println("Warning: a sensorconfig file still contains an abstract value: \'"+text+ "\'. It should be replaced with a set value, or the output .gazebo.xacro will likely be broken."); } } sensor.detach(); gazeboModel.getRootElement().addContent(sensor); } else { System.err.println("Invalid input. At least one sensorconfig file contains no or multiple <gazebo> entries."); System.exit(-1); } } break; default: System.err.println("Invalid input in \'"+in_fmName+"\': NO_CHANGE/ Custom parameter could not be parsed."); System.exit(-1); } //############################################### //######### Output result ####################### saveAsXml(gazeboModel, out_gmPath+out_gmName); BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(out_bnPath+out_bnName)); bufferedWriter.write(botName); bufferedWriter.close(); //############################################### } catch (Exception e) { e.printStackTrace(); } System.out.println("Adapter finished."); } }