summaryrefslogblamecommitdiffstats
path: root/src/main/java/org/openslx/util/vm/VboxConfig.java
blob: ef17f5c414fd3adb3ae9cef301ed93b502f79f8f (plain) (tree)
1
2
3
4
5
6
7



                            
                            

                            





                                                      




                                               

                                      
                                       


                                                
                                      
                               
                                                
                                      
                                                    
                        
                            
                           
                        
                            
                               
                                

                                                   


                       

                                                                                  
 
                                    

                                                                           
 

                                                                        
 
                                                                                        
                                                                           

                                                                                    









                                                                                                 


                                                                                                
 
                                                     
 



                                                                                                                 
 
                                                                                         
                                                                  


                                                                                                                
         






                                                                             
                                                                           


                                       
                                                                       


                                                                                                
                                                                                  
                                                                                               




                                                                           
                                                                       


                 
                                      

                                      

                           
 
                                  

                          


                                         



                                                                       

                                                
                                          




                                                                                    
 
 





                                                                                                        
                         
                 
                             
         
        
                                                                    





                                                                                          

                                                               


                                                                                   


                                    

                                                             

                                                                           
                                                                                      
                                         


                                                                                
                                                  
                                                               


                                                                                   
                                                                      


                                                                                



                                                                                                                                                  

                                                                                            


                                                                                                                
                                                                                                  



                                                                                                 
 
                                                                                

                                                                                       
 











                                                                                             

                                     
         







                                                                                          
         

                                                                                          
         





                                                                              



                                                     

                                                                                               
                                                        
                                                                             
                 










                                                                                                                          


                                                                                     


                                                                                                                             

                                               



                                                                             
 







































                                                                                                      
                            
                                                                            


                                                       
                                                                      
                                                                                         
 
                                                                                                                   
                                                                   


                                                                                
                                               
                                                                                                                                   





                                                                                                                                     

                                                 

                                                                                                                                              
                                                    
                         
                 
         


                                                                 

                                                                                        
                                                                          
         
 








                                      
 



                                            
 


                                












                                                                                               
         
 
 
package org.openslx.util.vm;

import java.io.File;
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Map;
import java.util.TreeMap;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.apache.commons.logging.Log;
import org.apache.log4j.Logger;
import org.apache.log4j.varia.StringMatchFilter;
import org.junit.runners.ParentRunner;
import org.openslx.util.vm.VmwareConfig.ConfigEntry;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.openslx.util.vm.VmMetaData.DriveBusType;
import org.openslx.util.vm.VmMetaData.HardDisk;

public class VboxConfig
{
	private static final Logger LOGGER = Logger.getLogger( VboxConfig.class );
	XPath xPath = XPathFactory.newInstance().newXPath();

	private Document doc = null;
	private String displayNameExpression = "/VirtualBox/Machine/@name";
	private String displayName;

	private String osTypeExpression = "/VirtualBox/Machine/@OSType";
	private String osName = new String();;

	private String hddsExpression = "/VirtualBox/Machine/MediaRegistry/HardDisks/*";
	private ArrayList<HardDisk> hddsArray = new ArrayList<HardDisk>();;

	// a black list of sorts of tags that need to be removed from the .vbox file
	private static String[] blackList = { "ExtraData", "Adapter", "GuestProperties", "LPT" };

	/*
	 * constructor with input xml file
	 * used to set the doc variable of this class when creating vm
	 * @args: file as File - the input xml File
	 * @return: no return value
	 */
	public VboxConfig( File file ) throws IOException, UnsupportedVirtualizerFormatException
	{
		try {
			DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
			DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();

			doc = dBuilder.parse( file );

			// TODO - does this test suffice??
			if ( !doc.getDocumentElement().getNodeName().equals( "VirtualBox" ) ) {
				throw new UnsupportedVirtualizerFormatException( "not VirtualBox image format" );
			}

		} catch ( ParserConfigurationException | SAXException | IOException e ) {
			LOGGER.warn( "Could not parse .Vbox", e );
			throw new UnsupportedVirtualizerFormatException( "Konnte VBoxConfig nicht erstellen!" );
		}
		displayName = new String();
	}

	/*
	 * constructor with input string from server
	 * used to set the doc variable of this class when rebuilding the doc
	 * @args: filtered as String - sent from server
	 * @return: no return value
	 */
	public VboxConfig( byte[] filtered, int length ) throws IOException
	{
		// TODO test this spoon
		try {
			String filteredString = new String( filtered );
			DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
			//dbFactory.setValidating( true );
			//dbFactory.setIgnoringElementContentWhitespace( true );
			DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
			InputSource is = new InputSource( new StringReader( filteredString ) );

			doc = dBuilder.parse( is );

		} catch ( ParserConfigurationException | SAXException e ) {

			LOGGER.warn( "Could not recreate the dom", e );
		}
	}

