diff options
Diffstat (limited to 'src/main/java/org/openslx/libvirt/xml')
11 files changed, 1480 insertions, 0 deletions
diff --git a/src/main/java/org/openslx/libvirt/xml/LibvirtXmlCreatable.java b/src/main/java/org/openslx/libvirt/xml/LibvirtXmlCreatable.java new file mode 100644 index 0000000..e799ace --- /dev/null +++ b/src/main/java/org/openslx/libvirt/xml/LibvirtXmlCreatable.java @@ -0,0 +1,26 @@ +package org.openslx.libvirt.xml; + +import org.w3c.dom.Node; + +/** + * Serializability of a Libvirt XML object from/to its XML representation. + * + * @author Manuel Bentele + * @version 1.0 + */ +public interface LibvirtXmlCreatable +{ + /** + * Serializing an object from its XML representation. + * + * @param xmlNode The object's XML representation. + */ + void fromXmlNode( Node xmlNode ); + + /** + * Serializing the object to its XML representation. + * + * @return XML representation of the object. + */ + Node toXmlNode(); +} diff --git a/src/main/java/org/openslx/libvirt/xml/LibvirtXmlDocument.java b/src/main/java/org/openslx/libvirt/xml/LibvirtXmlDocument.java new file mode 100644 index 0000000..8fe642b --- /dev/null +++ b/src/main/java/org/openslx/libvirt/xml/LibvirtXmlDocument.java @@ -0,0 +1,373 @@ +package org.openslx.libvirt.xml; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStream; +import java.io.StringWriter; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerConfigurationException; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; +import javax.xml.transform.stream.StreamSource; + +import org.apache.commons.io.IOUtils; +import org.w3c.dom.Document; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + +/** + * A generic representation of a Libvirt XML file. + * + * @implNote Base class to derive the representation of specific Libvirt XML files. + * + * @author Manuel Bentele + * @version 1.0 + */ +public abstract class LibvirtXmlDocument implements LibvirtXmlSerializable, LibvirtXmlValidatable +{ + /** + * Document builder to parse Libvirt XML document from file. + */ + private DocumentBuilder domBuilder = null; + + /** + * Representation of a Libvirt XML document. + */ + private Document xmlDocument = null; + + /** + * XML transformer to transform Libvirt XML document to a file. + */ + private Transformer xmlTransformer = null; + + /** + * XML root node of the Libvirt XML document. + */ + private LibvirtXmlNode rootXmlNode = null; + + /** + * RNG schema validator to validate the Libvirt XML document content. + */ + private LibvirtXmlSchemaValidator rngValidator = null; + + /** + * Creates and initializes XML context to create and transform a Libvirt XML file from/to a file. + * + * @param rngSchema RNG schema to validate the Libvirt XML document content. + * + * @throws LibvirtXmlDocumentException error occured during setup of the XML context to read and + * write from/to a Libvirt XML file. + */ + private void createXmlContext( InputStream rngSchema ) throws LibvirtXmlDocumentException + { + // used for XML input + try { + DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance(); + domFactory.setIgnoringElementContentWhitespace( true ); + domFactory.setNamespaceAware( true ); + this.domBuilder = domFactory.newDocumentBuilder(); + } catch ( ParserConfigurationException e ) { + String errorMsg = new String( "Setting up XML context for reading from the Libvirt XML document failed." ); + throw new LibvirtXmlDocumentException( errorMsg ); + } + + // used for XML output + try { + // use hack to load specific transformer factory implementation for XSLT + System.setProperty( TransformerFactory.class.getName(), + "org.apache.xalan.processor.TransformerFactoryImpl" ); + + // create XML transformer factory to create XML transformer with specific indentation + TransformerFactory transformerFactory = TransformerFactory.newInstance(); + + // create XML transformer and apply settings for output XML transformation + InputStream xslOutputSchemaStream = LibvirtXmlResources.getLibvirtXsl( "xml-output-transformation.xsl" ); + StreamSource xslOutputSchema = new StreamSource( xslOutputSchemaStream ); + this.xmlTransformer = transformerFactory.newTransformer( xslOutputSchema ); + } catch ( TransformerConfigurationException e ) { + String errorMsg = new String( "Setting up XML context for writing to the Libvirt XML document failed." ); + throw new LibvirtXmlDocumentException( errorMsg ); + } + + // used for XML validation with RNG schema files + if ( rngSchema != null ) { + try { + this.rngValidator = new LibvirtXmlSchemaValidator( rngSchema ); + } catch ( SAXException e ) { + String errorMsg = new String( "Setting up XML context for validating to the Libvirt XML document failed." ); + e.printStackTrace(); + throw new LibvirtXmlDocumentException( errorMsg ); + } + } + } + + /** + * Creates a Libvirt XML document from a given XML content. + * + * @param xml XML content as {@link String}. + * + * @throws LibvirtXmlDocumentException creation of XML context failed. + * @throws LibvirtXmlSerializationException serialization of the XML content failed. + * @throws LibvirtXmlValidationException XML content is not a valid Libvirt XML. + */ + public LibvirtXmlDocument( String xml ) + throws LibvirtXmlDocumentException, LibvirtXmlSerializationException, LibvirtXmlValidationException + { + this( xml, null ); + } + + /** + * Creates a Libvirt XML document from a given XML content. + * + * @param xml XML content as {@link String}. + * @param rngSchema RNG schema to validate XML content. + * + * @throws LibvirtXmlDocumentException creation of XML context failed. + * @throws LibvirtXmlSerializationException serialization of the XML content failed. + * @throws LibvirtXmlValidationException XML content is not a valid Libvirt XML. + */ + public LibvirtXmlDocument( String xml, InputStream rngSchema ) + throws LibvirtXmlDocumentException, LibvirtXmlSerializationException, LibvirtXmlValidationException + { + this.createXmlContext( rngSchema ); + this.fromXml( xml ); + this.validateXml(); + } + + /** + * Creates a Libvirt XML document from a given XML content. + * + * @param xml XML content as {@link File}. + * + * @throws LibvirtXmlDocumentException creation of XML context failed. + * @throws LibvirtXmlSerializationException serialization of the XML content failed. + * @throws LibvirtXmlValidationException XML content is not a valid Libvirt XML. + */ + public LibvirtXmlDocument( File xml ) + throws LibvirtXmlDocumentException, LibvirtXmlSerializationException, LibvirtXmlValidationException + { + this( xml, null ); + } + + /** + * Creates a Libvirt XML document from a given XML content. + * + * @param xml XML content as {@link File}. + * @param rngSchema RNG schema to validate XML content. + * + * @throws LibvirtXmlDocumentException creation of XML context failed. + * @throws LibvirtXmlSerializationException serialization of the XML content failed. + * @throws LibvirtXmlValidationException XML content is not a valid Libvirt XML. + */ + public LibvirtXmlDocument( File xml, InputStream rngSchema ) + throws LibvirtXmlDocumentException, LibvirtXmlSerializationException, LibvirtXmlValidationException + { + this.createXmlContext( rngSchema ); + this.fromXml( xml ); + this.validateXml(); + } + + /** + * Creates a Libvirt XML document from a given XML content. + * + * @param xml XML content as {@link InputStream}. + * + * @throws LibvirtXmlDocumentException creation of XML context failed. + * @throws LibvirtXmlSerializationException serialization of the XML content failed. + * @throws LibvirtXmlValidationException XML content is not a valid Libvirt XML. + */ + public LibvirtXmlDocument( InputStream xml ) + throws LibvirtXmlDocumentException, LibvirtXmlSerializationException, LibvirtXmlValidationException + { + this( xml, null ); + } + + /** + * Creates a Libvirt XML document from a given XML content. + * + * @param xml XML content as {@link InputStream}. + * @param rngSchema RNG schema to validate XML content. + * + * @throws LibvirtXmlDocumentException creation of XML context failed. + * @throws LibvirtXmlSerializationException serialization of the XML content failed. + * @throws LibvirtXmlValidationException XML content is not a valid Libvirt XML. + */ + public LibvirtXmlDocument( InputStream xml, InputStream rngSchema ) + throws LibvirtXmlDocumentException, LibvirtXmlSerializationException, LibvirtXmlValidationException + { + this.createXmlContext( rngSchema ); + this.fromXml( xml ); + this.validateXml(); + } + + /** + * Creates a Libvirt XML document from a given XML content. + * + * @param xml XML content as {@link InputSource}. + * + * @throws LibvirtXmlDocumentException creation of XML context failed. + * @throws LibvirtXmlSerializationException serialization of the XML content failed. + * @throws LibvirtXmlValidationException XML content is not a valid Libvirt XML. + */ + public LibvirtXmlDocument( InputSource xml ) + throws LibvirtXmlDocumentException, LibvirtXmlSerializationException, LibvirtXmlValidationException + { + this( xml, null ); + } + + /** + * Creates a Libvirt XML document from a given XML content. + * + * @param xml XML content as {@link InputSource}. + * @param rngSchema RNG schema to validate XML content. + * + * @throws LibvirtXmlDocumentException creation of XML context failed. + * @throws LibvirtXmlSerializationException serialization of the XML content failed. + * @throws LibvirtXmlValidationException XML content is not a valid Libvirt XML. + */ + public LibvirtXmlDocument( InputSource xml, InputStream rngSchema ) + throws LibvirtXmlDocumentException, LibvirtXmlSerializationException, LibvirtXmlValidationException + { + this.createXmlContext( rngSchema ); + this.fromXml( xml ); + this.validateXml(); + } + + /** + * Returns the XML root node of the Libvirt XML document. + * + * @return root node of the Libvirt XML document. + */ + public LibvirtXmlNode getRootXmlNode() + { + return this.rootXmlNode; + } + + @Override + public void fromXml( String xml ) throws LibvirtXmlSerializationException + { + try { + this.xmlDocument = this.domBuilder.parse( xml ); + this.xmlDocument.getDocumentElement().normalize(); + } catch ( SAXException e ) { + e.printStackTrace(); + } catch ( IOException e ) { + e.printStackTrace(); + } + + this.rootXmlNode = new LibvirtXmlNode( this.xmlDocument, this.xmlDocument.getDocumentElement() ); + } + + @Override + public void fromXml( File xml ) throws LibvirtXmlSerializationException + { + try { + this.xmlDocument = this.domBuilder.parse( xml ); + this.xmlDocument.getDocumentElement().normalize(); + } catch ( SAXException e ) { + throw new LibvirtXmlSerializationException( e.getLocalizedMessage() ); + } catch ( IOException e ) { + throw new LibvirtXmlSerializationException( e.getLocalizedMessage() ); + } + + this.rootXmlNode = new LibvirtXmlNode( this.xmlDocument, this.xmlDocument.getDocumentElement() ); + } + + @Override + public void fromXml( InputStream xml ) throws LibvirtXmlSerializationException + { + try { + this.xmlDocument = this.domBuilder.parse( xml ); + this.xmlDocument.getDocumentElement().normalize(); + } catch ( SAXException e ) { + throw new LibvirtXmlSerializationException( e.getLocalizedMessage() ); + } catch ( IOException e ) { + throw new LibvirtXmlSerializationException( e.getLocalizedMessage() ); + } + + this.rootXmlNode = new LibvirtXmlNode( this.xmlDocument, this.xmlDocument.getDocumentElement() ); + } + + @Override + public void fromXml( InputSource xml ) throws LibvirtXmlSerializationException + { + try { + this.xmlDocument = this.domBuilder.parse( xml ); + this.xmlDocument.getDocumentElement().normalize(); + } catch ( SAXException e ) { + throw new LibvirtXmlSerializationException( e.getLocalizedMessage() ); + } catch ( IOException e ) { + throw new LibvirtXmlSerializationException( e.getLocalizedMessage() ); + } + + this.rootXmlNode = new LibvirtXmlNode( this.xmlDocument, this.xmlDocument.getDocumentElement() ); + } + + @Override + @SuppressWarnings( "deprecation" ) + public String toXml() throws LibvirtXmlSerializationException + { + StringWriter xmlWriter = null; + String xml = null; + + try { + xmlWriter = new StringWriter(); + DOMSource source = new DOMSource( this.xmlDocument ); + StreamResult xmlString = new StreamResult( xmlWriter ); + this.xmlTransformer.transform( source, xmlString ); + xml = xmlWriter.toString() + System.lineSeparator(); + xmlWriter.close(); + } catch ( TransformerException | IOException e ) { + throw new LibvirtXmlSerializationException( e.getLocalizedMessage() ); + } finally { + IOUtils.closeQuietly( xmlWriter ); + } + + return xml; + } + + @Override + @SuppressWarnings( "deprecation" ) + public void toXml( File xml ) throws LibvirtXmlSerializationException + { + FileWriter xmlWriter = null; + + try { + xmlWriter = new FileWriter( xml ); + DOMSource source = new DOMSource( this.xmlDocument ); + StreamResult xmlStream = new StreamResult( xmlWriter ); + this.xmlTransformer.transform( source, xmlStream ); + xmlWriter.append( System.lineSeparator() ); + xmlWriter.close(); + } catch ( TransformerException | IOException e ) { + throw new LibvirtXmlSerializationException( e.getLocalizedMessage() ); + } finally { + IOUtils.closeQuietly( xmlWriter ); + } + } + + @Override + public void validateXml() throws LibvirtXmlValidationException + { + if ( this.rngValidator != null ) { + this.rngValidator.validate( this.xmlDocument ); + } + } + + @Override + public String toString() + { + try { + return this.toXml(); + } catch ( LibvirtXmlSerializationException e ) { + return null; + } + } +} diff --git a/src/main/java/org/openslx/libvirt/xml/LibvirtXmlDocumentException.java b/src/main/java/org/openslx/libvirt/xml/LibvirtXmlDocumentException.java new file mode 100644 index 0000000..f8605ed --- /dev/null +++ b/src/main/java/org/openslx/libvirt/xml/LibvirtXmlDocumentException.java @@ -0,0 +1,25 @@ +package org.openslx.libvirt.xml; + +/** + * An exception of a Libvirt XML document. + * + * @author Manuel Bentele + * @version 1.0 + */ +public class LibvirtXmlDocumentException extends Exception +{ + /** + * Version number for serialization. + */ + private static final long serialVersionUID = -7423926322035713576L; + + /** + * Creates an document exception including an error message. + * + * @param errorMsg message to describe a specific document error. + */ + public LibvirtXmlDocumentException( String errorMsg ) + { + super( errorMsg ); + } +} diff --git a/src/main/java/org/openslx/libvirt/xml/LibvirtXmlEditable.java b/src/main/java/org/openslx/libvirt/xml/LibvirtXmlEditable.java new file mode 100644 index 0000000..1ddddce --- /dev/null +++ b/src/main/java/org/openslx/libvirt/xml/LibvirtXmlEditable.java @@ -0,0 +1,241 @@ +package org.openslx.libvirt.xml; + +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +/** + * Editability of XML nodes based on {@link XPath} expressions. + * + * @author Manuel Bentele + * @version 1.0 + */ +public interface LibvirtXmlEditable +{ + /** + * Returns XML node selected by a {@link XPath} expression + * + * @param expression {@link XPath} expression to select XML node. + * @return selected XML node. + */ + public Node getXmlNode( String expression ); + + /** + * Returns XML nodes selected by a {@link XPath} expression + * + * @param expression {@link XPath} expression to select XML nodes. + * @return selected XML nodes. + */ + public NodeList getXmlNodes( String expression ); + + /** + * Return current XML root element. + * + * @return current XML root element. + */ + public default Node getXmlElement() + { + return this.getXmlElement( null ); + } + + /** + * Returns XML element from selection by a {@link XPath} expression. + * + * @param expression {@link XPath} expression to select XML element. + * @return selected XML element. + */ + public Node getXmlElement( String expression ); + + /** + * Sets an XML element selected by a {@link XPath} expression. + * + * If the XML element selected by the given {@link XPath} expression does not exists, the XML + * element will be created. + * + * @param expression {@link XPath} expression to select XML element. + */ + public default void setXmlElement( String expression ) + { + this.setXmlElement( expression, null ); + } + + /** + * Sets a XML element selected by a {@link XPath} expression and appends child XML node. + * + * If the XML element selected by the given {@link XPath} expression does not exists, the XML + * element will be created and the given XML child node is appended. + * + * @param expression {@link XPath} expression to select XML element. + * @param child XML node that will be appended to the selected XML element. + */ + public void setXmlElement( String expression, Node child ); + + /** + * Returns the text value of a XML element selected by a {@link XPath} expression. + * + * @param expression {@link XPath} expression to select XML element. + * @return Text value of the selected XML element. + */ + public String getXmlElementValue( String expression ); + + /** + * Sets the text value of a XML element selected by a {@link XPath} expression. + * + * @param expression {@link XPath} expression to select XML element. + * @param value text value to set selected XML element's text. + */ + public void setXmlElementValue( String expression, String value ); + + /** + * Removes a XML element and all its childs selected by a {@link XPath} expression. + * + * @param expression {@link XPath} expression to select XML element. + */ + public void removeXmlElement( String expression ); + + /** + * Removes all child elements of a XML element selected by a {@link XPath} expression. + * + * @param expression {@link XPath} expression to select XML element. + */ + public void removeXmlElementChilds( String expression ); + + /** + * Returns the text value of a XML attribute from the current XML root element. + * + * @param attributeName name to select XML attribute of the current XML root element. + * @return attribute text of the XML attribute from the current XML root element as + * {@link String}. + */ + public default String getXmlElementAttributeValue( String attributeName ) + { + return this.getXmlElementAttributeValue( null, attributeName ); + } + + /** + * Returns the binary choice of a XML attribute from the current XML root element. + * + * If the text value of the XML attribute equals to <i>yes</i>, the returned {@link boolean} + * value is set to <i>true</i>. Otherwise, if the text value of the XML attribute equals to + * <i>no</i>, the returned {@link boolean} value is set to <i>false</i>. + * + * @param attributeName name to select XML attribute of the current XML root element. + * @return attribute value of the XML attribute from the current XML root element as + * {@link boolean}. + */ + public default boolean getXmlElementAttributeValueAsBool( String attributeName ) + { + return "yes".equals( this.getXmlElementAttributeValue( attributeName ) ); + } + + /** + * Returns the binary choice of a XML attribute from a XML element selected by a + * {@link XPath}expression. + * + * If the text value of the XML attribute equals to <i>yes</i>, the returned {@link boolean} + * value is set to <i>true</i>. Otherwise, if the text value of the XML attribute equals to + * <i>no</i>, the returned {@link boolean} value is set to <i>false</i>. + * + * @param expression {@link XPath} expression to select XML element. + * @param attributeName name to select XML attribute of the current XML root element. + * @return attribute value of the XML attribute from the current XML root element as + * {@link boolean}. + */ + public default boolean getXmlElementAttributeValueAsBool( String expression, String attributeName ) + { + return "yes".equals( this.getXmlElementAttributeValue( expression, attributeName ) ); + } + + /** + * Returns the text value of a XML attribute from a XML element selected by a + * {@link XPath}expression. + * + * @param expression {@link XPath} expression to select XML element. + * @param attributeName name to select XML attribute of the selected XML element. + * @return attribute text of the XML attribute from the selected XML element. + */ + public String getXmlElementAttributeValue( String expression, String attributeName ); + + /** + * Sets the text value of a XML attribute from the current XML root element. + * + * @param attributeName name to select XML attribute of the current XML root element. + * @param value XML attribute value for the selected XML attribute from the current XML root + * element. + */ + public default void setXmlElementAttributeValue( String attributeName, String value ) + { + this.setXmlElementAttributeValue( null, attributeName, value ); + } + + /** + * Sets the binary choice value of a XML attribute from the current XML root element. + * + * If the binary choice value for the XML attribute equals to <i>true</i>, the text value of the + * selected XML attribute is set to <i>yes</i>. Otherwise, if the binary choice value for the + * selected XML attribute equals to <i>false</i>, the text value of the selected XML attribute is + * set to <i>no</i>. + * + * @param attributeName name to select XML attribute of the selected XML element. + * @param value binary choice value for the selected XML attribute from the selected XML element. + */ + public default void setXmlElementAttributeValue( String attributeName, boolean value ) + { + final String valueYesNo = value ? "yes" : "no"; + this.setXmlElementAttributeValue( attributeName, valueYesNo ); + } + + /** + * Sets the binary choice value of a XML attribute from a XML element selected by a + * {@link XPath} expression. + * + * If the binary choice value for the XML attribute equals to <i>true</i>, the text value of the + * selected XML attribute is set to <i>yes</i>. Otherwise, if the binary choice value for the + * selected XML attribute equals to <i>false</i>, the text value of the selected XML attribute is + * set to <i>no</i>. + * + * @param expression {@link XPath} expression to select XML element. + * @param attributeName name to select XML attribute of the selected XML element. + * @param value binary choice value for the selected XML attribute from the selected XML element. + */ + public default void setXmlElementAttributeValue( String expression, String attributeName, boolean value ) + { + final String valueYesNo = value ? "yes" : "no"; + this.setXmlElementAttributeValue( expression, attributeName, valueYesNo ); + } + + /** + * Sets the text value of a XML attribute from a XML element selected by a + * {@link XPath} expression. + * + * @param expression {@link XPath} expression to select XML element. + * @param attributeName name to select XML attribute of the selected XML element. + * @param value XML attribute value for the selected XML attribute from the selected XML element. + */ + public void setXmlElementAttributeValue( String expression, String attributeName, String value ); + + /** + * Removes an XML attribute from the current XML root element. + * + * @param attributeName name of the attribute which should be deleted. + */ + public default void removeXmlElementAttribute( String attributeName ) + { + this.removeXmlElementAttribute( null, attributeName ); + } + + /** + * Removes an XML attribute from a XML element selected by a {@link XPath} expression. + * + * @param expression {@link XPath} expression to select XML element. + * @param attributeName name of the attribute which should be deleted. + */ + public void removeXmlElementAttribute( String expression, String attributeName ); + + /** + * Removes all XML attributes from a XML element selected by a {@link XPath} expression. + * + * @param expression {@link XPath} expression to select XML element. + */ + public void removeXmlElementAttributes( String expression ); + +} diff --git a/src/main/java/org/openslx/libvirt/xml/LibvirtXmlNode.java b/src/main/java/org/openslx/libvirt/xml/LibvirtXmlNode.java new file mode 100644 index 0000000..93e28de --- /dev/null +++ b/src/main/java/org/openslx/libvirt/xml/LibvirtXmlNode.java @@ -0,0 +1,356 @@ +package org.openslx.libvirt.xml; + +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.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +/** + * A representation of a XML node as part of a {@link LibvirtXMLDocument}. + * + * @author Manuel Bentele + * @version 1.0 + */ +public class LibvirtXmlNode implements LibvirtXmlCreatable, LibvirtXmlEditable +{ + /** + * Separation character for internal {@link XPath} expressions. + */ + private static final String XPATH_EXPRESSION_SEPARATOR = "/"; + + /** + * Current XML node selection character for internal {@link XPath} expressions. + */ + private static final String XPATH_EXPRESSION_CURRENT_NODE = "."; + + /** + * Factory to create {@link XPath} objects. + */ + private XPathFactory xPathFactory = null; + + /** + * Representation of the XML document, in which this {@link LibvirtXmlNode} is part of. + */ + private Document xmlDocument = null; + + /** + * Current XML base node as XML root anchor for relative internal {@link XPath} expressions. + */ + private Node xmlBaseNode = null; + + /** + * Create and initialize {@link XPath} context to define and compile custom {@link XPath} + * expressions. + */ + private void createXPathContext() + { + this.xPathFactory = XPathFactory.newInstance(); + } + + /** + * Creates empty Libvirt XML node, which does not belong to any XML document and does not specify + * any XML base node. + * + * @implNote Please call {@link LibvirtXmlNode#setXmlDocument(Document)} and + * {@link LibvirtXmlNode#setXmlBaseNode(Node)} manually to obtain a functional Libvirt + * XML node. + */ + public LibvirtXmlNode() + { + this( null, null ); + } + + /** + * Creates Libvirt XML node from a existing Libvirt XML node by reference. + * + * @param xmlNode existing Libvirt XML node. + */ + public LibvirtXmlNode( LibvirtXmlNode xmlNode ) + { + this( xmlNode.getXmlDocument(), xmlNode.getXmlBaseNode() ); + } + + /** + * Creates Libvirt XML node as part of a existing XML document. + * + * @param xmlDocument existing XML document. + * + * @implNote Please call {@link LibvirtXmlNode#setXmlBaseNode(Node)} manually to obtain a + * functional Libvirt XML node. + */ + public LibvirtXmlNode( Document xmlDocument ) + { + this( xmlDocument, null ); + } + + /** + * Creates Libvirt XML node with a specific XML base node. + * + * @param xmlBaseNode existing XML base node. + * + * @implNote Please call {@link LibvirtXmlNode#setXmlDocument(Document)} manually to obtain a + * functional Libvirt XML node. + */ + public LibvirtXmlNode( Node xmlBaseNode ) + { + this( null, xmlBaseNode ); + } + + /** + * Creates Libvirt XML node with a specific XML base node as part of a XML document. + * + * @param xmlDocument existing XML document. + * @param xmlBaseNode existing XML base node. + */ + public LibvirtXmlNode( Document xmlDocument, Node xmlBaseNode ) + { + this.createXPathContext(); + + this.setXmlDocument( xmlDocument ); + this.setXmlBaseNode( xmlBaseNode ); + } + + /** + * Returns referenced XML document. + * + * @return referenced XML document. + */ + public Document getXmlDocument() + { + return this.xmlDocument; + } + + /** + * Sets existing XML document for Libvirt XML node. + * + * @param xmlDocument existing XML document. + */ + public void setXmlDocument( Document xmlDocument ) + { + this.xmlDocument = xmlDocument; + } + + /** + * Returns current XML base node. + * + * @return current XML base node as XML root anchor of relative internal {@link XPath} + * expressions. + */ + public Node getXmlBaseNode() + { + return this.xmlBaseNode; + } + + /** + * Sets existing XML base node for Libvirt XML node. + * + * @param xmlBaseNode existing XML base node as XML root anchor for relative internal + * {@link XPath} expressions. + */ + public void setXmlBaseNode( Node xmlBaseNode ) + { + this.xmlBaseNode = xmlBaseNode; + } + + @Override + public Node getXmlNode( String expression ) + { + NodeList nodes = this.getXmlNodes( expression ); + return nodes.item( 0 ); + } + + @Override + public NodeList getXmlNodes( String expression ) + { + Object nodes = null; + + try { + XPath xPath = this.xPathFactory.newXPath(); + XPathExpression xPathExpr = xPath.compile( expression ); + nodes = xPathExpr.evaluate( this.xmlBaseNode, XPathConstants.NODESET ); + } catch ( XPathExpressionException e ) { + e.printStackTrace(); + } + + return NodeList.class.cast( nodes ); + } + + @Override + public Node getXmlElement( String expression ) + { + String completeExpression = null; + + if ( expression == null ) { + completeExpression = XPATH_EXPRESSION_CURRENT_NODE; + } else if ( expression.isEmpty() ) { + completeExpression = XPATH_EXPRESSION_CURRENT_NODE; + } else { + completeExpression = XPATH_EXPRESSION_CURRENT_NODE + XPATH_EXPRESSION_SEPARATOR + expression; + } + + Node node = this.getXmlNode( completeExpression ); + + if ( node != null && node.getNodeType() == Node.ELEMENT_NODE ) { + return node; + } else { + return null; + } + } + + private Node createXmlElement( String expression ) + { + Node parentNode = this.xmlBaseNode; + Node currentNode = parentNode; + + if ( expression != null && !expression.isEmpty() ) { + String[] nodeNames = expression.split( XPATH_EXPRESSION_SEPARATOR ); + String partialExpression = XPATH_EXPRESSION_CURRENT_NODE; + + for ( int i = 0; i < nodeNames.length; i++ ) { + partialExpression += XPATH_EXPRESSION_SEPARATOR + nodeNames[i]; + currentNode = this.getXmlNode( partialExpression ); + + if ( currentNode == null ) { + parentNode.appendChild( this.xmlDocument.createElement( nodeNames[i] ) ); + currentNode = parentNode.getLastChild(); + } + + parentNode = currentNode; + } + } + + return currentNode; + } + + @Override + public void setXmlElement( String expression, Node child ) + { + Node node = this.createXmlElement( expression ); + + if ( child != null ) { + node.appendChild( child ); + } + } + + @Override + public String getXmlElementValue( String expression ) + { + Node node = this.getXmlElement( expression ); + + if ( node != null ) { + return node.getTextContent(); + } else { + return null; + } + } + + @Override + public void setXmlElementValue( String expression, String value ) + { + Node node = this.createXmlElement( expression ); + node.setTextContent( value ); + } + + @Override + public void removeXmlElement( String expression ) + { + Node node = this.getXmlElement( expression ); + + if ( node != null ) { + node.getParentNode().removeChild( node ); + } + } + + @Override + public void removeXmlElementChilds( String expression ) + { + Node node = this.getXmlElement( expression ); + + if ( node != null ) { + for ( int i = 0; i < node.getChildNodes().getLength(); i++ ) { + Node child = node.getChildNodes().item( 0 ); + node.removeChild( child ); + } + } + } + + @Override + public String getXmlElementAttributeValue( String expression, String attributeName ) + { + Node node = null; + + if ( expression != null && !expression.isEmpty() ) { + node = this.getXmlElement( expression ); + } else { + node = this.xmlBaseNode; + } + + if ( node == null ) { + return null; + } else { + Node attribute = node.getAttributes().getNamedItem( attributeName ); + + if ( attribute == null ) { + return null; + } else { + return attribute.getNodeValue(); + } + } + } + + @Override + public void setXmlElementAttributeValue( String expression, String attributeName, String value ) + { + Node node = this.createXmlElement( expression ); + Node attribute = node.getAttributes().getNamedItem( attributeName ); + + if ( attribute == null ) { + Element element = Element.class.cast( node ); + element.setAttribute( attributeName, value ); + } else { + attribute.setNodeValue( value ); + } + } + + @Override + public void removeXmlElementAttribute( String expression, String attributeName ) + { + Node node = this.getXmlElement( expression ); + + if ( node != null ) { + Node attribute = node.getAttributes().getNamedItem( attributeName ); + node.getAttributes().removeNamedItem( attribute.getNodeName() ); + } + } + + @Override + public void removeXmlElementAttributes( String expression ) + { + Node node = this.getXmlElement( expression ); + + if ( node != null ) { + for ( int i = 0; i < node.getAttributes().getLength(); i++ ) { + Node attribute = node.getAttributes().item( 0 ); + node.getAttributes().removeNamedItem( attribute.getNodeName() ); + } + } + } + + @Override + public void fromXmlNode( Node xmlNode ) + { + this.setXmlBaseNode( xmlNode ); + } + + @Override + public Node toXmlNode() + { + return this.getXmlBaseNode(); + } +} diff --git a/src/main/java/org/openslx/libvirt/xml/LibvirtXmlResources.java b/src/main/java/org/openslx/libvirt/xml/LibvirtXmlResources.java new file mode 100644 index 0000000..38c818b --- /dev/null +++ b/src/main/java/org/openslx/libvirt/xml/LibvirtXmlResources.java @@ -0,0 +1,52 @@ +package org.openslx.libvirt.xml; + +import java.io.File; +import java.io.InputStream; + +/** + * Collection of resource utils for a Libvirt XML document. + * + * @author Manuel Bentele + * @version 1.0 + */ +public final class LibvirtXmlResources +{ + /** + * File path prefix of the absolute path to the libvirt resource folder in a *.jar file. + */ + private static final String LIBVIRT_PREFIX_PATH = File.separator + "libvirt"; + + /** + * File path prefix of the absolute path to the libvirt XSL resource folder in a *.jar file. + */ + private static final String LIBVIRT_PREFIX_PATH_XSL = LIBVIRT_PREFIX_PATH + File.separator + "xsl"; + + /** + * File path prefix of the absolute path to the libvirt RNG resource folder in a *.jar file. + */ + private static final String LIBVIRT_PREFIX_PATH_RNG = LIBVIRT_PREFIX_PATH + File.separator + "rng"; + + /** + * Returns a Libvirt XSL resource as stream. + * + * @param libvirtXslFileName file name of the XSL resource in the resources *.jar folder. + * @return Libvirt XSL resource as stream. + */ + public static InputStream getLibvirtXsl( String libvirtXslFileName ) + { + String libvirtXslPath = LibvirtXmlResources.LIBVIRT_PREFIX_PATH_XSL + File.separator + libvirtXslFileName; + return LibvirtXmlResources.class.getResourceAsStream( libvirtXslPath ); + } + + /** + * Returns a Libvirt RNG schema resource as stream. + * + * @param libvirtRngFileName file name of the RNG schema resource in the resources *.jar folder. + * @return Libvirt RNG schema resource as stream. + */ + public static InputStream getLibvirtRng( String libvirtRngFileName ) + { + String libvirtRngPath = LibvirtXmlResources.LIBVIRT_PREFIX_PATH_RNG + File.separator + libvirtRngFileName; + return LibvirtXmlResources.class.getResourceAsStream( libvirtRngPath ); + } +} diff --git a/src/main/java/org/openslx/libvirt/xml/LibvirtXmlSchemaValidator.java b/src/main/java/org/openslx/libvirt/xml/LibvirtXmlSchemaValidator.java new file mode 100644 index 0000000..e074948 --- /dev/null +++ b/src/main/java/org/openslx/libvirt/xml/LibvirtXmlSchemaValidator.java @@ -0,0 +1,282 @@ +package org.openslx.libvirt.xml; + +import java.io.BufferedInputStream; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.Reader; + +import javax.xml.XMLConstants; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; +import javax.xml.transform.stream.StreamSource; +import javax.xml.validation.Schema; +import javax.xml.validation.SchemaFactory; +import javax.xml.validation.Validator; + +import org.w3c.dom.Document; +import org.w3c.dom.ls.LSInput; +import org.w3c.dom.ls.LSResourceResolver; +import org.xml.sax.SAXException; + +/** + * Resource resolver input for RelaxNG schemas. + * + * @author Manuel Bentele + * @version 1.0 + */ +class LibvirtXmlSchemaResourceInput implements LSInput +{ + /** + * Stores the public identification of the schema resource. + */ + private String publicId; + + /** + * Stores the system identification of the schema resource. + */ + private String systemId; + + /** + * Stream to process and read the schema resource. + */ + private BufferedInputStream inputStream; + + /** + * Creates a resource resolver input for a RelaxNG schema. + * + * @param publicId public identification of the schema resource. + * @param sysId system identification of the schema resource. + * @param input stream of the schema resource. + */ + public LibvirtXmlSchemaResourceInput( String publicId, String sysId, InputStream input ) + { + this.publicId = publicId; + this.systemId = sysId; + this.inputStream = new BufferedInputStream( input ); + } + + @Override + public String getBaseURI() + { + return null; + } + + @Override + public InputStream getByteStream() + { + return null; + } + + @Override + public boolean getCertifiedText() + { + return false; + } + + @Override + public Reader getCharacterStream() + { + return null; + } + + @Override + public String getEncoding() + { + return null; + } + + @Override + public String getPublicId() + { + return this.publicId; + } + + @Override + public String getStringData() + { + String data = null; + + synchronized ( this.inputStream ) { + try { + int inputLength = this.inputStream.available(); + byte[] input = new byte[ inputLength ]; + this.inputStream.read( input ); + data = new String( input ); + } catch ( IOException e ) { + e.printStackTrace(); + } + } + + return data; + } + + @Override + public String getSystemId() + { + return this.systemId; + } + + @Override + public void setBaseURI( String arg0 ) + { + } + + @Override + public void setByteStream( InputStream arg0 ) + { + } + + @Override + public void setCertifiedText( boolean arg0 ) + { + } + + @Override + public void setCharacterStream( Reader arg0 ) + { + } + + @Override + public void setEncoding( String arg0 ) + { + } + + @Override + public void setPublicId( String arg0 ) + { + this.publicId = arg0; + } + + @Override + public void setStringData( String arg0 ) + { + } + + @Override + public void setSystemId( String arg0 ) + { + this.systemId = arg0; + } +} + +/** + * Resource resolver for RelaxNG schemas. + * + * @author Manuel Bentele + * @version 1.0 + */ +class LibvirtXmlSchemaResourceResolver implements LSResourceResolver +{ + @Override + public LSInput resolveResource( String type, String namespaceURI, String publicId, String systemId, String baseURI ) + { + InputStream rngResourceStream = LibvirtXmlResources.getLibvirtRng( systemId ); + return new LibvirtXmlSchemaResourceInput( publicId, systemId, rngResourceStream ); + } +} + +/** + * Validator for validation of Libvirt XML documents with RelaxNG schemas. + * + * @author Manuel Bentele + * @version 1.0 + */ +public class LibvirtXmlSchemaValidator +{ + /** + * RelaxNG based validator for validation of Libvirt XML documents. + */ + private Validator rngSchemaValidator; + + /** + * Creates a validator for validation of Libvirt XML documents with RelaxNG schemas. + * + * @param rngSchema + * @throws SAXException + */ + public LibvirtXmlSchemaValidator( InputStream rngSchema ) throws SAXException + { + this.createValidationContext( rngSchema ); + } + + /** + * Creates context for validation of Libvirt XML documents with a RelaxNG schema. + * + * @param rngSchema RelaxNG schema used for validation with {@link #validate(Document)}. + * + * @throws SAXException Loading, creation and processing of <code>rngSchema</code> has failed. + */ + private void createValidationContext( InputStream rngSchema ) throws SAXException + { + // use hack to load specific schema factory implementation for RelaxNG schemas + System.setProperty( SchemaFactory.class.getName() + ":" + XMLConstants.RELAXNG_NS_URI, + "com.thaiopensource.relaxng.jaxp.XMLSyntaxSchemaFactory" ); + + // create schema resource resolver to resolve schema resources during parsing and validation + LibvirtXmlSchemaResourceResolver schemaResolver = new LibvirtXmlSchemaResourceResolver(); + + // create schema factory to be able to create a RelaxNG schema validator + SchemaFactory factory = SchemaFactory.newInstance( XMLConstants.RELAXNG_NS_URI ); + factory.setResourceResolver( schemaResolver ); + Schema schema = factory.newSchema( new StreamSource( rngSchema ) ); + + // create the RelaxNG schema validator + this.rngSchemaValidator = schema.newValidator(); + this.rngSchemaValidator.setResourceResolver( schemaResolver ); + } + + /** + * Transforms a DOM source to a Stream source. + * + * @param domSource DOM source of a Libvirt XML document. + * @return Stream source of a Libvirt XML document. + * + * @throws TransformerException Transformation of DOM source to a Stream source has failed. + * + * @implNote This utility method is necessary in {@link #validate(Document)} to be able to + * validate a DOM Libvirt XML document with the schema and validator implementation for + * RelaxNG schema files from + * <code>com.thaiopensource.relaxng.jaxp.XMLSyntaxSchemaFactory</code>. + */ + private static StreamSource toStreamSource( DOMSource domSource ) throws TransformerException + { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + StreamResult result = new StreamResult( outputStream ); + + // create identity transformer + Transformer transformer = TransformerFactory.newInstance().newTransformer(); + transformer.transform( domSource, result ); + + ByteArrayInputStream inputStream = new ByteArrayInputStream( outputStream.toByteArray() ); + return new StreamSource( inputStream ); + } + + /** + * Validates a given (and parsed) DOM Libvirt XML document. + * + * Validation takes place if the specified <code>xmlDocument</code> is non-null, otherwise the + * validation succeeds immediately. If the validation of the <code>xmlDocument</code> fails, a + * validation exception is thrown. + * + * @param xmlDocument Libvirt XML document. + * + * @throws LibvirtXmlValidationException Validation of Libvirt XML document failed. + */ + public void validate( Document xmlDocument ) throws LibvirtXmlValidationException + { + if ( xmlDocument != null ) { + try { + DOMSource domSource = new DOMSource( xmlDocument ); + StreamSource source = LibvirtXmlSchemaValidator.toStreamSource( domSource ); + this.rngSchemaValidator.validate( source ); + } catch ( SAXException | TransformerException | IOException e ) { + throw new LibvirtXmlValidationException( e.getLocalizedMessage() ); + } + } + } +} diff --git a/src/main/java/org/openslx/libvirt/xml/LibvirtXmlSerializable.java b/src/main/java/org/openslx/libvirt/xml/LibvirtXmlSerializable.java new file mode 100644 index 0000000..6f11ce5 --- /dev/null +++ b/src/main/java/org/openslx/libvirt/xml/LibvirtXmlSerializable.java @@ -0,0 +1,57 @@ +package org.openslx.libvirt.xml; + +import java.io.File; +import java.io.InputStream; + +import org.xml.sax.InputSource; + +/** + * Serializability of a Libvirt XML document from/to a XML file. + * + * @author Manuel Bentele + * @version 1.0 + */ +public abstract interface LibvirtXmlSerializable +{ + /** + * Serialize Libvirt XML document from {@link String}. + * + * @param xml {@link String} containing XML content. + */ + public void fromXml( String xml ) throws LibvirtXmlSerializationException; + + /** + * Serialize Libvirt XML document from {@link File}. + * + * @param xml {@link File} containing XML content. + */ + public void fromXml( File xml ) throws LibvirtXmlSerializationException; + + /** + * Serialize Libvirt XML document from {@link InputStream}. + * + * @param xml {@link InputStream} providing XML content. + */ + void fromXml( InputStream xml ) throws LibvirtXmlSerializationException; + + /** + * Serialize Libvirt XML document from {@link InputSource}. + * + * @param xml {@link InputSource} providing XML content. + */ + public void fromXml( InputSource xml ) throws LibvirtXmlSerializationException; + + /** + * Serialize Libvirt XML document to {@link String}. + * + * @return XML {@link String} containing Libvirt XML document content. + */ + public String toXml() throws LibvirtXmlSerializationException; + + /** + * Serialize Libvirt XML document to {@link File}. + * + * @param xml XML {@link File} containing Libvirt XML document content. + */ + public void toXml( File xml ) throws LibvirtXmlSerializationException; +} diff --git a/src/main/java/org/openslx/libvirt/xml/LibvirtXmlSerializationException.java b/src/main/java/org/openslx/libvirt/xml/LibvirtXmlSerializationException.java new file mode 100644 index 0000000..d522107 --- /dev/null +++ b/src/main/java/org/openslx/libvirt/xml/LibvirtXmlSerializationException.java @@ -0,0 +1,25 @@ +package org.openslx.libvirt.xml; + +/** + * An exception of an serialization error during Libvirt XML serialization. + * + * @author Manuel Bentele + * @version 1.0 + */ +public class LibvirtXmlSerializationException extends Exception +{ + /** + * Version number for serialization. + */ + private static final long serialVersionUID = 7995955592221349949L; + + /** + * Creates a XML serialization exception including an error message. + * + * @param errorMsg message to describe a specific XML serialization error. + */ + public LibvirtXmlSerializationException( String errorMsg ) + { + super( errorMsg ); + } +} diff --git a/src/main/java/org/openslx/libvirt/xml/LibvirtXmlValidatable.java b/src/main/java/org/openslx/libvirt/xml/LibvirtXmlValidatable.java new file mode 100644 index 0000000..8574cc4 --- /dev/null +++ b/src/main/java/org/openslx/libvirt/xml/LibvirtXmlValidatable.java @@ -0,0 +1,18 @@ +package org.openslx.libvirt.xml; + +/** + * Validatability of Libvirt XML document. + * + * @author Manuel Bentele + * @version 1.0 + */ +public abstract interface LibvirtXmlValidatable +{ + /** + * Validates the XML document's content and report error if document is not a valid Libvirt XML + * document. + * + * @throws LibvirtXmlValidationException XML content is not a valid Libvirt XML. + */ + public void validateXml() throws LibvirtXmlValidationException; +} diff --git a/src/main/java/org/openslx/libvirt/xml/LibvirtXmlValidationException.java b/src/main/java/org/openslx/libvirt/xml/LibvirtXmlValidationException.java new file mode 100644 index 0000000..24e9db7 --- /dev/null +++ b/src/main/java/org/openslx/libvirt/xml/LibvirtXmlValidationException.java @@ -0,0 +1,25 @@ +package org.openslx.libvirt.xml; + +/** + * An exception of an unsuccessful Libvirt XML validation. + * + * @author Manuel Bentele + * @version 1.0 + */ +public class LibvirtXmlValidationException extends Exception +{ + /** + * Version number for serialization. + */ + private static final long serialVersionUID = 2299967599483742777L; + + /** + * Creates a validation exception including an error message. + * + * @param errorMsg message to describe a specific Libvirt XML error. + */ + public LibvirtXmlValidationException( String errorMsg ) + { + super( errorMsg ); + } +} |