package de.jpaw.bonaparte.xml;
import java.io.OutputStream;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
import de.jpaw.bonaparte.core.AbstractMessageWriter;
import de.jpaw.bonaparte.core.BonaCustom;
import de.jpaw.bonaparte.core.BonaPortable;
/** Via XmlWriter, elements can be written sequentially, avoiding to keep everything in memory at once. */
public class XmlWriter<T extends BonaPortable> extends AbstractMessageWriter<XMLStreamException> {
private final boolean formatted;
private final boolean fragment;
private final Marshaller m;
private final String dataTag;
private final XMLStreamWriter sw;
private final Class<T> cls;
public XmlWriter(Marshaller m, OutputStream os, boolean formatted, boolean fragment, Class<T> cls, String outerElementName) throws Exception {
this.m = m;
this.formatted = formatted;
this.fragment = fragment;
this.cls = cls;
this.dataTag = outerElementName == null ? "data" : outerElementName;
this.sw = XMLOutputFactory.newFactory().createXMLStreamWriter(os);
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.valueOf(formatted));
m.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.valueOf(fragment)); // with XmlStreamWriter, fragments can be written
}
private void conditionalNewline(XMLStreamWriter sw) throws XMLStreamException {
if (formatted) {
if (getWriteCRs())
sw.writeCharacters("\r");
sw.writeCharacters("\n");
}
}
@Override
public void startTransmission() throws XMLStreamException {
sw.writeStartDocument();
conditionalNewline(sw);
sw.writeStartElement(dataTag);
conditionalNewline(sw);
}
@Override
public void writeRecord(BonaCustom o) throws XMLStreamException {
JAXBElement<T> element = new JAXBElement<T>(QName.valueOf(o.getClass().getSimpleName()), cls, (T) o);
try {
m.marshal(element, sw);
} catch (JAXBException e) {
throw new XMLStreamException(e);
}
}
@Override
public void terminateTransmission() throws XMLStreamException {
sw.writeEndElement();
sw.writeEndDocument();
conditionalNewline(sw);
}
@Override
public void writeObject(BonaCustom o) throws XMLStreamException {
if (fragment)
throw new UnsupportedOperationException("Cannot write single objects in streaming mode");
}
}