Commit cfc11646 authored by Luc Maisonobe's avatar Luc Maisonobe
Browse files

WIP on Navigation Data Message writing.

parent 3c74bfb8
......@@ -19,6 +19,7 @@ package org.orekit.files.ccsds.ndm;
import java.io.IOException;
import org.orekit.errors.OrekitException;
import org.orekit.errors.OrekitInternalError;
import org.orekit.errors.OrekitMessages;
import org.orekit.files.ccsds.ndm.adm.aem.AemFile;
import org.orekit.files.ccsds.ndm.adm.apm.ApmFile;
......@@ -27,7 +28,10 @@ import org.orekit.files.ccsds.ndm.odm.oem.OemFile;
import org.orekit.files.ccsds.ndm.odm.omm.OmmFile;
import org.orekit.files.ccsds.ndm.odm.opm.OpmFile;
import org.orekit.files.ccsds.ndm.tdm.TdmFile;
import org.orekit.files.ccsds.section.Header;
import org.orekit.files.ccsds.section.Segment;
import org.orekit.files.ccsds.utils.generation.Generator;
import org.orekit.files.ccsds.utils.generation.MessageWriter;
/**
* Writer for CCSDS Navigation Data Message.
......@@ -40,6 +44,9 @@ public class NdmWriter {
/** Builder for the constituents writers. */
private final WriterBuilder builder;
/** Indicator for started message. */
private boolean started;
/** Number of constituents written. */
private int count;
......@@ -53,9 +60,58 @@ public class NdmWriter {
*/
public NdmWriter(final WriterBuilder builder) {
this.builder = builder;
this.started = false;
this.count = 0;
}
/** Write one complete message.
* @param generator generator to use for producing output
* @param message message to write
* @throws IOException if the stream cannot write to stream
*/
public void writeMessage(final Generator generator, final NdmFile message)
throws IOException {
// write the global comments
for (final String comment : message.getComments()) {
writeComment(generator, comment);
}
// write the constituents
for (final NdmConstituent<?, ?> constituent : message.getConstituents()) {
if (constituent instanceof TdmFile) {
writeTdmConstituent(generator, (TdmFile) constituent);
} else if (constituent instanceof OpmFile) {
writeOpmConstituent(generator, (OpmFile) constituent);
} else if (constituent instanceof OmmFile) {
writeOmmConstituent(generator, (OmmFile) constituent);
} else if (constituent instanceof OemFile) {
writeOemConstituent(generator, (OemFile) constituent);
} else if (constituent instanceof OcmFile) {
writeOcmConstituent(generator, (OcmFile) constituent);
} else if (constituent instanceof ApmFile) {
writeApmConstituent(generator, (ApmFile) constituent);
} else if (constituent instanceof AemFile) {
writeAemConstituent(generator, (AemFile) constituent);
} else {
// this should never happen
throw new OrekitInternalError(null);
}
}
}
/** Start the composite message if needed.
* @param generator generator to use for producing output
* @throws IOException if the stream cannot write to stream
*/
private void startMessageIfNeeded(final Generator generator) throws IOException {
if (!started) {
generator.enterSection(NdmStructureKey.tdm.name());
started = true;
}
}
/** Write a comment line.
* <p>
* Comments allows comments only before constituents, so attempting to
......@@ -68,6 +124,8 @@ public class NdmWriter {
*/
public void writeComment(final Generator generator, final String comment) throws IOException {
startMessageIfNeeded(generator);
// check we can still write comments
if (count > 0) {
throw new OrekitException(OrekitMessages.ATTEMPT_TO_GENERATE_MALFORMED_FILE, generator.getOutputName());
......@@ -82,7 +140,7 @@ public class NdmWriter {
* @param tdmConstituent TDM constituent
*/
public void writeTdmConstituent(final Generator generator, final TdmFile tdmConstituent) throws IOException {
builder.buildTdmWriter().writeMessage(generator, tdmConstituent);
writeConstituent(generator, builder.buildTdmWriter(), tdmConstituent);
}
/** Write an OPM constituent.
......@@ -90,7 +148,7 @@ public class NdmWriter {
* @param opmConstituent OPM constituent
*/
public void writeOpmConstituent(final Generator generator, final OpmFile opmConstituent) throws IOException {
builder.buildOpmWriter().writeMessage(generator, opmConstituent);
writeConstituent(generator, builder.buildOpmWriter(), opmConstituent);
}
/** Write an OMM constituent.
......@@ -98,7 +156,7 @@ public class NdmWriter {
* @param ommConstituent OMM constituent
*/
public void writeOmmConstituent(final Generator generator, final OmmFile ommConstituent) throws IOException {
builder.buildOmmWriter().writeMessage(generator, ommConstituent);
writeConstituent(generator, builder.buildOmmWriter(), ommConstituent);
}
/** Write an OEM constituent.
......@@ -106,7 +164,7 @@ public class NdmWriter {
* @param oemConstituent TDM constituent
*/
public void writeOemConstituent(final Generator generator, final OemFile oemConstituent) throws IOException {
builder.buildOemWriter().writeMessage(generator, oemConstituent);
writeConstituent(generator, builder.buildOemWriter(), oemConstituent);
}
/** Write an OCM constituent.
......@@ -114,7 +172,7 @@ public class NdmWriter {
* @param ocmConstituent OCM constituent
*/
public void writeOcmConstituent(final Generator generator, final OcmFile ocmConstituent) throws IOException {
builder.buildOcmWriter().writeMessage(generator, ocmConstituent);
writeConstituent(generator, builder.buildOcmWriter(), ocmConstituent);
}
/** Write an APM constituent.
......@@ -122,7 +180,7 @@ public class NdmWriter {
* @param apmConstituent APM constituent
*/
public void writeApmConstituent(final Generator generator, final ApmFile apmConstituent) throws IOException {
builder.buildApmWriter().writeMessage(generator, apmConstituent);
writeConstituent(generator, builder.buildApmWriter(), apmConstituent);
}
/** Write an AEM constituent.
......@@ -130,7 +188,22 @@ public class NdmWriter {
* @param aemConstituent AEM constituent
*/
public void writeAemConstituent(final Generator generator, final AemFile aemConstituent) throws IOException {
builder.buildAemWriter().writeMessage(generator, aemConstituent);
writeConstituent(generator, builder.buildAemWriter(), aemConstituent);
}
/** Write a constituent.
* @param generator generator to use for producing output
* @param writer writer for the constituent
* @param constituent constituent
* @param <H> type of the header
* @param <S> type of the segments
* @param <F> type of the file
*/
private <H extends Header, S extends Segment<?, ?>, F extends NdmConstituent<H, S>>
void writeConstituent(final Generator generator, final MessageWriter<H, S, F> writer,
final F constituent) throws IOException {
startMessageIfNeeded(generator);
writer.writeMessage(generator, constituent);
}
}
......@@ -26,6 +26,7 @@ import org.orekit.files.ccsds.section.Segment;
* Interface for writing Navigation Data Message (NDM) files.
* @param <H> type of the header
* @param <S> type of the segments
* @param <F> type of the file
* @author Luc Maisonobe
* @since 11.0
*/
......
......@@ -67,11 +67,12 @@ public class XmlLexicalAnalyzer implements LexicalAnalyzer {
// Read the xml file
messageParser.reset(FileFormat.XML);
final InputStream is = source.getStreamOpener().openOnce();
if (is == null) {
throw new OrekitException(OrekitMessages.UNABLE_TO_FIND_FILE, source.getName());
try (InputStream is = source.getStreamOpener().openOnce()) {
if (is == null) {
throw new OrekitException(OrekitMessages.UNABLE_TO_FIND_FILE, source.getName());
}
saxParser.parse(is, handler);
}
saxParser.parse(is, handler);
// Get the content of the file
return messageParser.build();
......
/* Copyright 2002-2021 CS GROUP
* Licensed to CS Systèmes d'Information (CS) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* CS licenses this file to You 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 org.orekit.files.ccsds.ndm;
import java.io.ByteArrayInputStream;
import java.io.CharArrayWriter;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import org.junit.Assert;
import org.junit.Before;
import org.orekit.Utils;
import org.orekit.data.DataSource;
import org.orekit.files.ccsds.section.Header;
import org.orekit.files.ccsds.section.Segment;
import org.orekit.files.ccsds.utils.FileFormat;
import org.orekit.files.ccsds.utils.generation.Generator;
import org.orekit.files.ccsds.utils.generation.KvnGenerator;
import org.orekit.files.ccsds.utils.generation.MessageWriter;
import org.orekit.files.ccsds.utils.generation.XmlGenerator;
import org.orekit.files.ccsds.utils.lexical.MessageParser;
public abstract class AbstractWriterTest<H extends Header, S extends Segment<?, ?>, F extends NdmConstituent<H, S>> {
@Before
public void setUp() {
Utils.setDataRoot("regular-data");
}
protected abstract MessageParser<F> getParser();
protected abstract MessageWriter<H, S, F> getWriter();
protected void doTest(final String name) {
doTest(name, FileFormat.KVN, 60);
doTest(name, FileFormat.KVN, 0);
doTest(name, FileFormat.XML, 60);
doTest(name, FileFormat.XML, 0);
}
protected void doTest(final String name, final FileFormat format, final int unitsColumn) {
try {
final DataSource source1 = new DataSource(name, () -> getClass().getResourceAsStream(name));
final F original = getParser().parseMessage(source1);
// write the parsed file back to a characters array
final CharArrayWriter caw = new CharArrayWriter();
final Generator generator = format == FileFormat.KVN ?
new KvnGenerator(caw, 25, "dummy.kvn", unitsColumn) :
new XmlGenerator(caw, XmlGenerator.DEFAULT_INDENT, "dummy.xml", unitsColumn > 0);
getWriter().writeMessage(generator, original);
// reparse the written file
final byte[] bytes = caw.toString().getBytes(StandardCharsets.UTF_8);
final DataSource source2 = new DataSource(name, () -> new ByteArrayInputStream(bytes));
final F rebuilt = getParser().parseMessage(source2);
NdmTestUtils.checkEquals(original, rebuilt);
} catch (IOException ioe) {
Assert.fail(ioe.getLocalizedMessage());
}
}
}
......@@ -16,11 +16,7 @@
*/
package org.orekit.files.ccsds.ndm;
import java.io.ByteArrayInputStream;
import java.io.CharArrayWriter;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Locale;
import java.util.Map;
......@@ -33,9 +29,6 @@ import org.hipparchus.linear.RealMatrix;
import org.hipparchus.util.FastMath;
import org.hipparchus.util.Precision;
import org.junit.Assert;
import org.junit.Before;
import org.orekit.Utils;
import org.orekit.data.DataSource;
import org.orekit.errors.OrekitException;
import org.orekit.errors.OrekitMessages;
import org.orekit.files.ccsds.definitions.BodyFacade;
......@@ -52,64 +45,17 @@ import org.orekit.files.ccsds.ndm.odm.ocm.OrbitState;
import org.orekit.files.ccsds.ndm.odm.ocm.OrbitStateHistory;
import org.orekit.files.ccsds.ndm.tdm.Observation;
import org.orekit.files.ccsds.section.CommentsContainer;
import org.orekit.files.ccsds.section.Header;
import org.orekit.files.ccsds.section.Segment;
import org.orekit.files.ccsds.utils.FileFormat;
import org.orekit.files.ccsds.utils.generation.Generator;
import org.orekit.files.ccsds.utils.generation.KvnGenerator;
import org.orekit.files.ccsds.utils.generation.MessageWriter;
import org.orekit.files.ccsds.utils.generation.XmlGenerator;
import org.orekit.files.ccsds.utils.lexical.MessageParser;
import org.orekit.frames.Frame;
import org.orekit.time.AbsoluteDate;
import org.orekit.utils.AngularCoordinates;
import org.orekit.utils.PVCoordinates;
import org.orekit.utils.units.Unit;
public abstract class AbstractNdmWriterTest<H extends Header, S extends Segment<?, ?>, F extends NdmConstituent<H, S>> {
public class NdmTestUtils {
private static final int ULPS = 3;
@Before
public void setUp() {
Utils.setDataRoot("regular-data");
}
protected abstract MessageParser<F> getParser();
protected abstract MessageWriter<H, S, F> getWriter();
protected void doTest(final String name) {
doTest(name, FileFormat.KVN, 60);
doTest(name, FileFormat.KVN, 0);
doTest(name, FileFormat.XML, 60);
doTest(name, FileFormat.XML, 0);
}
protected void doTest(final String name, final FileFormat format, final int unitsColumn) {
try {
final DataSource source1 = new DataSource(name, () -> getClass().getResourceAsStream(name));
final F original = getParser().parseMessage(source1);
// write the parsed file back to a characters array
final CharArrayWriter caw = new CharArrayWriter();
final Generator generator = format == FileFormat.KVN ?
new KvnGenerator(caw, 25, "dummy.kvn", unitsColumn) :
new XmlGenerator(caw, XmlGenerator.DEFAULT_INDENT, "dummy.xml", unitsColumn > 0);
getWriter().writeMessage(generator, original);
// reparse the written file
final byte[] bytes = caw.toString().getBytes(StandardCharsets.UTF_8);
final DataSource source2 = new DataSource(name, () -> new ByteArrayInputStream(bytes));
final F rebuilt = getParser().parseMessage(source2);
checkEquals(original, rebuilt);
} catch (IOException ioe) {
Assert.fail(ioe.getLocalizedMessage());
}
}
private void checkEquals(final F original, final F rebuilt) {
public static void checkEquals(final NdmConstituent<?, ?> original, final NdmConstituent<?, ?> rebuilt) {
checkContainer(original.getHeader(), rebuilt.getHeader());
Assert.assertEquals(original.getSegments().size(), rebuilt.getSegments().size());
for (int i = 0; i < original.getSegments().size(); ++i) {
......@@ -118,7 +64,7 @@ public abstract class AbstractNdmWriterTest<H extends Header, S extends Segment<
}
}
private boolean recurseCheck(final Object original, final Object rebuilt) {
public static boolean recurseCheck(final Object original, final Object rebuilt) {
if (original == null) {
return rebuilt == null;
......@@ -196,7 +142,7 @@ public abstract class AbstractNdmWriterTest<H extends Header, S extends Segment<
}
private void checkContainer(final Object original, final Object rebuilt) {
public static void checkContainer(final Object original, final Object rebuilt) {
Assert.assertEquals(original.getClass(), rebuilt.getClass());
final Class<?> cls = original.getClass();
Stream.of(cls.getMethods()).
......@@ -223,28 +169,28 @@ public abstract class AbstractNdmWriterTest<H extends Header, S extends Segment<
});
}
private void checkIntArray(final int[] original, final int[] rebuilt) {
public static void checkIntArray(final int[] original, final int[] rebuilt) {
Assert.assertEquals(original.length, rebuilt.length);
for (int i = 0; i < original.length; ++i) {
Assert.assertEquals(original[i], rebuilt[i]);
}
}
private void checkDoubleArray(final double[] original, final double[] rebuilt) {
public static void checkDoubleArray(final double[] original, final double[] rebuilt) {
Assert.assertEquals(original.length, rebuilt.length);
for (int i = 0; i < original.length; ++i) {
Assert.assertTrue(Precision.equalsIncludingNaN(original[i], rebuilt[i], 1));
}
}
private void checkList(final List<?> original, final List<?> rebuilt) {
public static void checkList(final List<?> original, final List<?> rebuilt) {
Assert.assertEquals(original.size(), rebuilt.size());
for (int i = 0; i < original.size(); ++i) {
Assert.assertTrue(recurseCheck(original.get(i), rebuilt.get(i)));
}
}
private void checkMap(final Map<?, ?> original, final Map<?, ?> rebuilt) {
public static void checkMap(final Map<?, ?> original, final Map<?, ?> rebuilt) {
Assert.assertEquals(original.size(), rebuilt.size());
for (final Map.Entry<?, ?> entry : original.entrySet()) {
Assert.assertTrue(rebuilt.containsKey(entry.getKey()));
......@@ -252,7 +198,7 @@ public abstract class AbstractNdmWriterTest<H extends Header, S extends Segment<
}
}
private void checkFrameFacade(final FrameFacade original, final FrameFacade rebuilt) {
public static void checkFrameFacade(final FrameFacade original, final FrameFacade rebuilt) {
if (original.asFrame() == null) {
Assert.assertNull(rebuilt.asFrame());
} else {
......@@ -278,7 +224,7 @@ public abstract class AbstractNdmWriterTest<H extends Header, S extends Segment<
Assert.assertEquals(original.getName(), rebuilt.getName());
}
private void checkBodyFacade(final BodyFacade original, final BodyFacade rebuilt) {
public static void checkBodyFacade(final BodyFacade original, final BodyFacade rebuilt) {
if (original.getBody() == null) {
Assert.assertNull(rebuilt.getBody());
} else {
......@@ -288,13 +234,13 @@ public abstract class AbstractNdmWriterTest<H extends Header, S extends Segment<
Assert.assertEquals(original.getName().toUpperCase(Locale.US), rebuilt.getName().toUpperCase(Locale.US));
}
private void checkOdMethodFacade(final OdMethodFacade original, final OdMethodFacade rebuilt) {
public static void checkOdMethodFacade(final OdMethodFacade original, final OdMethodFacade rebuilt) {
Assert.assertEquals(original.getName(), rebuilt.getName());
Assert.assertEquals(original.getType(), rebuilt.getType());
Assert.assertEquals(original.getTool(), rebuilt.getTool());
}
private void checkOrbitStateHistory(final OrbitStateHistory original, final OrbitStateHistory rebuilt) {
public static void checkOrbitStateHistory(final OrbitStateHistory original, final OrbitStateHistory rebuilt) {
// we don't use checkContainer here because the history getters are redundant
// with embedded metadata and states, and because the getFrame() method
// that would be called automatically may trhow an exception
......@@ -303,34 +249,34 @@ public abstract class AbstractNdmWriterTest<H extends Header, S extends Segment<
checkList(original.getOrbitalStates(), rebuilt.getOrbitalStates());
}
private void checkDate(final AbsoluteDate original, final AbsoluteDate rebuilt) {
public static void checkDate(final AbsoluteDate original, final AbsoluteDate rebuilt) {
Assert.assertEquals(0.0, rebuilt.durationFrom(original), 1.0e-14);
}
private void checkUnit(final Unit original, final Unit rebuilt) {
public static void checkUnit(final Unit original, final Unit rebuilt) {
Assert.assertTrue(Precision.equals(original.getScale(), rebuilt.getScale(), 1));
Assert.assertTrue(rebuilt.sameDimension(original));
}
private void checkFrame(final Frame original, final Frame rebuilt) {
public static void checkFrame(final Frame original, final Frame rebuilt) {
Assert.assertEquals(original.getName(), rebuilt.getName());
}
private void checkVector3D(final Vector3D original, final Vector3D rebuilt) {
public static void checkVector3D(final Vector3D original, final Vector3D rebuilt) {
double eps = ULPS * FastMath.ulp(original.getNorm());
Assert.assertTrue(Precision.equalsIncludingNaN(original.getX(), rebuilt.getX(), eps));
Assert.assertTrue(Precision.equalsIncludingNaN(original.getY(), rebuilt.getY(), eps));
Assert.assertTrue(Precision.equalsIncludingNaN(original.getZ(), rebuilt.getZ(), eps));
}
private void checkQuaternion(final Quaternion original, final Quaternion rebuilt) {
public static void checkQuaternion(final Quaternion original, final Quaternion rebuilt) {
Assert.assertTrue(Precision.equalsIncludingNaN(original.getQ0(), rebuilt.getQ0(), ULPS));
Assert.assertTrue(Precision.equalsIncludingNaN(original.getQ1(), rebuilt.getQ1(), ULPS));
Assert.assertTrue(Precision.equalsIncludingNaN(original.getQ2(), rebuilt.getQ2(), ULPS));
Assert.assertTrue(Precision.equalsIncludingNaN(original.getQ3(), rebuilt.getQ3(), ULPS));
}
private void checkRealMatrix(final RealMatrix original, final RealMatrix rebuilt) {
public static void checkRealMatrix(final RealMatrix original, final RealMatrix rebuilt) {
Assert.assertEquals(original.getRowDimension(), rebuilt.getRowDimension());
Assert.assertEquals(original.getColumnDimension(), rebuilt.getColumnDimension());
for (int i = 0; i < original.getRowDimension(); ++i) {
......@@ -340,11 +286,11 @@ public abstract class AbstractNdmWriterTest<H extends Header, S extends Segment<
}
}
private void checkRotation(final Rotation original, final Rotation rebuilt) {
public static void checkRotation(final Rotation original, final Rotation rebuilt) {
Assert.assertEquals(0.0, Rotation.distance(original, rebuilt), 1.0e-12);
}
private void checkDouble(final Double original, final Double rebuilt) {
public static void checkDouble(final Double original, final Double rebuilt) {
Assert.assertTrue(Precision.equalsIncludingNaN(original.doubleValue(), rebuilt.doubleValue(), ULPS));
}
......
/* Copyright 2002-2021 CS GROUP
* Licensed to CS GROUP (CS) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* CS licenses this file to You 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 org.orekit.files.ccsds.ndm;
import java.io.ByteArrayInputStream;
import java.io.CharArrayWriter;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.orekit.Utils;
import org.orekit.data.DataSource;
import org.orekit.errors.OrekitException;
import org.orekit.errors.OrekitMessages;
import org.orekit.files.ccsds.ndm.adm.apm.ApmFile;
import org.orekit.files.ccsds.ndm.odm.ocm.OcmFile;
import org.orekit.files.ccsds.ndm.odm.opm.OpmFile;
import org.orekit.files.ccsds.utils.FileFormat;
import org.orekit.files.ccsds.utils.generation.Generator;
import org.orekit.files.ccsds.utils.generation.KvnGenerator;
import org.orekit.files.ccsds.utils.generation.XmlGenerator;
/**
* Test class for CCSDS Navigation Data Message writing.<p>
* @author Luc Maisonobe
*/
public class NdmWriterTest {
@Before
public void setUp() {
Utils.setDataRoot("regular-data");
}
@Test
public void testOpm() throws IOException {
final String name = "/ccsds/ndm/NDM-opm.xml";
final DataSource source = new DataSource(name, () -> NdmWriterTest.class.getResourceAsStream(name));
final NdmFile ndm = new ParserBuilder().buildNdmParser().parseMessage(source);
final CharArrayWriter caw = new CharArrayWriter();
try (Generator generator = new XmlGenerator(caw, XmlGenerator.DEFAULT_INDENT, "dummy.xml", true)) {
new WriterBuilder().buildNdmWriter().writeMessage(generator, ndm);
}
System.out.println(caw.toString());
final byte[] bytes = caw.toString().getBytes(StandardCharsets.UTF_8);
final DataSource source2 = new DataSource(name, () -> new ByteArrayInputStream(bytes));
NdmTestUtils.checkContainer(ndm, new ParserBuilder().buildNdmParser().parseMessage(source2));
}
@Test
public void testOpmApm() throws IOException {
final String name = "/ccsds/ndm/NDM-ocm-apm.xml";
final DataSource source = new DataSource(name, () -> NdmWriterTest.class.getResourceAsStream(name));
final NdmFile ndm = new ParserBuilder().buildNdmParser().parseMessage(source);
final CharArrayWriter caw = new CharArrayWriter();
try (final Generator generator = new XmlGenerator(caw, XmlGenerator.DEFAULT_INDENT, "dummy.xml", true)) {
new WriterBuilder().buildNdmWriter().writeMessage(generator, ndm);
}
final byte[] bytes = caw.toString().getBytes(StandardCharsets.UTF_8);
final DataSource source2 = new DataSource(name, () -> new ByteArrayInputStream(bytes));