summaryrefslogblamecommitdiffstats
path: root/src/main/java/org/openslx/libvirt/xml/LibvirtXmlSchemaValidator.java
blob: d589d41b9c830570a2a8491f6082a5d335d79d0a (plain) (tree)
1
2
3
4
5
6
7
8
9







                                     
                                         

                              

































































































                                                                                                
                                                                                   
























































































                                                                                                                            


                                                                                                
           
                                                                                     










                                                                                                      
                                                                                         










                                                                                                            
                                                                                   























































                                                                                                            
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 java.nio.charset.StandardCharsets;

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, StandardCharsets.UTF_8 );
			} 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 RelaxNG schema used for validation with {@link #validate(Document)}.
	 * 
	 * @throws SAXException creation of a Libvirt XML validator failed.
	 */
	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() );
			}
		}
	}
}