/** * The contents of this file are subject to the Mozilla Public License * Version 1.1 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the * License for the specific language governing rights and limitations * under the License. * * The Original Code is available at https://svn.forge.morfeo-project.org/claudia * * The Initial Developer of the Original Code is Telefonica Investigacion y Desarrollo S.A.U., * (http://www.tid.es), Emilio Vargas 6, 28043 Madrid, Spain. .* * No portions of the Code have been created by third parties. * All Rights Reserved. * * Contributor(s): ______________________________________. * */ package com.abiquo.ovf.xml; import java.io.InputStream; import java.io.OutputStream; import java.io.StringWriter; import java.net.URL; import javax.xml.bind.Binder; 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.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamReader; import javax.xml.stream.XMLStreamWriter; import javax.xml.validation.Schema; import javax.xml.validation.SchemaFactory; import org.dmtf.schemas.ovf.environment._1.EnvironmentType; import org.dmtf.schemas.ovf.environment._1.ObjectFactory; import org.dmtf.schemas.ovf.environment._1.PlatformSectionType; import org.dmtf.schemas.ovf.environment._1.PropertySectionType; import org.dmtf.schemas.ovf.environment._1.SectionType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.w3c.dom.Node; import com.abiquo.ovf.exceptions.XMLException; public class OVFEnvironmentSerializer { private final static Logger logger = LoggerFactory.getLogger(OVFEnvironmentSerializer.class); /** Define the allowed objects to be binded from/into the OVF-environment schema definition. */ private final JAXBContext contextEnvironment; /** Generated factory to create XML elements in OVF-environment name space. */ private final ObjectFactory factoryEnvironment; /** Determines if the marshalling process to format the XML document.*/ private boolean formatOutput = true; /** Determines if the unmarshalling process is to validate the XML document.*/ private boolean validateXML = true; /** Path to the OVF XSD schema document (in order to validate documents). */ private final static String OVF_ENVIRONMENT_SCHEMA_LOCATION = "resources/schemas/dsp8027.xsd"; /** Used to validate XML documents. */ private Schema environmentSchema; /** The singleton instance. */ private static OVFEnvironmentSerializer instance; /** Used to bind an environment into a DOM document. **/ private static DocumentBuilderFactory docBuilderFact = DocumentBuilderFactory.newInstance(); //** Define the allowed objects to be binded form/into the OVFIndex schema definition. */ //private final JAXBContext contextIndex; ///** Generated factory to create XML elements on OVFIndex name space. */ //private final com.abiquo.repositoryspace.ObjectFactory factoryIndex; /** * Get the OVFSerializer singelton instance. * * @return the OVFSerializer instance or null if it can not be created. */ public static OVFEnvironmentSerializer getInstance() { if (instance == null) { try { instance = new OVFEnvironmentSerializer(); } catch (JAXBException e) { logger.error("OVFSerializer instance can not be created ", e); } } return instance; } /** * Configure the ''formatOutput'' property. * Determines if the marshalling process to format the XML document. * */ public void setFormatOutput(boolean formatOutput) { this.formatOutput = formatOutput; } /** * Configure the ''validateXML'' property. * Determines if the unmarshalling process is to validate the XML document. * @throws JAXBException, if the schema can not be located. * */ public void setValidateXML(boolean validateXML) throws JAXBException { this.validateXML = validateXML; if(validateXML) { configureValidation(); } } /** * Set up the schema to be used during validation. * @throws JAXBException * */ private void configureValidation() throws JAXBException { //SchemaFactory sf = SchemaFactory.newInstance(javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI); SchemaFactory sf = SchemaFactory.newInstance(javax.xml.XMLConstants.DEFAULT_NS_PREFIX); URL schemaURL = OVFSerializer.class.getClassLoader().getResource(OVF_ENVIRONMENT_SCHEMA_LOCATION); try { logger.debug("Using schema from [{}]", schemaURL.toExternalForm()); environmentSchema = sf.newSchema(schemaURL); } catch (Exception e) // SAXException or Null pointer { throw new JAXBException("Can not localize the OVFEnvironment schema in order to validate documents",e); } } /** * Instantiate a new OVFSerializer. * * @throws JAXBException, if some JAXB context can not be created. */ private OVFEnvironmentSerializer() throws JAXBException { contextEnvironment = JAXBContext.newInstance(EnvironmentType.class); factoryEnvironment = new ObjectFactory(); //contextIndex = JAXBContext.newInstance(new Class[]{EnvironmentType.class});//RepositorySpace.class,OVFIndex.class}); //factoryIndex = new com.abiquo.repositoryspace.ObjectFactory(); } /** * Creates an XML document representing the provided OVF-envelop and write it to output stream. * * @param environment, 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(EnvironmentType environment, OutputStream os) throws XMLException { XMLStreamWriter writer; Marshaller marshall; try { writer = Stax2Factory.getStreamWriterFactory().createXMLStreamWriter(os); marshall = contextEnvironment.createMarshaller(); if (formatOutput) { marshall.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); } marshall.marshal(factoryEnvironment.createEnvironment(environment), writer); writer.close(); } catch (JAXBException ea) { throw new XMLException(ea); } catch (XMLStreamException ex) { throw new XMLException(ex); } } /** * Creates an XML document representing the provided OVF-section and write it to output stream. * * @param section, 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(SectionType section, OutputStream os) throws XMLException { XMLStreamWriter writer; Marshaller marshall; try { writer = Stax2Factory.getStreamWriterFactory().createXMLStreamWriter(os); marshall = contextEnvironment.createMarshaller(); if (formatOutput) { marshall.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); } marshall.marshal(toJAXBElement(section), writer); writer.close(); } catch (JAXBException ea) { throw new XMLException(ea); } catch (XMLStreamException ex) { throw new XMLException(ex); } } /** * Creates an XML document representing the provided OVF-section and write it to formatter string. * * @param section, the object to be binded into an XML document. * @throws XMLException, any XML problem. */ public String writeXML(SectionType section) throws XMLException { Marshaller marshall; StringWriter writer = new StringWriter(); try { marshall = contextEnvironment.createMarshaller(); if (formatOutput) { marshall.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); } marshall.marshal(toJAXBElement(section), writer); return writer.toString(); } catch (JAXBException ea) { throw new XMLException(ea); } } /** * Read an expected OVF-environment form the provided source. * * @param is, the input stream source where read XML documents. * @return the OVF-environment read from source. * @throws XMLException, if it is not an environment type or any XML problem. */ public EnvironmentType readXMLEnvironment(InputStream is) throws XMLException { XMLStreamReader reader; Unmarshaller unmarshall; JAXBElement<EnvironmentType> jaxbEnvironment; try { reader = Stax2Factory.getStreamReaderFactory().createXMLStreamReader(is); unmarshall = contextEnvironment.createUnmarshaller(); if(validateXML) { unmarshall.setSchema(environmentSchema); } jaxbEnvironment = unmarshall.unmarshal(reader, EnvironmentType.class); reader.close(); } catch (JAXBException ea) { ea.printStackTrace(); // TODO remove throw new XMLException(ea); } catch (XMLStreamException ex) { ex.printStackTrace(); // TODO remove throw new XMLException(ex); } return jaxbEnvironment.getValue(); } /** Wrap into an JAXBElement the provided OVF environment.**/ public JAXBElement<EnvironmentType> toJAXBElement(EnvironmentType environment) { return factoryEnvironment.createEnvironment(environment); } /** Wrap into an JAXBElement the provided OVF environment section.**/ @SuppressWarnings("unchecked") public <T extends SectionType> JAXBElement<T> toJAXBElement(T section) { JAXBElement<T> jaxB; if(section instanceof PlatformSectionType) { jaxB = (JAXBElement<T>) factoryEnvironment.createPlatformSection((PlatformSectionType) section); } else if(section instanceof PropertySectionType) { jaxB = (JAXBElement<T>) factoryEnvironment.createPropertySection((PropertySectionType) section); } else { // TODO throws an exception for invalid section jaxB = null; } return jaxB; } /** * Wrap into an DOM document the provided OVF environment. * @param environment, the OVF environment the be wrapped * @param isNamespaceAware, determine if the created document is XML name space aware. * @return a DOM document containing the provided OVF environment. * TODO rename to "toDocument" * */ public Document bindToDocument(EnvironmentType environment, boolean isNamespaceAware) throws ParserConfigurationException, JAXBException { // Now serialize the Java Content tree back to XML data docBuilderFact.setNamespaceAware(isNamespaceAware); DocumentBuilder docBuilder = docBuilderFact.newDocumentBuilder(); Document doc = docBuilder.newDocument(); Binder<Node> binder = contextEnvironment.createBinder(); binder.marshal(toJAXBElement(environment), doc); return doc; } }