	// returns definition document
	public Document getConfigDoc()
	{
		return doc;
	}

	// initialization function
	public void init()
	{
		try {
			setMachineName();
			setOsType();
			if ( checkForPlaceholders() ) {
				LOGGER.debug( "we have placeholders" );
				return;
			}
			setHdds();
			removeBlackListedTags();
			addPlaceHolders();
		} catch ( XPathExpressionException e ) {
			LOGGER.debug( "Konnte VBoxConfig nicht initializieren", e );
			return;
		}
	}


	private boolean checkForPlaceholders(){
		NodeList hdds = findANode( "HardDisk" );
		for ( int i = 0; i < hdds.getLength(); i++) {
			Element hdd =(Element) hdds.item( i );
			if ( hdd.getAttribute( "location" ).equals( "#some_fancy_HDD_place_holder" ) ) {
				return true;
			}
		}
		return false;
	}
	
	public void setMachineName() throws XPathExpressionException
	{
		String name = xPath.compile( displayNameExpression ).evaluate( this.doc );
		if ( !name.isEmpty() ) {
			displayName = name;
		}
	}

	public void setOsType() throws XPathExpressionException
	{
		String os = xPath.compile( osTypeExpression ).evaluate( this.doc );
		if ( !os.isEmpty() ) {
			osName = os;
		}
	}

	public void setHdds() throws XPathExpressionException
	{
		XPathExpression hddsExpr = xPath.compile( hddsExpression );
		Object result = hddsExpr.evaluate( this.doc, XPathConstants.NODESET );
		// take all the hdd nodes
		NodeList nodes = (NodeList)result;

		// TODO find all HardDisk under HardDisks, give them to the hdds
		// foreach hdd in the hddnodes do:
		for ( int i = 0; i < nodes.getLength(); i++ ) {
			// have the node
			// take the uuid
			// look under <AttachedDevice if found and do stuff with it
			Element hddElement = (Element)nodes.item( i );
			// read the filePath
			String fileName = hddElement.getAttribute( "location" );
			// take the uuid
			String uuid = hddElement.getAttribute( "uuid" );

			// do the loop the loop
			// search in the xml thingy and give back the parent of the parent of the node that is called Image and has the given uuid
			String pathToParent = givePathToStorageController( uuid );
			XPathExpression attachedDevicesExpr = xPath.compile( pathToParent );
			Object devicesResult = attachedDevicesExpr.evaluate( this.doc, XPathConstants.NODESET );
			NodeList devicesNodes = (NodeList)devicesResult;

			// TODO -- ehm...should only have 1 element...what do when there are more?
			if ( devicesNodes.getLength() > 1 ) {
				LOGGER.error( "There can not be more HDDs with the same UUID!" );
				return;
			}

			Element deviceElement = (Element)devicesNodes.item( 0 );
			String controllerDevice = deviceElement.getAttribute( "type" );
			String bus = deviceElement.getAttribute( "name" );

			DriveBusType busType = null;
			if ( bus.equals( "IDE" ) ) {
				busType = DriveBusType.IDE;
			} else if ( bus.equals( "SCSI" ) ) {
				busType = DriveBusType.SCSI;
			} else if ( bus.equals( "SATA" ) ) {
				busType = DriveBusType.SATA;
			}
			// add them together
			hddsArray.add( new HardDisk( controllerDevice, busType, fileName ) );
		}
	}

	public void addPlaceHolders()
	{
		// placeholder for the location of the virtual hdd
		changeAttribute( "HardDisk", "location", "#some_fancy_HDD_place_holder" );

		// placeholder for the memory
		changeAttribute( "Memory", "RAMSize", "#some_fancy_MEMORY_place_holder" );

		// placeholder for the CPU
		changeAttribute( "CPU", "count", "#some_fancy_CPU_place_holder" );
	}

	public void changeAttribute( String targetTag, String attribute, String newValue )
	{
		changeAttribute( targetTag, attribute, newValue, null, null );
	}

	public NodeList findANode( String targetTag )
	{
		String path = ".//" + targetTag;
		XPathExpression expr;
		NodeList nodes = null;
		try {
			expr = xPath.compile( path );
			Object nodesObject = expr.evaluate( this.doc, XPathConstants.NODESET );
			nodes = (NodeList)nodesObject;
		} catch ( XPathExpressionException e ) {
			LOGGER.error( "Path konnte nicht gebaut werden", e );
		}
		return nodes;
	}

