All Downloads are FREE. Search and download functionalities are using the official Maven repository.

fm.xml.XmlWriter.scala Maven / Gradle / Ivy

/*
 * Copyright 2014 Frugal Mechanic (http://frugalmechanic.com)
 *
 * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package fm.xml

import com.ctc.wstx.stax.WstxOutputFactory
import fm.common.Implicits._
import java.io.{Closeable, OutputStream}
import javax.xml.bind.{JAXBContext, Marshaller}
import org.codehaus.stax2.XMLStreamWriter2
import org.codehaus.stax2.validation.Validatable

final class XmlWriter(classes: Seq[Class[_]], rootName: String, defaultNamespace: String, outputStream: OutputStream) extends Closeable with Validatable {
  private[this] val jaxbContext: JAXBContext = JAXBContext.newInstance(classes: _*)
  
  private[this] val encoding: String = "UTF-8"
  
  private[this] val marshaller: Marshaller = jaxbContext.createMarshaller()
  marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true)
  marshaller.setProperty(Marshaller.JAXB_FRAGMENT, true)
  marshaller.setProperty(Marshaller.JAXB_ENCODING, encoding)
  
  private[this] val outputFactory: WstxOutputFactory = new WstxOutputFactory()
  outputFactory.configureForSpeed()
  
  private[this] val xmlStreamWriter2: XMLStreamWriter2 = outputFactory.createXMLStreamWriter(outputStream, encoding).asInstanceOf[XMLStreamWriter2]  
  private[this] val xmlStreamWriter: IndentingXMLStreamWriter = new IndentingXMLStreamWriter(xmlStreamWriter2)
  
  // If we are validating we need to be able to hookup validation before we start writing
  private lazy val init: Unit = {
    xmlStreamWriter.writeStartDocument(encoding, "1.0")
    
    if (defaultNamespace.isNotNullOrBlank) {
      xmlStreamWriter.setDefaultNamespace(defaultNamespace)
      xmlStreamWriter.writeStartElement(defaultNamespace, rootName)
      xmlStreamWriter.writeDefaultNamespace(defaultNamespace)
    } else {
      xmlStreamWriter.writeStartElement(rootName)
    }
  }
  
  // To be used with care
  def writeStartElement(name: String): Unit = {
    init
    
    // Need to use the defaultNamespace so validation works
    if (defaultNamespace.isNotNullOrBlank) xmlStreamWriter.writeStartElement(defaultNamespace, name)
    else xmlStreamWriter.writeStartElement(name)
  }

  // To be used with care
  def writeEndElement(): Unit = {
    init
    xmlStreamWriter.writeEndElement()
  }

  def writeWrapperElement(name: String) (f: => Unit): Unit = {
    writeStartElement(name)
    f
    writeEndElement()
  }
  
  def write(item: AnyRef): Unit = {
    init
    marshaller.marshal(item, xmlStreamWriter)
  }
  
  def close(): Unit = {
    init
    xmlStreamWriter.writeEndElement() // could do writeEndDocument but that's probably sloppy
    xmlStreamWriter.flush()
    xmlStreamWriter.close() // This does not close the underlying OutputStream
    outputStream.flush()
    outputStream.close()
  }
  
  //
  // Validatable implementation
  //
  import org.codehaus.stax2.validation._
  
  private def validatable: Validatable = xmlStreamWriter2
  
  def setValidationProblemHandler(h: ValidationProblemHandler): ValidationProblemHandler = validatable.setValidationProblemHandler(h)
  def stopValidatingAgainst(schema: XMLValidationSchema): XMLValidator = validatable.stopValidatingAgainst(schema)
  def stopValidatingAgainst(validator: XMLValidator): XMLValidator = validatable.stopValidatingAgainst(validator)
  def validateAgainst(schema: XMLValidationSchema): XMLValidator = validatable.validateAgainst(schema)
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy