package org.gbif.occurrence.ws.provider; import org.gbif.api.model.occurrence.VerbatimOccurrence; import org.gbif.dwc.terms.DwcTerm; import org.gbif.dwc.terms.Term; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; import java.lang.annotation.Annotation; import java.lang.reflect.Type; import javax.ws.rs.Produces; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.Response; import javax.ws.rs.ext.MessageBodyWriter; import javax.ws.rs.ext.Provider; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.OutputKeys; 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 org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Custom {@link MessageBodyWriter} to serialize {@link VerbatimOccurrence} in DarwinCore XML. * We do not use JAXB annotations to keep it easy to manage dynamic properties like verbatim fields map. * */ @Provider @Produces(MediaType.APPLICATION_XML) public class OccurrenceVerbatimDwcXMLBodyWriter implements MessageBodyWriter<VerbatimOccurrence> { private static final Logger LOG = LoggerFactory.getLogger(OccurrenceVerbatimDwcXMLBodyWriter.class); /** * Transforms a {@link VerbatimOccurrence} object into a byte[] representing a XML document. * * @param occurrence * @return the {@link VerbatimOccurrence} as byte[] * @throws WebApplicationException if something went wrong while generating the XML document */ private byte[] verbatimOccurrenceXMLAsByteArray(VerbatimOccurrence occurrence) throws WebApplicationException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); try { DwcXMLDocument dwcXMLDocument = DwcXMLDocument.newInstance(DwcTerm.Occurrence); for (Term term : occurrence.getVerbatimFields().keySet()) { dwcXMLDocument.tryAppend(term, occurrence.getVerbatimField(term)); } Transformer transformer = TransformerFactory.newInstance().newTransformer(); transformer.setOutputProperty(OutputKeys.INDENT, "yes"); DOMSource source = new DOMSource(dwcXMLDocument.getDocument()); StreamResult result = new StreamResult(baos); transformer.transform(source, result); } catch (ParserConfigurationException | TransformerException e) { LOG.error("Can't generate Dwc XML for VerbatimOccurrence [{}]", occurrence); throw new WebApplicationException(e, Response.Status.INTERNAL_SERVER_ERROR); } return baos.toByteArray(); } @Override public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) { return type == VerbatimOccurrence.class; } @Override public long getSize(VerbatimOccurrence occurrence, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) { // deprecated by JAX-RS 2.0 and ignored by Jersey runtime return -1L; } @Override public void writeTo(VerbatimOccurrence occurrence, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream) throws IOException, WebApplicationException { entityStream.write(verbatimOccurrenceXMLAsByteArray(occurrence)); } }