	public void changeAttribute( String targetTag, String targetAttr, String newValue, String refAttr, String refVal )
	{
		NodeList nodes = findANode( targetTag );

		for ( int i = 0; i < nodes.getLength(); i++ ) {
			Element element = (Element)nodes.item( i );
			if ( refAttr != null && refVal != null ) {
				if ( element.getAttribute( refAttr ).equals( refVal ) ) {
					element.setAttribute( targetAttr, newValue );
					break;
				}
			} else {
				if ( nodes.getLength() > 1 ) {
					LOGGER.error( "Aktion würde an mehreren Knotten die Value ändern; unterbrochen!" );
					return;
				}
				element.setAttribute( targetAttr, newValue );
			}
		}
	}

	public void addSomeNewNode( String nameOfParent ,String nameOfnewNode , boolean justTheTip) {
		Node parent = findANode( nameOfParent ).item( 0 );
		if ( !parent.getNodeName().equals( nameOfParent )) {
			LOGGER.warn( "parent could not be found... exiting" );
			return;
		}
		
		String helperStr = "";
		if ( justTheTip ) {
			helperStr = "/";
		}
		Element newTag = doc.createElement( nameOfnewNode + helperStr );
		parent.appendChild( newTag );
		//Element newT = doc.create
		
	}
	// function removes a given child and the format childNode 
	private void removeNode( Node node ) {
		Node parent = node.getParentNode();
		// this node here is usually a type3 Node used only for the formating of the vbox file
		Node previousSibling = node.getPreviousSibling();
		
		parent.removeChild( node );
		
	// HACK remove empty lines
		// format children have type 3
		if ( previousSibling.getNodeType() == 3 ) {
			// the value of these Nodes are characters
			String tmp = previousSibling.getNodeValue();
			boolean shouldDelete = true;
			for ( int foo = 0; foo < tmp.length(); foo++ ) {
				if ( !Character.isWhitespace( tmp.charAt( foo ) ) ) {
					shouldDelete = false;
					break;
				}
			}
			if ( shouldDelete )
				parent.removeChild( previousSibling );
		}
	}
	// cleanup part here
	private void removeBlackListedTags() throws XPathExpressionException
	{
		// iterate over the blackList
		for ( String blackedTag : blackList ) {
			String blackedExpression = ".//" + blackedTag;
			XPathExpression blackedExpr = xPath.compile( blackedExpression );

			NodeList blackedNodes = (NodeList)blackedExpr.evaluate( this.doc, XPathConstants.NODESET );
			//LOGGER.debug( blackedNodes.getLength() );
			for ( int i = 0; i < blackedNodes.getLength(); i++ ) {
				// get the child node
				Element child = (Element)blackedNodes.item( i );
				// remove child
				if ( child.getTagName().equals( "Adapter" ) && child.getAttribute( "enabled" ).equals( "true" ) ) {
					// we need to remove the children of the active network adapter
					// these are the mode of network connection and disabled modes...they go together -> see wiki
					if ( child.getChildNodes().item( 0 ).getNodeName().equals( "#text" ) &&
							!child.getChildNodes().item( 1 ).getNodeName().equals( "#text" ) ) {
						removeNode( child.getChildNodes().item( 1 ) );
					}
					continue;
				}
				// the structure of the xml Document is achieved through children nodes that are made up of just /n and spaces
				// when a child node is deleted we get an empty line there the old child node used to be
				removeNode( child );
			}
		}
	}

	//private void removeTag
	private String givePathToStorageController( String uuid )
	{
		// StorageController is the parent of the parent of node with given uuid
		return "//Image[contains(@uuid, \'" + uuid + "\')]/../..";
	}

	public String getDisplayName()
	{
		return displayName;
	}

	public String getOsName()
	{
		return osName;
	}

	public ArrayList<HardDisk> getHdds()
	{
		return hddsArray;
	}

	public String toString()
	{
		try {
			StringWriter sw = new StringWriter();
			TransformerFactory tf = TransformerFactory.newInstance();
			Transformer transformer = tf.newTransformer();
			transformer.setOutputProperty( OutputKeys.OMIT_XML_DECLARATION, "no" );
			transformer.setOutputProperty( OutputKeys.METHOD, "xml" );
			transformer.setOutputProperty( OutputKeys.INDENT, "yes" );
			transformer.setOutputProperty( OutputKeys.ENCODING, "UTF-8" );

			transformer.transform( new DOMSource( doc ), new StreamResult( sw ) );
			return sw.toString();
		} catch ( Exception ex ) {
			throw new RuntimeException( "Error converting to String", ex );
		}
	}

}