package com.abiquo.appliancemanager.xml;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.XMLStreamWriter;
import org.dmtf.schemas.ovf.envelope._1.EnvelopeType;
import org.dmtf.schemas.ovf.envelope._1.MsgType;
import org.dmtf.schemas.ovf.envelope._1.VirtualHardwareSectionType;
import org.dmtf.schemas.ovf.envelope._1.VirtualSystemType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.abiquo.appliancemanager.exceptions.XMLException;
import com.abiquo.ovfindex.RepositorySpace;
/**
* Use JAXB to bind standard OVF-envelope and OVFIndex objects into/from XML documents.<br/>
*
* @see Stax2Factory, where Woodstox is used as StAX implementation of the underlying XML parser.
* @see ANT build file "jaxb" target, where the binding classes are generated.
* @TODO XMLStreamWriter can specify the encoding ... useful ?
* @TODO close writers even when an exception occurs.
*/
public class OVFSerializer
{
private final static Logger log = LoggerFactory.getLogger(OVFSerializer.class);
/** Define the allowed objects to be binded from/into the OVF-envelope schema definition. */
private final JAXBContext contextEnvelope;
/** Define the allowed objects to be binded form/into the OVFIndex schema definition. */
private final JAXBContext contextIndex;
/** Generated factory to create XML elements in OVF-envelope name space. */
private final org.dmtf.schemas.ovf.envelope._1.ObjectFactory factoryEnvelop;
/** Generated factory to create XML elements on OVFIndex name space. */
private final com.abiquo.ovfindex.ObjectFactory factoryIndex;
/** Specify to marshall process to format the XML document. @TODO.from configuration?. */
private final static boolean isFormattingWrite = true;
/**
* @TODO ensure Validation. Specify to unmarshall process to validate the XML document.
* @TODO.from configuration?. private final static boolean isValidatingRead = true;
*/
/** The singleton instance. */
private static OVFSerializer instance;
/**
* Get the OVFSerializer singelton instance.
*
* @return the OVFSerializer instance or null if it can not be created.
*/
public static OVFSerializer getInstance()
{
if (instance == null)
{
try
{
instance = new OVFSerializer();
}
catch (JAXBException e)
{
log.error("OVFSerializer instance can not be created ", e);
}
}
return instance;
}
/**
* Instantiate a new OVFSerializer.
*
* @throws JAXBException, if some JAXB context can not be created.
*/
private OVFSerializer() throws JAXBException
{
contextEnvelope = JAXBContext.newInstance(EnvelopeType.class);
contextIndex = JAXBContext.newInstance(RepositorySpace.class);
factoryEnvelop = new org.dmtf.schemas.ovf.envelope._1.ObjectFactory();
factoryIndex = new com.abiquo.ovfindex.ObjectFactory();
}
/**
* Creates an XML document representing the provided OVF-envelop and write it to output stream.
*
* @param envelope, the object to be binded into an XML document.
* @param os, the destination of the XML document.
* @throws XMLException, any XML problem.
*/
public void writeXML(EnvelopeType envelope, OutputStream os) throws XMLException
{
XMLStreamWriter writer;
Marshaller marshall;
try
{
writer = Stax2Factory.getStreamWriterFactory().createXMLStreamWriter(os);
marshall = contextEnvelope.createMarshaller();
if (isFormattingWrite)
{
marshall.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, new Boolean(true));
}
marshall.marshal(factoryEnvelop.createEnvelope(envelope), writer);
writer.close();
}
catch (JAXBException ea)
{
throw new XMLException(ea);
}
catch (XMLStreamException ex)
{
throw new XMLException(ex);
}
// finally writer.close();
}
/**
* Creates an XML document representing an OVF-envelop with the provided virtual system and
* write it to output stream.
*
* @param virutalSystem, the object inside the envelope to be binded into an XML document.
* @param os, the destination of the XML document.
* @throws XMLException, any XML problem.
*/
public void writeXML(VirtualSystemType virtualSystem, OutputStream os) throws XMLException
{
EnvelopeType envelope;
envelope = factoryEnvelop.createEnvelopeType();
envelope.setContent(factoryEnvelop.createVirtualSystem(virtualSystem));
writeXML(envelope, os);
}
/**
* Creates an XML document representing the provided repository space and write it to output
* stream.
*
* @param repoSpace, the object to be binded into an XML document.
* @param os, the destination of the XML document.
* @throws XMLException, any XML problem.
*/
public void writeXML(RepositorySpace repoSpace, OutputStream os) throws XMLException
{
XMLStreamWriter writer;
Marshaller marshall;
try
{
writer = Stax2Factory.getStreamWriterFactory().createXMLStreamWriter(os);
marshall = contextIndex.createMarshaller();
if (isFormattingWrite)
{
marshall.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, new Boolean(true));
}
marshall.marshal(factoryIndex.createRepositorySpace(repoSpace), writer);
writer.close();
}
catch (JAXBException ea)
{
throw new XMLException(ea);
}
catch (XMLStreamException ex)
{
throw new XMLException(ex);
}
}
/**
* Read an expected OVF-envelope form the provided source.
*
* @param is, the input stream source where read XML documents.
* @return the OVF-envelope read from source.
* @throws XMLException, if it is not an envelope type or any XML problem.
*/
public EnvelopeType readXMLEnvelope(InputStream is) throws XMLException
{
XMLStreamReader reader;
Unmarshaller unmarshall;
JAXBElement<EnvelopeType> jaxbEnvelope;
try
{
reader = Stax2Factory.getStreamReaderFactory().createXMLStreamReader(is);
unmarshall = contextEnvelope.createUnmarshaller();
jaxbEnvelope = unmarshall.unmarshal(reader, EnvelopeType.class);
reader.close();
}
catch (JAXBException ea)
{
throw new XMLException(ea);
}
catch (XMLStreamException ex)
{
throw new XMLException(ex);
}
return jaxbEnvelope.getValue();
}
/**
* Read an expected RepositorySpace form the provided source.
*
* @param is, the input stream source where read XML documents.
* @return the RepositorySpace read from source.
* @throws XMLException, if it is not a RepositorySpace type or any XML problem.
*/
public RepositorySpace readXMLRepositorySpace(InputStream is) throws XMLException
{
XMLStreamReader reader;
Unmarshaller unmarshall;
JAXBElement<RepositorySpace> jaxbRepo;
try
{
reader = Stax2Factory.getStreamReaderFactory().createXMLStreamReader(is);
unmarshall = contextIndex.createUnmarshaller();
jaxbRepo = unmarshall.unmarshal(reader, RepositorySpace.class);
reader.close();
}
catch (JAXBException ea)
{
throw new XMLException(ea);
}
catch (XMLStreamException ex)
{
throw new XMLException(ex);
}
return jaxbRepo.getValue();
}
/**
* Create an Envelepo to test
*
* @deprecated first test
*/
private EnvelopeType createTestEnvelope()
{
EnvelopeType enve;
enve = factoryEnvelop.createEnvelopeType();
VirtualSystemType virtualSystem = factoryEnvelop.createVirtualSystemType();
VirtualHardwareSectionType hw = factoryEnvelop.createVirtualHardwareSectionType();
virtualSystem.getSection().add(factoryEnvelop.createVirtualHardwareSection(hw));
MsgType msg = factoryEnvelop.createMsgType();
msg.setValue("hello OVF");
virtualSystem.setInfo(msg);
virtualSystem.setId("unid");
enve.setContent(factoryEnvelop.createContent(virtualSystem));
return enve;
}
/**
* run a create/write/read first test
*
* @deprecated
*/
public static void main(String[] args) throws Exception
{
final String filePath = "resources/xml/envelopeexample2.xml";
EnvelopeType envelop;
OVFSerializer ovfserial = new OVFSerializer();
envelop = ovfserial.createTestEnvelope();
System.err.println("created");
ovfserial.writeXML(envelop, new FileOutputStream(new File(filePath)));
System.err.println("writed");
envelop = ovfserial.readXMLEnvelope(new FileInputStream(new File(filePath)));
System.err.println("readed");
}
}