Skip to content
Snippets Groups Projects
Adapter.java 12.9 KiB
Newer Older
marvin's avatar
marvin committed
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);
	}
	
marvin's avatar
marvin committed
	/**
	 * Takes a gives directory path and lists all files directly in it.
	 * (Does not visit sub-directories recursively)
	 * 
	 * @param path			Path to the directory
	 * @return ArrayList with all file names
	 */
	public static ArrayList<String> getFileNames(String path) {
		ArrayList<String> fileNames = new ArrayList<String>();
		File directory = new File(path);
		File[] contentList = directory.listFiles();

		for (File file : contentList) {
			if (file.isFile()) fileNames.add(file.getName());
		}
		
		return fileNames;
	}
	
marvin's avatar
marvin committed
	/**
	 * 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()) {
marvin's avatar
marvin committed
			System.err.println("Error during value replacement: Sensor xml trees have mismatching deph (maybe tags with no value)");
marvin's avatar
marvin committed
			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;
				}
			}
		}
marvin's avatar
marvin committed
		
marvin's avatar
marvin committed
		return false;
	}
	
marvin's avatar
marvin committed
	/**
	 * Obtains an attribute value of the input/ output entries specified in adapterconfig.xml.
marvin's avatar
marvin committed
	 * 
	 * @param doc		The JDOM Document (adapterconfig.xml)
	 * @param entry		String formed as "{input or output}/{entity}"
	 * @param val		Attribute name as string
marvin's avatar
marvin committed
	 * @return path as specified in adapterconfig.xml
	 */
	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 adapterconfig.xml");
marvin's avatar
marvin committed
			System.exit(-1);
		}

		return valList.get(0).getValue();
marvin's avatar
marvin committed
	/**
	 * @param args
	 */
	public static void main(String[] args) {
marvin's avatar
marvin committed
//		System.out.println("Adapter started.");
//		
//		try {
//			//TODO##### Input ###############################			
//			Document adapterConfig = readXml("./adapterconfig.xml");
//			
//			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_scName = "";
//			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> sensorConfig = new ArrayList<>();
//			Document gazeboModel = null;
//			
//			//Get the selected mode (either NO_CHANGE or Custom)
//			//TODO
//			String mode = "";
//			List<Attribute> modeList = xQueryAttributes(featureModel, "TODO get NO_CHANGE/ Custom parameter");
//			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
//			//TODO
//			switch(mode) {
//				case "NO_CHANGE":
//					break;
//				case "Custom":
//					List<Attribute> sensorList = xQueryAttributes(featureModel, "TODO get all selected sensor parameters");
//					////TODO oder weglassen
////					List<String> scList = getFileNames(in_scPath);
////					boolean inDirectory = true;
////					for(Attribute sensor : sensorList) {
////						for(String fileName : scList) {
////							if(!fileName.equals(sensor.getValue()+".xml")) inDirectory = false;
////						}
////					}
////					if(!inDirectory) {
////						System.err.println("");
////						System.exit(-1);
////					}
//					////
//					for(Attribute sensor : sensorList) {
//						sensorConfig.add(readXml(in_scPath+sensor.getValue()+".xml")); 
//					}
//					break;
//				default:
//					System.err.println("Error: Unmatched case");
//					System.exit(-1);
//			}
//			
//			//Get selected .gazebo.xacro file
//			//TODO
//			//TODO generalize botList (remove "TurtleBot")
//			//List<Attribute> botList = xQueryAttributes(featureModel, "//module[@types='TurtleBot']/@name");
//			String botName = "";
//			List<Attribute> botList = xQueryAttributes(featureModel, "TODO get name of the bot");
//			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);
//			//###############################################
//			
//			
//			//TODO##### Operate on .gazebo.xacro ############ NOCH NICHT UEBERARBEITET
//			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 "+in_scName);
//				System.exit(-1);
//			}
//			if(gSensorList.isEmpty()) {
//				System.out.println("No sensors found in "+in_gmName);
//				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 "+in_scName+" and "+in_gmName);
//			//###############################################
//			
//			
//			//######### Output result #######################
//			saveAsXml(gazeboModel, out_gmPath+out_gmName);
//			
//			BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(out_bnPath+out_bnName));
//			bufferedWriter.write(botName);
//			bufferedWriter.close();
//			//###############################################
//		}
//		catch (JDOMException | IOException e) {
//			e.printStackTrace();
//		}

		System.out.println("Adapter finished.");
marvin's avatar
marvin committed
	}
}
marvin's avatar
marvin committed


//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());