Commit d710573e authored by Tony Schaller's avatar Tony Schaller

Unicode Fix for automatic generated XDS metadata from a CDA

Added Methods for loading UTF-8 files into stream
DemoDocSource refactored

git-svn-id: https://svn.code.sf.net/p/ehealthconnector/code/trunk@1704 e99adb7c-5e35-42fd-8d1b-cdb378af05e8
parent cc8b18e6
......@@ -16,7 +16,6 @@
*/
using System;
using System.Text;
using java.text;
using org.ehealth_connector.common;
using org.ehealth_connector.communication;
......
......@@ -513,10 +513,20 @@ namespace eHealthConnectorDemo
return step;
}
/**
* Finds the last registered document.
*
* @param qr
* the query response
* @param mimeType
* the mime type
* @return the document entry type
*/
private DocumentEntryType findLastDoc(XDSQueryResponseType qr, String mimeType)
{
DocumentEntryType docEntry = null;
for (int i = 0; i < qr.getDocumentEntryResponses().size(); i++)
for (int i = (qr.getDocumentEntryResponses().size() - 1); i < qr.getDocumentEntryResponses()
.size(); i--)
{
DocumentEntryResponseType response = (DocumentEntryResponseType)qr.getDocumentEntryResponses()
.get((qr.getDocumentEntryResponses().size() - 1) - i);
......
......@@ -16,9 +16,6 @@
*/
using org.ehealth_connector.communication;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace eHealthConnectorDemo
{
......
......@@ -227,7 +227,7 @@ public class XdResources {
// Uri and LanguageCode
final Attachment attachment = new Attachment();
attachment.setLanguage(docLangCode);
attachment.setUrl(DemoDocSource.CDA_FILE_PATH);
attachment.setUrl(DemoDocSource.DOC_CDA);
doc.getContentFirstRep().setAttachment(attachment);
// Authors
......@@ -414,7 +414,7 @@ public class XdResources {
// Uri and LanguageCode
final Attachment attachment = new Attachment();
attachment.setLanguage(docLangCode);
attachment.setUrl(DemoDocSource.PDF_FILE_PATH);
attachment.setUrl(DemoDocSource.DOC_PDF);
doc.getContentFirstRep().setAttachment(attachment);
// Authors
......@@ -597,7 +597,7 @@ public class XdResources {
// Uri and LanguageCode
final Attachment attachment = new Attachment();
attachment.setLanguage(docLangCode);
attachment.setUrl(DemoDocSource.CDA_FILE_PATH);
attachment.setUrl(DemoDocSource.DOC_CDA);
doc.getContentFirstRep().setAttachment(attachment);
// Authors
......@@ -786,7 +786,7 @@ public class XdResources {
// Uri and LanguageCode
final Attachment attachment = new Attachment();
attachment.setLanguage(docLangCode);
attachment.setUrl(DemoDocSource.PDF_FILE_PATH);
attachment.setUrl(DemoDocSource.DOC_PDF);
doc.getContentFirstRep().setAttachment(attachment);
// Authors
......
......@@ -483,9 +483,19 @@ public class DemoDocConsumer {
return step;
}
/**
* Finds the last registered document.
*
* @param qr
* the query response
* @param mimeType
* the mime type
* @return the document entry type
*/
private DocumentEntryType findLastDoc(XDSQueryResponseType qr, String mimeType) {
DocumentEntryType docEntry = null;
for (int i = 0; i < qr.getDocumentEntryResponses().size(); i++) {
for (int i = (qr.getDocumentEntryResponses().size() - 1); i < qr.getDocumentEntryResponses()
.size(); i--) {
final DocumentEntryResponseType response = qr.getDocumentEntryResponses()
.get((qr.getDocumentEntryResponses().size() - 1) - i);
docEntry = response.getDocumentEntry();
......
......@@ -84,8 +84,8 @@ public class DemoDocSource {
// The Logger
private static Logger log = LoggerFactory.getLogger(DemoDocSource.class);
public static final String PDF_FILE_PATH = "demoDocSource/patientconsent.pdf";
public static final String CDA_FILE_PATH = "demoDocSource/CDA-CH-VACD_Impfausweis.xml";
public static final String DOC_PDF = "demoDocSource/patientconsent.pdf";
public static final String DOC_CDA = "demoDocSource/CDA-CH-VACD_Impfausweis.xml";
// Hard coded feature toggles
public static final boolean FEATURE_SWISS_EPR_USING_ENUMS_ENABLE = true;
......@@ -149,11 +149,15 @@ public class DemoDocSource {
for (final DocumentMetadata item : res.GetDocumentMetadatas(transaction,
receiverFacilityOid, senderFacilityOid)) {
final InputStream inputStream = getClass().getResourceAsStream("/" + item.getUri());
final DocumentMetadata documentMetadata = conCom
.addDocument(item.getDocumentDescriptor(), inputStream);
final InputStream inputStreamMetadata = getClass()
.getResourceAsStream("/" + item.getUri());
final DocumentMetadata documentMetadata = conCom.addDocument(
item.getDocumentDescriptor(), inputStream, inputStreamMetadata);
// remove URI before submission
item.setUri(null);
documentMetadata.setMetadata(item);
inputStream.close();
inputStreamMetadata.close();
}
System.out.print("done\n\n");
......@@ -225,12 +229,11 @@ public class DemoDocSource {
conCom.clearDocuments();
// assemble two files for the XDM Zip
final InputStream inputStream = getClass().getResourceAsStream("/" + CDA_FILE_PATH);
DocumentMetadata metaData = conCom.addDocument(DocumentDescriptor.CDA_R2, inputStream);
DocumentMetadata metaData = conCom.addDocument(DocumentDescriptor.CDA_R2, getDocCda(),
getDocCda());
setNistMetadataForCda(metaData);
final InputStream inputStream2 = getClass().getResourceAsStream("/" + PDF_FILE_PATH);
metaData = conCom.addDocument(DocumentDescriptor.PDF, inputStream2);
metaData = conCom.addDocument(DocumentDescriptor.PDF, getDocPdf());
setNistMetadataForPdf(metaData);
// create a FileOutputStream to store the zip file
......@@ -278,12 +281,11 @@ public class DemoDocSource {
conCom.clearDocuments();
// assemble two files for the XDM Zip
final InputStream inputStream = getClass().getResourceAsStream("/" + CDA_FILE_PATH);
DocumentMetadataCh metaData = conCom.addChDocument(DocumentDescriptor.CDA_R2, inputStream);
DocumentMetadataCh metaData = conCom.addChDocument(DocumentDescriptor.CDA_R2, getDocCda(),
getDocCda());
setSwissEprMetadataForCda(metaData);
final InputStream inputStream2 = getClass().getResourceAsStream("/" + PDF_FILE_PATH);
metaData = conCom.addChDocument(DocumentDescriptor.PDF, inputStream2);
metaData = conCom.addChDocument(DocumentDescriptor.PDF, getDocPdf());
setSwissEprMetadataForPdf(metaData);
// create a FileOutputStream to store the zip file
......@@ -398,13 +400,9 @@ public class DemoDocSource {
SubmissionSetMetadataExtractionMode.NO_METADATA_EXTRACTION);
// Sub-Step 1: Sending CDA Document to Repository (NON-TLS)
final InputStream inputStream1 = getClass()
.getResourceAsStream("/" + CDA_FILE_PATH);
final DocumentMetadata metaData1 = conCom1.addDocument(DocumentDescriptor.CDA_R2,
inputStream1);
getDocCda(), getDocCda());
setNistMetadataForCda(metaData1);
inputStream1.close();
System.out.print(DemoDocCommon.dateFormat.format(new Date()) + ": Step " + step
+ "." + subStep + " Sending CDA Document to " + DemoDocCommon.NIST_TOOL_NAME
......@@ -440,21 +438,13 @@ public class DemoDocSource {
System.out.print(DemoDocCommon.checkAndEnableXua(conCom2, assertionFile));
// Sub-Step 2: Sending CDA and PDF Document to Repository (TLS)
final InputStream inputStream2 = getClass()
.getResourceAsStream("/" + CDA_FILE_PATH);
final DocumentMetadata metaData21 = conCom2.addDocument(DocumentDescriptor.CDA_R2,
inputStream2);
getDocCda(), getDocCda());
setNistMetadataForCda(metaData21);
inputStream2.close();
final InputStream inputStream3 = getClass()
.getResourceAsStream("/" + PDF_FILE_PATH);
final DocumentMetadata metaData22 = conCom2.addDocument(DocumentDescriptor.PDF,
inputStream3);
getDocPdf());
setNistMetadataForPdf(metaData22);
inputStream3.close();
SubmissionSetType subset = conCom2.generateDefaultSubmissionSetAttributes();
subset.setContentTypeCode(XdsMetadataUtil.convertEhcCodeToCodedMetadataType(
......@@ -528,13 +518,9 @@ public class DemoDocSource {
affinityDomain);
// Sub-Step 1: Sending CDA Document to Repository (NON-TLS)
final InputStream inputStream1 = getClass()
.getResourceAsStream("/" + CDA_FILE_PATH);
final DocumentMetadataCh metaData1 = conCom1
.addChDocument(DocumentDescriptor.CDA_R2, inputStream1);
.addChDocument(DocumentDescriptor.CDA_R2, getDocCda(), getDocCda());
setSwissEprMetadataForCda(metaData1);
inputStream1.close();
System.out.print(DemoDocCommon.dateFormat.format(new Date()) + ": Step " + step
+ "." + subStep + " Sending CDA Document to "
......@@ -572,21 +558,13 @@ public class DemoDocSource {
System.out.print(DemoDocCommon.checkAndEnableXua(conCom2, assertionFile));
// Sub-Step 2: Sending CDA and PDF Document to Repository (TLS)
final InputStream inputStream2 = getClass()
.getResourceAsStream("/" + CDA_FILE_PATH);
final DocumentMetadataCh metaData21 = conCom2
.addChDocument(DocumentDescriptor.CDA_R2, inputStream2);
.addChDocument(DocumentDescriptor.CDA_R2, getDocCda(), getDocCda());
setSwissEprMetadataForCda(metaData21);
inputStream2.close();
final InputStream inputStream3 = getClass()
.getResourceAsStream("/" + PDF_FILE_PATH);
final DocumentMetadataCh metaData22 = conCom2.addChDocument(DocumentDescriptor.PDF,
inputStream3);
getDocPdf());
setSwissEprMetadataForPdf(metaData22);
inputStream3.close();
// SwissEPR specific
final SubmissionSetType subSet = conCom2.getTxnData().getSubmissionSet();
......@@ -648,18 +626,14 @@ public class DemoDocSource {
System.out.print(DemoDocCommon.checkAndEnableXua(conCom1, assertionFile));
final InputStream inputStream1 = getClass()
.getResourceAsStream("/" + CDA_FILE_PATH);
final FolderMetadata folderMeta1 = conCom1
.addFolder(new Code("1.3.6.1.4.1.21367.2017.3", "UNSPECIFIED-CONTENT-TYPE",
"Unspecified Clinical Activity"));
setNistMetadataForFolder(folderMeta1, "This is a Folder");
final DocumentMetadata metaData1 = conCom1.addDocument(DocumentDescriptor.CDA_R2,
inputStream1);
getDocCda(), getDocCda());
setNistMetadataForCda(metaData1);
inputStream1.close();
conCom1.addDocumentToFolder(metaData1.getEntryUUID(), folderMeta1.getEntryUUID());
......@@ -726,22 +700,16 @@ public class DemoDocSource {
setNistMetadataForFolder(folderMeta2, "This is a Folder");
// add 1st document
final InputStream inputStream2 = getClass()
.getResourceAsStream("/" + CDA_FILE_PATH);
final DocumentMetadata metaData21 = conCom21.addDocument(DocumentDescriptor.CDA_R2,
inputStream2);
getDocCda(), getDocCda());
setNistMetadataForCda(metaData21);
conCom21.addDocumentToFolder(metaData21.getEntryUUID(), folderMeta2.getEntryUUID());
inputStream2.close();
// add 2nd document
final InputStream inputStream3 = getClass()
.getResourceAsStream("/" + PDF_FILE_PATH);
final DocumentMetadata metaData22 = conCom21.addDocument(DocumentDescriptor.PDF,
inputStream3);
getDocPdf());
setNistMetadataForPdf(metaData22);
conCom21.addDocumentToFolder(metaData22.getEntryUUID(), folderMeta2.getEntryUUID());
inputStream3.close();
SubmissionSetType subset = conCom21.generateDefaultSubmissionSetAttributes();
subset.setContentTypeCode(XdsMetadataUtil.convertEhcCodeToCodedMetadataType(
......@@ -783,14 +751,11 @@ public class DemoDocSource {
+ " Sending CDA Document associated with folder to NIST-Repository (TLS)...\n");
// add document document
final InputStream inputStream23 = getClass()
.getResourceAsStream("/" + CDA_FILE_PATH);
final DocumentMetadata docMetaData23 = conCom22
.addDocument(DocumentDescriptor.CDA_R2, inputStream23);
.addDocument(DocumentDescriptor.CDA_R2, getDocCda(), getDocCda());
setNistMetadataForCda(docMetaData23);
conCom22.addDocumentToFolder(docMetaData23.getEntryUUID(),
folderMeta22.getEntryUUID());
inputStream23.close();
// submit the document associated to the folder
subset = conCom22.generateDefaultSubmissionSetAttributes();
......@@ -841,6 +806,24 @@ public class DemoDocSource {
return new Destination(organizationalId, repositoryUri);
}
/**
* Gets the sample CDA document stream.
*
* @return a CDA document stream
*/
private InputStream getDocCda() {
return getClass().getResourceAsStream("/" + DOC_CDA);
}
/**
* Gets the sample PDF document stream.
*
* @return a PDF document stream
*/
private InputStream getDocPdf() {
return getClass().getResourceAsStream("/" + DOC_PDF);
}
/**
* Method to initialize the xds atna stuff
*
......@@ -1087,5 +1070,4 @@ public class DemoDocSource {
metaData.setTitle("Informed Consent");
}
}
......@@ -67,8 +67,7 @@ public abstract class CdaChUtil extends CdaUtil {
throws Exception {
FileInputStream fs = new FileInputStream(filePath);
CdaChLrepV1GeneralReport retVal = loadCdaChLrepV1GeneralReportFromStream(
IOUtils.toInputStream(IOUtils.toString(new InputStreamReader(fs, "UTF-8")),
Charsets.UTF_8));
Util.getUtf8InputStream(fs));
fs.close();
return retVal;
}
......@@ -98,8 +97,7 @@ public abstract class CdaChUtil extends CdaUtil {
String filePath) throws Exception {
FileInputStream fs = new FileInputStream(filePath);
CdaChV2StructuredBody<org.openhealthtools.mdht.uml.cda.ch.CdaChV2StructuredBody> retVal = loadCdaChV2FromStream(
IOUtils.toInputStream(IOUtils.toString(new InputStreamReader(fs, "UTF-8")),
Charsets.UTF_8));
Util.getUtf8InputStream(fs));
fs.close();
return retVal;
}
......
......@@ -18,10 +18,13 @@
package org.ehealth_connector.common.utils;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
......@@ -33,8 +36,22 @@ import java.util.Map;
import java.util.Random;
import java.util.Stack;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerFactoryConfigurationError;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.apache.commons.io.Charsets;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringEscapeUtils;
import org.apache.commons.lang3.SystemUtils;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
......@@ -84,6 +101,10 @@ import org.openhealthtools.mdht.uml.hl7.datatypes.TEL;
import org.openhealthtools.mdht.uml.hl7.vocab.EntityNameUse;
import org.openhealthtools.mdht.uml.hl7.vocab.NullFlavor;
import org.openhealthtools.mdht.uml.hl7.vocab.x_ActRelationshipEntryRelationship;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
/**
* Helper methods for the eHealth Connector and CDA
......@@ -143,6 +164,57 @@ public class Util {
return il;
}
/**
* Escapes all non java character in the inputsream that is expected as XML
*
* @param inputStream
* the input stream to be escaped
* @return the input stream
*/
public static InputStream convertNonAsciiText2Unicode(InputStream inputStream) {
InputStream retVal = null;
DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder;
try {
docBuilder = docBuilderFactory.newDocumentBuilder();
Document document = docBuilder.parse(inputStream);
convertNonAsciiText2Unicode(document.getDocumentElement());
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
Source xmlSource = new DOMSource(document);
Result outputTarget = new StreamResult(outputStream);
TransformerFactory.newInstance().newTransformer().transform(xmlSource, outputTarget);
retVal = new ByteArrayInputStream(outputStream.toByteArray());
} catch (ParserConfigurationException | SAXException | IOException | TransformerException
| TransformerFactoryConfigurationError e) {
// Do nothing
}
return retVal;
}
/**
* Escapes all non java character in the node text.
*
* @param node
* the node to be escaped
*/
public static void convertNonAsciiText2Unicode(Node node) {
if (node.getFirstChild() != null) {
String nodeValue = node.getFirstChild().getNodeValue();
if (nodeValue != null) {
nodeValue = nodeValue.replace("\n", "").replace("\t", "");
node.getFirstChild().setNodeValue(StringEscapeUtils.escapeJava(nodeValue));
}
}
NodeList nodeList = node.getChildNodes();
for (int i = 0; i < nodeList.getLength(); i++) {
Node currentNode = nodeList.item(i);
if (currentNode.getNodeType() == Node.ELEMENT_NODE) {
// calls this method for all the children which is Element
convertNonAsciiText2Unicode(currentNode);
}
}
}
/**
* Creates an address
*
......@@ -1141,6 +1213,64 @@ public class Util {
}
/**
* Gets the utf 8 input stream from file.
*
* @param file
* the file
* @return the utf 8 input stream from file
*/
public static InputStream getUtf8InputStream(File file) {
try {
return getUtf8InputStream(new FileInputStream(file));
} catch (IOException e) {
return null;
}
}
/**
* Gets the utf 8 input stream from file.
*
* @param fis
* the fis
* @return the utf 8 input stream from file
*/
public static InputStream getUtf8InputStream(FileInputStream fis) {
try {
return IOUtils.toInputStream(IOUtils.toString(new InputStreamReader(fis, "UTF-8")),
Charsets.UTF_8);
} catch (IOException e) {
return null;
}
}
/**
* Gets the utf 8 input stream from file.
*
* @param is
* the is
* @return the utf 8 input stream from file
*/
public static InputStream getUtf8InputStream(InputStream is) {
try {
return IOUtils.toInputStream(IOUtils.toString(new InputStreamReader(is, "UTF-8")),
Charsets.UTF_8);
} catch (IOException e) {
return null;
}
}
/**
* Gets the utf 8 input stream from file.
*
* @param fileName
* the file name
* @return the utf 8 input stream from file
*/
public static InputStream getUtf8InputStream(String fileName) {
return getUtf8InputStream(new File(fileName));
}
/**
* Gets the free Java VM heap space in mega bytes.
*
......
......@@ -26,6 +26,7 @@ import java.io.InputStream;
import org.ehealth_connector.common.Identificator;
import org.ehealth_connector.common.ch.AuthorCh;
import org.ehealth_connector.common.ch.enums.AuthorRole;
import org.ehealth_connector.common.utils.Util;
import org.ehealth_connector.communication.AffinityDomain;
import org.ehealth_connector.communication.AtnaConfig.AtnaConfigMode;
import org.ehealth_connector.communication.ConvenienceCommunication;
......@@ -95,6 +96,23 @@ public class ConvenienceCommunicationCh extends ConvenienceCommunication {
* @return the document metadata (which have to be completed)</div>
*/
public DocumentMetadataCh addChDocument(DocumentDescriptor desc, InputStream inputStream) {
return addChDocument(desc, inputStream, null);
}
/**
* <div class="en">Adds a document to the XDS Submission set.
*
* @param desc
* the document descriptor (which kind of document do you want to
* transfer? e.g. PDF, CDA,...)
* @param inputStream
* the input stream to the document
* @param inputStream4Metadata
* the input stream 4 metadata
* @return the document metadata (which have to be completed)</div>
*/
public DocumentMetadataCh addChDocument(DocumentDescriptor desc, InputStream inputStream,
InputStream inputStream4Metadata) {
DocumentMetadataCh retVal = null;
if (inputStream == null)
try {
......@@ -104,8 +122,13 @@ public class ConvenienceCommunicationCh extends ConvenienceCommunication {
}
XDSDocument doc;
try {
XDSDocument doc4Metadata = null;
if (inputStream4Metadata != null) {
doc4Metadata = new XDSDocumentFromStream(desc,
Util.convertNonAsciiText2Unicode(inputStream4Metadata));
}
doc = new XDSDocumentFromStream(desc, inputStream);
retVal = new DocumentMetadataCh(addXdsDocument(doc, desc));
retVal = new DocumentMetadataCh(addXdsDocument(doc, desc, doc4Metadata));
} catch (final IOException e) {
e.printStackTrace();
}
......
......@@ -201,12 +201,35 @@ public class ConvenienceCommunication {
* @return the document metadata (which have to be completed)</div>
*/
public DocumentMetadata addDocument(DocumentDescriptor desc, InputStream inputStream) {
return addDocument(desc, inputStream, null);
}
/**
* <div class="en">Adds a document to the XDS Submission set.
*
* @param desc
* the document descriptor (which kind of document do you want to
* transfer? e.g. PDF, CDA,...)
* @param inputStream
* The input stream to the document
* @param inputStream4Metadata
* the input stream that is only used to get the metadata from
* (it's texts will be ascii conform for registry purposes)
* @return the document metadata (which have to be completed)</div>
*/
public DocumentMetadata addDocument(DocumentDescriptor desc, InputStream inputStream,
InputStream inputStream4Metadata) {
lastError = "";
DocumentMetadata retVal = null;
XDSDocument doc;
try {
XDSDocument doc4Metadata = null;
if (inputStream4Metadata != null) {
doc4Metadata = new XDSDocumentFromStream(desc,
Util.convertNonAsciiText2Unicode(inputStream4Metadata));
}
doc = new XDSDocumentFromStream(desc, inputStream);
retVal = addXdsDocument(doc, desc);
retVal = addXdsDocument(doc, desc, doc4Metadata);
} catch (final IOException e) {
log.error("Error adding document from inputstream.", e);
String message = e.getMessage();
......@@ -235,6 +258,25 @@ public class ConvenienceCommunication {
*/
public DocumentMetadata addDocument(DocumentDescriptor desc, String filePath)
throws FileNotFoundException {
return addDocument(desc, filePath, null);
}
/**
* <div class="en"> Adds a document to the XDS Submission set.
*
* @param desc
* the document descriptor (which kind of document do you want to
* transfer? e.g. PDF, CDA,...)
* @param filePath
* the file path
* @param filePathMetadata
* the file path metadata
* @return the document metadata (which have to be completed) </div>
* @throws FileNotFoundException
* exception
*/
public DocumentMetadata addDocument(DocumentDescriptor desc, String filePath,
String filePathMetadata) throws FileNotFoundException {
return addDocument(desc, new FileInputStream(new File(filePath)));
}
......@@ -288,6 +330,22 @@ public class ConvenienceCommunication {
* @return the DocumentMetadata
*/
protected DocumentMetadata addXdsDocument(XDSDocument doc, DocumentDescriptor desc) {
return addXdsDocument(doc, desc, null);
}
/**
* <div class="en">Adds an XDSDocument to the Transaction data</div>.
*
* @param doc
* the document
* @param desc
* the Document descriptor
* @param metadataDoc
* the metadata doc
* @return the doc to get the metadata from
*/
protected DocumentMetadata addXdsDocument(XDSDocument doc, DocumentDescriptor desc,
XDSDocument metadataDoc) {